Elde.RegulValveMilwaukee, Modbus.Novus added, Elde component updated (18.12.2020), ver. 2.26.1571

This commit is contained in:
Milan Hanajik 2021-01-08 10:02:39 +01:00
parent 3399b07fc0
commit 66852682bf
31 changed files with 3125 additions and 14 deletions

View File

@ -561,9 +561,9 @@ namespace TBF.BenchControl.Elde
/// <param name="valveMode">Valve regulation mode, see the enum</param>
/// <param name="valveValue">Target position or target frequency or pulse duration</param>
/// <param name="stableTime">Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec.</param>
public void ValveMove(int valveNo, RegulValveMode valveMode, float[] valveValue, int stableTime)
public void ValveMove(int valveNo, RegulValveMode valveMode, float[] valveValue, int stableTime, bool mailwaukeeRV = false)
{
controlCom.ValveMove(valveNo, valveMode, valveValue, stableTime);
controlCom.ValveMove(valveNo, valveMode, valveValue, (stableTime & 0x0000001F) + (mailwaukeeRV ? 0x000000C0 : 0));
}

View File

@ -163,6 +163,27 @@ namespace TBF.BenchControl.Elde
{
#if GENESIS
if (nr > 0 && nr <= 3) ctrlBrdComponent.TankTemp[nr - 1] = temp;
#elif MILWAUKEE
if (nr >= 0 && nr < ctrlBrdComponent.ThermostatState.Length)
{
string text;
if (nr % 2 == 1)
{
text = string.Format("T = {0:F1} °F", Config.Units.ConvertTo(Config.Unit.F, temp));
}
else if (temp != 0)
{
text = string.Format("SP = {0:F1} °F", Config.Units.ConvertTo(Config.Unit.F, temp));
}
else
{
text = string.Empty;
}
ctrlBrdComponent.ThermostatState[nr] = text;
log.DebugFormat("SetReservoirTemp({0}, {1}) ... cbrd.ThermostatState[{0}] = {2}", nr, temp, text);
}
#endif
}

View File

@ -141,7 +141,7 @@ namespace TBF.BenchControl.Elde.Diverter
#elif TURA_IPERL || TURA_IPERL_NEW
flowMtrNr4Cmd = divNrFromName + 16 * divNrFromName;
#elif MILWAUKEE
flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : 4;
flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : 68;
#else /// all other benches
flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : 3;
#endif

View File

@ -19,7 +19,7 @@ namespace TBF.BenchControl.Elde.RegulValve
/// Set by the constructor
readonly ControlBoardDev controlBoard;
readonly Elde.RegulValve.RegulValve regulValve;
readonly RegulValve regulValve;
readonly int regulValveNr;
readonly IFlowMeter flowMeter;
readonly double requiredFlowLo;
@ -83,7 +83,7 @@ namespace TBF.BenchControl.Elde.RegulValve
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.controlBoard = controlBoard;
this.regulValve = regulValve as Elde.RegulValve.RegulValve;
this.regulValve = regulValve as RegulValve;
if (this.regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
regulValveNr = this.regulValve.Idx1;

View File

@ -0,0 +1,79 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class ChangeRegulValvePositionOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ChangeRegulValvePositionOp));
public override string ToString()
{
return string.Format("ChangeRegulValvePositionOp({0},{1}s)", regulValve.Name, timePulseSec.ToString("F2"));
}
/// Set by the constructor
readonly ControlBoardDev controlBoard;
readonly RegulValve regulValve;
readonly int regulValveNr;
readonly float timePulseSec;
/// <summary>
/// Set required water flow.
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="_regulValve">Regulation valve component</param>
/// <param name="posLoPct">Lower limit of the position to be achieved</param>
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
/// <param name="timeout">Timeout in sec. for setting the flow</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public ChangeRegulValvePositionOp(ControlBoardDev controlBoard, RegulValve _regulValve, float timePulseSec)
{
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.controlBoard = controlBoard;
regulValve = _regulValve as RegulValve;
if (regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
regulValveNr = this.regulValve.Idx1;
this.timePulseSec = timePulseSec;
log.Debug(this.ToString());
}
/// <summary>Start this operation</summary>
public void Start()
{
float positionPct = controlBoard.RValvePosition(regulValveNr);
log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
controlBoard.ValveMove(regulValveNr,
RegulValveMode.PulseWidth,
new float[2] { timePulseSec, timePulseSec },
regulValve.StableTime,
true);
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.SetFlowDone
/// </returns>
public Event Run()
{
float positionPct = controlBoard.RValvePosition(regulValveNr);
log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
return Event.PositionReached;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -0,0 +1,26 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class Factory : IComponentFactory
{
public string ClassName { get { return "RegulationValveMilwaukee"; } }
public void ResetStaticProperties() { RegulValve.ResetStaticProperties(); }
public IComponent DummyComponent() { return new RegulValve(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new RegulValve(cfg, components); }
public IComponentCfg DefaultConfig() { return new RegulValveCfg("RV", this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(RegulValveCfg.Serializer, component, this);
}
}
}

View File

@ -0,0 +1,36 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using log4net;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
static class Handlers
{
static readonly ILog log = LogManager.GetLogger(typeof(Handlers));
static Handlers()
{
}
/// <summary>
/// Called from the state machine when a procedure is selected and UI needs to be updated.
/// </summary>
public static void OnAdcChanged(object sender, CmdResponseArgs data)
{
if (AdcChangedHandler == null)
return;
try
{
AdcChangedHandler(sender, data);
}
catch (Exception e)
{
log.Error("AdcChangedHandler(...) failed", e);
}
}
public static event EventHandler<CmdResponseArgs> AdcChangedHandler;
}
}

View File

@ -0,0 +1,182 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.Generic;
using TBF.Boxes;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class RegulValve : ComponentBase, IDevice, GenericDevices.IRegulValve
{
private static readonly ILog log = LogManager.GetLogger(typeof(RegulValve));
public override string ToString() { return string.Format("RegulValve({0})", Cfg.ToString(1)); }
public readonly RegulValveCfg RegulValveCfg;
IDictionary<double, float> dict;
public IDictionary<double, float> Dict { get { return dict; } }
public readonly ControlBoardDev ControlBoard;
public ValveCategory Category { get { return RegulValveCfg.Category; } }
public int Idx1 { get { return RegulValveCfg.Idx1; } } /// 1..7
public int DacValueClosed { get { return RegulValveCfg.AdcValueClosed; } } /// 0..1023
public int DacValueOpen { get { return RegulValveCfg.AdcValueOpen; } } /// 0..1023
public int StableTime { get { return RegulValveCfg.StableTime; } } /// 0=200ms, step=50ms, max. 1500ms (max.26)
public int FlowStableSec { get { return RegulValveCfg.FlowStableSec; } } /// 0..60 sec
///
public bool IsCoax { get { return false; } }
///
public float Position { get { return ControlBoard.RValvePosition(Idx1); } }
///
int adcChannel;
#region Configuration Change Handling
public static void OnCfgChange(object sender, CfgChangeArgs args)
{
if (CfgChangeHandler == null) return;
try { CfgChangeHandler(sender, args); }
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
}
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
public override void StartChangeHandler()
{
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
{
RegulValveCfg tmpcfg = args.Cfg as RegulValveCfg;
if (tmpcfg != null && tmpcfg.Name.Equals(Name))
{
if (args.Command == CfgChangeCmd.CfgChange)
{
RegulValveCfg.StableTimeMs = tmpcfg.StableTimeMs;
RegulValveCfg.FlowStableSec = tmpcfg.FlowStableSec;
}
else if (args.Command == CfgChangeCmd.RVOpenStep)
{
ControlBoard.ValveMove(Idx1, RegulValveMode.PulseWidth, new float[2] { 2.0f, 2.0f }, StableTime, true);
// TODO: avoid conflicts
// TOTEST
}
else if (args.Command == CfgChangeCmd.RVCloseStep)
{
ControlBoard.ValveMove(Idx1, RegulValveMode.PulseWidth, new float[2] { -2.0f, -2.0f }, StableTime, true);
// TODO: avoid conflicts
// TOTEST
}
else if (args.Command == CfgChangeCmd.GetAdc1 || args.Command == CfgChangeCmd.GetAdc2)
{
int adcValue = (int)ControlBoard.AnalogInputRaw(adcChannel, 0);
RegulValveCfgCtrl.OnCmdResponse(this, new CmdResponseArgs(args.Command, Idx1, adcValue));
}
}
};
}
#endregion Configuration Change Handling
public RegulValve()
{
}
public RegulValve(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
RegulValveCfg = cfg as RegulValveCfg;
ControlBoard = (ControlBoardDev)TbfComponents.FindComponent(cfg.ParentName, components);
if (ControlBoard == null) throw new Exception("Cannot find " + Name + " parent");
this.dict = new Dictionary<double, float>();
adcChannel = Idx1 - 1;
if (Idx1 < ControlBoard.RegValveCalib.GetLength(0))
{
this.ControlBoard.RegValveCalib[adcChannel, 0] = (uint)DacValueClosed;
this.ControlBoard.RegValveCalib[adcChannel, 1] = (uint)DacValueOpen;
}
else
{
log.ErrorFormat("Unable to set {0} ADC levels: RegValveCalib array size={1}, RV Idx1={2}, RV AdcNr={3}",
Name, ControlBoard.RegValveCalib.GetLength(0), Idx1, Idx1 - 1);
}
StartChangeHandler();
log.Warn(this.ToString());
}
///
/// IDevice interface implementation
///
public void Initialize() { }
public void RunDeviceBefore()
{
int adcValue = (int)ControlBoard.AnalogInputRaw(adcChannel, 0);
Handlers.OnAdcChanged(this, new CmdResponseArgs(CfgChangeCmd.GetAdc, Idx1, adcValue));
}
public void RunDeviceAfter() { }
public void StopDevice() { }
public void StopDevice2() { }
/// <summary>
/// Operation to set the water flow within tolerances
/// Events: Event.None, Event.FlowReached, Event.FlowTimeOut
/// </summary>
/// <param name="flowMeter">Flowmeter component</param>
/// <param name="requiredFlowLo">Lower limit of the required flow [m3/h]</param>
/// <param name="requiredFlowHi">Higher limit of the required flow [m3/h]</param>
/// <param name="pidCoef">PID coefficient (float)</param>
/// <param name="measuredFlow">Measured flow [m3/h]</param>
/// <param name="timeout">Timeout in [s]</param>
/// <returns>SetFlowOp instance</returns>
public IOperation SetFlowOp(GenericDevices.IFlowMeter flowMeter, double requiredFlowLo, double requiredFlowHi, DoubleBox measuredFlow, int timeout)
{
return new SetFlowOp(ControlBoard, this, flowMeter, requiredFlowLo, requiredFlowHi, measuredFlow, RegulValveCfg.ReTryCommands, timeout);
}
/// <summary>
/// Operation to set the water flow within tolerances. Leave the measurement running.
/// Events: Event.None, Event.FlowReached, Event.FlowTimeOut
/// </summary>
/// <param name="flowMeter">Flowmeter component</param>
/// <param name="requiredFlowLo">Lower limit of the required flow [m3/h]</param>
/// <param name="requiredFlowHi">Higher limit of the required flow [m3/h]</param>
/// <param name="measuredFlow">Measured flow [m3/h]</param>
/// <param name="timeout">Timeout in [s]</param>
/// <returns>SetFlowOp instance</returns>
public IOperation SetFlowAndMeasureOp(GenericDevices.IFlowMeter flowMeter, double requiredFlowLo, double requiredFlowHi,
DoubleBox measuredFlow, int timeout, float filterConstant)
{
return new SetFlowOp(ControlBoard, this, flowMeter, requiredFlowLo, requiredFlowHi, measuredFlow, RegulValveCfg.ReTryCommands, timeout, true);
}
/// <summary>
/// Operation to set the regulation valve to a required position
/// Events: Event.None
/// </summary>
/// <param name="flowLo">Lower limit of the required valve position in [%]</param>
/// <param name="flowLo">Higher limit of the required valve position in [%]</param>
/// <returns>SetPositionOp instance</returns>
public IOperation SetRegulValvePositionOp(float pctLo, float pctHi, int timeoutMs)
{
return new SetRegulValvePositionOp(ControlBoard, this, pctLo, pctHi, timeoutMs);
}
public IOperation ChangeRegulValvePositionOp(float timePulseSec)
{
return new ChangeRegulValvePositionOp(ControlBoard, this, timePulseSec);
}
}
}

View File

@ -0,0 +1,72 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class RegulValveCfg : ComponentCfgBase, IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(RegulValveCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new RegulValveCfgCtrl(); }
///
/// Serialized parameters
///
public int Idx1; /// 1..8
public ValveCategory Category; /// Feeding or Output
public int AdcValueClosed; /// 0..1023
public int AdcValueOpen; /// 0..1023
public int StableTimeMs; /// 200..1500 ms, step is 50 ms
public int FlowStableSec; /// 0..60 sec
public bool StoredPositionReuse; /// true = store and re-use previous regulation valve positions
public bool ReTryCommands;
/// <summary>
/// Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec.
/// </summary>
public int StableTime { get { return (StableTimeMs - 200) / 50; } }
/// Private parameterless constructor invoked by all other (public) constructors
RegulValveCfg()
{
}
public RegulValveCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = "CB";
Category = ValveCategory.Output;
Idx1 = 1;
AdcValueClosed = 100;
AdcValueOpen = 500;
StableTimeMs = 500;
FlowStableSec = 5;
StoredPositionReuse = false;
ReTryCommands = false;
}
public string ToString(int i)
{
return string.Format("Name={0} ({1}), Idx1={2}, Cat.={3}, ADC-Closed={4}, ADC-Open={5}, StabTm={6}ms, FlowStable={7}s, PosReuse={8}, ReTryCmds={9}",
Name,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName),
Idx1,
Category,
AdcValueClosed,
AdcValueOpen,
StableTimeMs,
FlowStableSec,
StoredPositionReuse,
ReTryCommands);
}
}
}

View File

@ -0,0 +1,19 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class RegulValveCfgChangeArgs : EventArgs
{
public CfgChangeCmd Command;
public Generic.IComponentCfg Cfg;
public RegulValveCfgChangeArgs(CfgChangeCmd command, Generic.IComponentCfg cfg)
{
Command = command;
Cfg = cfg;
}
}
}

View File

@ -0,0 +1,523 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
partial class RegulValveCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.positionTextBox = new System.Windows.Forms.TextBox();
this.positionLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.adcClosedLabel = new System.Windows.Forms.Label();
this.adcClosedTextBox = new System.Windows.Forms.TextBox();
this.adcOpenTextBox = new System.Windows.Forms.TextBox();
this.adcOpenLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.storedPosReuseCheckBox = new System.Windows.Forms.CheckBox();
this.stableTimeTextBox = new System.Windows.Forms.TextBox();
this.stableTimeLabel = new System.Windows.Forms.Label();
this.flowStableSecTextBox = new System.Windows.Forms.TextBox();
this.flowStableSecLabel = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.setButton1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.ADC = new System.Windows.Forms.Label();
this.getButton1 = new System.Windows.Forms.Button();
this.pctTextBox1 = new System.Windows.Forms.TextBox();
this.adcTextBox1 = new System.Windows.Forms.TextBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.setButton2 = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.getButton2 = new System.Windows.Forms.Button();
this.pctTextBox2 = new System.Windows.Forms.TextBox();
this.adcTextBox2 = new System.Windows.Forms.TextBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.closeButton = new System.Windows.Forms.Button();
this.openButton = new System.Windows.Forms.Button();
this.adcTextBox = new System.Windows.Forms.TextBox();
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.label4 = new System.Windows.Forms.Label();
this.categoryComboBox = new System.Windows.Forms.ComboBox();
this.categoryLabel = new System.Windows.Forms.Label();
this.reTryCommandsCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.groupBox4.SuspendLayout();
this.SuspendLayout();
//
// positionTextBox
//
this.positionTextBox.Enabled = false;
this.positionTextBox.Location = new System.Drawing.Point(138, 114);
this.positionTextBox.Name = "positionTextBox";
this.positionTextBox.Size = new System.Drawing.Size(46, 20);
this.positionTextBox.TabIndex = 8;
//
// positionLabel
//
this.positionLabel.AutoSize = true;
this.positionLabel.Location = new System.Drawing.Point(28, 117);
this.positionLabel.Name = "positionLabel";
this.positionLabel.Size = new System.Drawing.Size(18, 13);
this.positionLabel.TabIndex = 7;
this.positionLabel.Text = "ID";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(28, 68);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
this.parentNameLabel.TabIndex = 3;
this.parentNameLabel.Text = "Parent Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(138, 41);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(28, 44);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(135, 14);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(89, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComponentName";
//
// adcClosedLabel
//
this.adcClosedLabel.AutoSize = true;
this.adcClosedLabel.Location = new System.Drawing.Point(28, 141);
this.adcClosedLabel.Name = "adcClosedLabel";
this.adcClosedLabel.Size = new System.Drawing.Size(93, 13);
this.adcClosedLabel.TabIndex = 9;
this.adcClosedLabel.Text = "ADC when Closed";
//
// adcClosedTextBox
//
this.adcClosedTextBox.Enabled = false;
this.adcClosedTextBox.Location = new System.Drawing.Point(138, 138);
this.adcClosedTextBox.Name = "adcClosedTextBox";
this.adcClosedTextBox.Size = new System.Drawing.Size(46, 20);
this.adcClosedTextBox.TabIndex = 10;
//
// adcOpenTextBox
//
this.adcOpenTextBox.Enabled = false;
this.adcOpenTextBox.Location = new System.Drawing.Point(138, 162);
this.adcOpenTextBox.Name = "adcOpenTextBox";
this.adcOpenTextBox.Size = new System.Drawing.Size(46, 20);
this.adcOpenTextBox.TabIndex = 12;
//
// adcOpenLabel
//
this.adcOpenLabel.AutoSize = true;
this.adcOpenLabel.Location = new System.Drawing.Point(28, 165);
this.adcOpenLabel.Name = "adcOpenLabel";
this.adcOpenLabel.Size = new System.Drawing.Size(87, 13);
this.adcOpenLabel.TabIndex = 11;
this.adcOpenLabel.Text = "ADC when Open";
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(138, 65);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 4;
//
// storedPosReuseCheckBox
//
this.storedPosReuseCheckBox.AutoSize = true;
this.storedPosReuseCheckBox.Enabled = false;
this.storedPosReuseCheckBox.Location = new System.Drawing.Point(31, 239);
this.storedPosReuseCheckBox.Name = "storedPosReuseCheckBox";
this.storedPosReuseCheckBox.Size = new System.Drawing.Size(162, 17);
this.storedPosReuseCheckBox.TabIndex = 17;
this.storedPosReuseCheckBox.Text = "Enable stored position re-use";
this.storedPosReuseCheckBox.UseVisualStyleBackColor = true;
//
// stableTimeTextBox
//
this.stableTimeTextBox.Enabled = false;
this.stableTimeTextBox.Location = new System.Drawing.Point(138, 186);
this.stableTimeTextBox.Name = "stableTimeTextBox";
this.stableTimeTextBox.Size = new System.Drawing.Size(46, 20);
this.stableTimeTextBox.TabIndex = 14;
//
// stableTimeLabel
//
this.stableTimeLabel.AutoSize = true;
this.stableTimeLabel.Location = new System.Drawing.Point(28, 189);
this.stableTimeLabel.Name = "stableTimeLabel";
this.stableTimeLabel.Size = new System.Drawing.Size(81, 13);
this.stableTimeLabel.TabIndex = 13;
this.stableTimeLabel.Text = "Stable time [ms]";
//
// flowStableSecTextBox
//
this.flowStableSecTextBox.Enabled = false;
this.flowStableSecTextBox.Location = new System.Drawing.Point(138, 210);
this.flowStableSecTextBox.Name = "flowStableSecTextBox";
this.flowStableSecTextBox.Size = new System.Drawing.Size(46, 20);
this.flowStableSecTextBox.TabIndex = 16;
//
// flowStableSecLabel
//
this.flowStableSecLabel.AutoSize = true;
this.flowStableSecLabel.Location = new System.Drawing.Point(28, 213);
this.flowStableSecLabel.Name = "flowStableSecLabel";
this.flowStableSecLabel.Size = new System.Drawing.Size(74, 13);
this.flowStableSecLabel.TabIndex = 15;
this.flowStableSecLabel.Text = "Flow stable [s]";
//
// groupBox1
//
this.groupBox1.Controls.Add(this.setButton1);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.ADC);
this.groupBox1.Controls.Add(this.getButton1);
this.groupBox1.Controls.Add(this.pctTextBox1);
this.groupBox1.Controls.Add(this.adcTextBox1);
this.groupBox1.Location = new System.Drawing.Point(10, 398);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(280, 59);
this.groupBox1.TabIndex = 19;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Measured value 1";
//
// setButton1
//
this.setButton1.Location = new System.Drawing.Point(229, 17);
this.setButton1.Name = "setButton1";
this.setButton1.Size = new System.Drawing.Size(38, 33);
this.setButton1.TabIndex = 5;
this.setButton1.Text = "Set";
this.setButton1.UseVisualStyleBackColor = true;
this.setButton1.Click += new System.EventHandler(this.setButton_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(209, 28);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(15, 13);
this.label1.TabIndex = 4;
this.label1.Text = "%";
//
// ADC
//
this.ADC.AutoSize = true;
this.ADC.Location = new System.Drawing.Point(11, 28);
this.ADC.Name = "ADC";
this.ADC.Size = new System.Drawing.Size(32, 13);
this.ADC.TabIndex = 3;
this.ADC.Text = "ADC:";
//
// getButton1
//
this.getButton1.Location = new System.Drawing.Point(101, 18);
this.getButton1.Name = "getButton1";
this.getButton1.Size = new System.Drawing.Size(38, 33);
this.getButton1.TabIndex = 2;
this.getButton1.Text = "Get";
this.getButton1.UseVisualStyleBackColor = true;
this.getButton1.Click += new System.EventHandler(this.getButton1_Click);
//
// pctTextBox1
//
this.pctTextBox1.Location = new System.Drawing.Point(160, 24);
this.pctTextBox1.Name = "pctTextBox1";
this.pctTextBox1.Size = new System.Drawing.Size(46, 20);
this.pctTextBox1.TabIndex = 1;
//
// adcTextBox1
//
this.adcTextBox1.Location = new System.Drawing.Point(47, 24);
this.adcTextBox1.Name = "adcTextBox1";
this.adcTextBox1.Size = new System.Drawing.Size(44, 20);
this.adcTextBox1.TabIndex = 0;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.setButton2);
this.groupBox2.Controls.Add(this.label2);
this.groupBox2.Controls.Add(this.label3);
this.groupBox2.Controls.Add(this.getButton2);
this.groupBox2.Controls.Add(this.pctTextBox2);
this.groupBox2.Controls.Add(this.adcTextBox2);
this.groupBox2.Location = new System.Drawing.Point(10, 462);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(280, 59);
this.groupBox2.TabIndex = 20;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Measured value 2";
//
// setButton2
//
this.setButton2.Location = new System.Drawing.Point(229, 17);
this.setButton2.Name = "setButton2";
this.setButton2.Size = new System.Drawing.Size(38, 33);
this.setButton2.TabIndex = 5;
this.setButton2.Text = "Set";
this.setButton2.UseVisualStyleBackColor = true;
this.setButton2.Click += new System.EventHandler(this.setButton_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(209, 28);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(15, 13);
this.label2.TabIndex = 4;
this.label2.Text = "%";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(11, 27);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(32, 13);
this.label3.TabIndex = 3;
this.label3.Text = "ADC:";
//
// getButton2
//
this.getButton2.Location = new System.Drawing.Point(101, 18);
this.getButton2.Name = "getButton2";
this.getButton2.Size = new System.Drawing.Size(38, 33);
this.getButton2.TabIndex = 2;
this.getButton2.Text = "Get";
this.getButton2.UseVisualStyleBackColor = true;
this.getButton2.Click += new System.EventHandler(this.getButton2_Click);
//
// pctTextBox2
//
this.pctTextBox2.Location = new System.Drawing.Point(160, 24);
this.pctTextBox2.Name = "pctTextBox2";
this.pctTextBox2.Size = new System.Drawing.Size(46, 20);
this.pctTextBox2.TabIndex = 1;
//
// adcTextBox2
//
this.adcTextBox2.Location = new System.Drawing.Point(47, 24);
this.adcTextBox2.Name = "adcTextBox2";
this.adcTextBox2.Size = new System.Drawing.Size(44, 20);
this.adcTextBox2.TabIndex = 0;
//
// groupBox3
//
this.groupBox3.Controls.Add(this.closeButton);
this.groupBox3.Controls.Add(this.openButton);
this.groupBox3.Location = new System.Drawing.Point(10, 527);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(280, 60);
this.groupBox3.TabIndex = 21;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Regulation valve";
//
// closeButton
//
this.closeButton.Location = new System.Drawing.Point(14, 19);
this.closeButton.Name = "closeButton";
this.closeButton.Size = new System.Drawing.Size(107, 28);
this.closeButton.TabIndex = 1;
this.closeButton.Text = "Close";
this.closeButton.UseVisualStyleBackColor = true;
this.closeButton.Click += new System.EventHandler(this.closeButton_Click);
//
// openButton
//
this.openButton.Location = new System.Drawing.Point(160, 19);
this.openButton.Name = "openButton";
this.openButton.Size = new System.Drawing.Size(107, 28);
this.openButton.TabIndex = 0;
this.openButton.Text = "Open";
this.openButton.UseVisualStyleBackColor = true;
this.openButton.Click += new System.EventHandler(this.openButton_Click);
//
// adcTextBox
//
this.adcTextBox.Location = new System.Drawing.Point(47, 14);
this.adcTextBox.Name = "adcTextBox";
this.adcTextBox.Size = new System.Drawing.Size(44, 20);
this.adcTextBox.TabIndex = 21;
//
// groupBox4
//
this.groupBox4.Controls.Add(this.label4);
this.groupBox4.Controls.Add(this.adcTextBox);
this.groupBox4.Location = new System.Drawing.Point(10, 352);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(279, 40);
this.groupBox4.TabIndex = 22;
this.groupBox4.TabStop = false;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(11, 17);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(32, 13);
this.label4.TabIndex = 22;
this.label4.Text = "ADC:";
//
// categoryComboBox
//
this.categoryComboBox.Enabled = false;
this.categoryComboBox.FormattingEnabled = true;
this.categoryComboBox.Location = new System.Drawing.Point(138, 90);
this.categoryComboBox.Name = "categoryComboBox";
this.categoryComboBox.Size = new System.Drawing.Size(130, 21);
this.categoryComboBox.TabIndex = 6;
//
// categoryLabel
//
this.categoryLabel.AutoSize = true;
this.categoryLabel.Location = new System.Drawing.Point(28, 93);
this.categoryLabel.Name = "categoryLabel";
this.categoryLabel.Size = new System.Drawing.Size(49, 13);
this.categoryLabel.TabIndex = 5;
this.categoryLabel.Text = "Category";
//
// reTryCommandsCheckBox
//
this.reTryCommandsCheckBox.AutoSize = true;
this.reTryCommandsCheckBox.Enabled = false;
this.reTryCommandsCheckBox.Location = new System.Drawing.Point(31, 262);
this.reTryCommandsCheckBox.Name = "reTryCommandsCheckBox";
this.reTryCommandsCheckBox.Size = new System.Drawing.Size(108, 17);
this.reTryCommandsCheckBox.TabIndex = 18;
this.reTryCommandsCheckBox.Text = "Re-try commands";
this.reTryCommandsCheckBox.UseVisualStyleBackColor = true;
//
// RegulValveCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.reTryCommandsCheckBox);
this.Controls.Add(this.categoryComboBox);
this.Controls.Add(this.categoryLabel);
this.Controls.Add(this.groupBox4);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.flowStableSecTextBox);
this.Controls.Add(this.flowStableSecLabel);
this.Controls.Add(this.stableTimeTextBox);
this.Controls.Add(this.stableTimeLabel);
this.Controls.Add(this.storedPosReuseCheckBox);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.adcOpenTextBox);
this.Controls.Add(this.adcOpenLabel);
this.Controls.Add(this.adcClosedTextBox);
this.Controls.Add(this.adcClosedLabel);
this.Controls.Add(this.positionTextBox);
this.Controls.Add(this.positionLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "RegulValveCfgCtrl";
this.Size = new System.Drawing.Size(300, 700);
this.Load += new System.EventHandler(this.RegulationValveCfgCtrl_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.groupBox4.ResumeLayout(false);
this.groupBox4.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox positionTextBox;
private System.Windows.Forms.Label positionLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.Label adcClosedLabel;
private System.Windows.Forms.TextBox adcClosedTextBox;
private System.Windows.Forms.TextBox adcOpenTextBox;
private System.Windows.Forms.Label adcOpenLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.CheckBox storedPosReuseCheckBox;
private System.Windows.Forms.TextBox stableTimeTextBox;
private System.Windows.Forms.Label stableTimeLabel;
private System.Windows.Forms.TextBox flowStableSecTextBox;
private System.Windows.Forms.Label flowStableSecLabel;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button setButton1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label ADC;
private System.Windows.Forms.Button getButton1;
private System.Windows.Forms.TextBox pctTextBox1;
private System.Windows.Forms.TextBox adcTextBox1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Button setButton2;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button getButton2;
private System.Windows.Forms.TextBox pctTextBox2;
private System.Windows.Forms.TextBox adcTextBox2;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.Button openButton;
private System.Windows.Forms.TextBox adcTextBox;
private System.Windows.Forms.GroupBox groupBox4;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox categoryComboBox;
private System.Windows.Forms.Label categoryLabel;
private System.Windows.Forms.CheckBox reTryCommandsCheckBox;
}
}

View File

@ -0,0 +1,350 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using log4net;
using Config.Entities;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public partial class RegulValveCfgCtrl : UserControl, IComponentCfgCtrl
{
static readonly ILog log = LogManager.GetLogger(typeof(RegulValveCfgCtrl));
ComponentParametersDlg parent;
public bool ShowMore { get { return true; } }
RegulValveCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as RegulValveCfg;
Redraw();
}
}
public RegulValveCfgCtrl()
{
InitializeComponent();
}
private void RegulationValveCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.TbfComponents != null)
{
foreach (var cmpnt in parent.TbfComponents)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Elde.ControlBoardFactory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
categoryComboBox.Items.Add(ValveCategory.Feeding.ToString());
categoryComboBox.Items.Add(ValveCategory.Output.ToString());
if (config != null)
{
adc1 = config.AdcValueClosed;
pct1 = 0;
adc2 = config.AdcValueOpen;
pct2 = 100;
}
Redraw();
StartResponseHandler();
}
public void Closing()
{
StopResponseHandler();
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
categoryComboBox.Text = config.Category.ToString();
positionTextBox.Text = config.Idx1.ToString();
adcClosedTextBox.Text = config.AdcValueClosed.ToString();
adcOpenTextBox.Text = config.AdcValueOpen.ToString();
stableTimeTextBox.Text = config.StableTimeMs.ToString();
flowStableSecTextBox.Text = config.FlowStableSec.ToString();
storedPosReuseCheckBox.Checked = config.StoredPositionReuse;
reTryCommandsCheckBox.Checked = config.ReTryCommands;
adcTextBox1.Text = adc1.ToString();
adcTextBox2.Text = adc2.ToString();
pctTextBox1.Text = pct1.ToString();
pctTextBox2.Text = pct2.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
categoryComboBox.Enabled = true;
positionTextBox.Enabled = true;
adcClosedTextBox.Enabled = true;
adcOpenTextBox.Enabled = true;
stableTimeTextBox.Enabled = true;
flowStableSecTextBox.Enabled = true;
storedPosReuseCheckBox.Enabled = true;
reTryCommandsCheckBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!categoryComboBox.Text.Equals(ValveCategory.Feeding.ToString()) &&
!categoryComboBox.Text.Equals(ValveCategory.Output.ToString()))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Category'";
}
if (!int.TryParse(positionTextBox.Text, out dummy) || dummy < 1 || dummy > 8)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Position' should be between 1 and 8";
}
if (!int.TryParse(adcClosedTextBox.Text, out dummy) || dummy < 0 || dummy > 1023)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'ADC when Closed' should be between 0 and 1023";
}
if (!int.TryParse(adcOpenTextBox.Text, out dummy) || dummy < 0 || dummy > 1023)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'ADC when Open' should be between 0 and 1023";
}
if (!int.TryParse(stableTimeTextBox.Text, out dummy) || dummy < 200 || dummy > 1500 || (dummy % 50) != 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Stable time' should be between 200 and 1500 ms in 50 ms steps";
}
if (!int.TryParse(flowStableSecTextBox.Text, out dummy) || dummy < 0 || dummy > 60)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Flow stable' should be between 0 and 60 sec";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
///
if (!config.Name.Equals(nameTextBox.Text))
{
config.Name = nameTextBox.Text;
flags |= CfgUpdateFlags.RestartRqrd;
}
string parentname = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
if (!config.ParentName.Equals(parentname))
{
config.ParentName = parentname;
flags |= CfgUpdateFlags.RestartRqrd;
}
ValveCategory newCategory;
if (categoryComboBox.Text.Equals(ValveCategory.Feeding.ToString())) newCategory = ValveCategory.Feeding;
else if (categoryComboBox.Text.Equals(ValveCategory.Output.ToString())) newCategory = ValveCategory.Output;
else newCategory = ValveCategory.None;
if (newCategory != config.Category)
{
config.Category = newCategory;
flags |= CfgUpdateFlags.RestartRqrd;
}
int tmp = int.Parse(positionTextBox.Text);
if (config.Idx1 != tmp)
{
config.Idx1 = tmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
tmp = int.Parse(adcClosedTextBox.Text);
if (config.AdcValueClosed != tmp)
{
config.AdcValueClosed = tmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
tmp = int.Parse(adcOpenTextBox.Text);
if (config.AdcValueOpen != tmp)
{
config.AdcValueOpen = tmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
tmp = int.Parse(stableTimeTextBox.Text);
if (config.StableTimeMs != tmp)
{
config.StableTimeMs = tmp;
flags |= CfgUpdateFlags.AnyChange;
}
tmp = int.Parse(flowStableSecTextBox.Text);
if (config.FlowStableSec != tmp)
{
config.FlowStableSec = tmp;
flags |= CfgUpdateFlags.AnyChange;
}
bool btmp = storedPosReuseCheckBox.Checked;
if (config.StoredPositionReuse != btmp)
{
config.StoredPositionReuse = btmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
btmp = reTryCommandsCheckBox.Checked;
if (config.ReTryCommands != btmp)
{
config.ReTryCommands = btmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
if ((flags & CfgUpdateFlags.AnyChange) != 0)
{
RegulValve.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.CfgChange, config));
}
return flags;
}
int adc1;
int pct1;
int adc2;
int pct2;
private void openButton_Click(object sender, EventArgs e)
{
RegulValve.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.RVOpenStep, config));
}
private void closeButton_Click(object sender, EventArgs e)
{
RegulValve.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.RVCloseStep, config));
}
//
private void getButton1_Click(object sender, EventArgs e)
{
RegulValve.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.GetAdc1, config));
}
private void getButton2_Click(object sender, EventArgs e)
{
RegulValve.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.GetAdc2, config));
}
private void setButton_Click(object sender, EventArgs e)
{
int tmpPct1;
int tmpPct2;
if ((int.TryParse(pctTextBox1.Text, out tmpPct1) && (tmpPct1 >= 0) && (tmpPct1 <= 100)) &&
(int.TryParse(pctTextBox2.Text, out tmpPct2) && (tmpPct2 >= 0) && (tmpPct2 <= 100)))
{
pct1 = tmpPct1;
pct2 = tmpPct2;
UpdateValveOpenClose();
}
}
void UpdateValveOpenClose()
{
if ((adc1 == adc2) || (pct1 == pct2)) return;
double factor = (float)(adc2 - adc1) / (float)(pct2 - pct1);
int adcClosed = (int)((float)(0 - pct1) * factor + (float)adc1 + 0.5f);
int adcOpen = (int)((float)(100 - pct1) * factor + (float)adc1 + 0.5f);
if ((adcClosed >= 0) && (adcOpen >= 0))
{
adcClosedTextBox.Text = adcClosed.ToString();
adcOpenTextBox.Text = adcOpen.ToString();
}
}
#region Configuration Change Handling
public static void OnCmdResponse(object sender, CmdResponseArgs args)
{
if (CmdResponseHandler == null) return;
try { CmdResponseHandler(sender, args); }
catch (Exception e) { log.Error("CmdResponseHandler(...) failed", e); }
}
public static event EventHandler<CmdResponseArgs> CmdResponseHandler;
public void StartResponseHandler()
{
Handlers.AdcChangedHandler += delegate(object sndr, CmdResponseArgs args)
{
if (InvokeRequired) { Invoke(new EventHandler<CmdResponseArgs>(OnAdcChanged), sndr, args); }
else OnAdcChanged(sndr, args);
};
CmdResponseHandler += delegate(object sender, CmdResponseArgs args)
{
if (args.Command == CfgChangeCmd.GetAdc1)
{
adc1 = args.Response;
adcTextBox1.Text = adc1.ToString();
}
else if (args.Command == CfgChangeCmd.GetAdc2)
{
adc2 = args.Response;
adcTextBox2.Text = adc2.ToString();
}
};
}
public void StopResponseHandler()
{
CmdResponseHandler = null;
}
void OnAdcChanged(object sender, CmdResponseArgs data)
{
if (data.Command == CfgChangeCmd.GetAdc && data.Id == config.Idx1)
{
adcTextBox.Text = data.Response.ToString();
}
}
#endregion Configuration Change Handling
}
}

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,461 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
using TBF.Boxes;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class SetFlowOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(SetFlowOp));
public override string ToString()
{
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regulValve.Name, requiredFlowLo, requiredFlowHi);
}
/// Set by the constructor
readonly ControlBoardDev controlBoard;
readonly RegulValve regulValve;
readonly int regulValveNr;
readonly IFlowMeter flowMeter;
readonly double requiredFlowLo;
readonly double requiredFlowHi;
readonly double reqFlowAve;
readonly int timeout;
readonly bool leaveMeasurementRunning;
readonly bool reTryCommands;
readonly double nominalFlow;
readonly double maximalFlow;
///
/// Internal states of this operation
///
enum OpState
{
Idle = 0,
ValveMoveToPosition1, /// Wait 1 takt
ValveMoveToPosition2, /// This is actual move to position
ValveMoveToPosition3, /// Wait 1 takt
CheckStatePosition, /// Verify
SettingPosition,
ValveMoveToFlow1, /// Wait 1 takt
ValveMoveToFlow2, /// This is actual move to flow
ValveMoveToFlow3, /// Wait 1 takt
CheckStateFlow, /// Verify
SettingFlow,
FlowReached,
SendCommandAgain,
}
OpState opState;
double currentReqFlowLo;
double currentReqFlowHi;
float targetPositionLo;
float targetPositionHi;
int startTime;
int expireTime;
DoubleBox flowBox;
int flowWithinBoundsTime;
/// <summary>
/// Set required water flow. Conditionally leave the measurement running.
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="regulValve">Regulation valve component</param>
/// <param name="flowMeter">Flowmeter component</param>
/// <param name="requiredFlowLo">Lower limit of the flow to be achieved in [m3/h]</param>
/// <param name="requiredFlowHi">Upper limit of the flow to be achieved in [m3/h]</param>
/// <param name="pidCoef">PID coefficient (float)</param>
/// <param name="timeout">Timeout for the flow setting in [s]</param>
/// <param name="leaveMeasurementRunning">true = Leave the measurement running after op. stop</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public SetFlowOp(ControlBoardDev controlBoard, IRegulValve regulValve, IFlowMeter flowMeter, double requiredFlowLo, double requiredFlowHi,
DoubleBox flowBox, bool reTryCmds, int timeout, bool leaveMeasurementRunning)
{
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.controlBoard = controlBoard;
this.regulValve = regulValve as RegulValve;
if (this.regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
regulValveNr = this.regulValve.Idx1;
if (flowMeter == null) throw new ArgumentNullException("flowMeter");
this.flowMeter = flowMeter;
nominalFlow = flowMeter.NominalFlow;
maximalFlow = nominalFlow * 1.25;
this.reqFlowAve = (requiredFlowLo + requiredFlowHi) / 2;
this.requiredFlowLo = (0.7 * requiredFlowLo) + (0.3 * this.reqFlowAve); /// Move the lower limit 15% of the range up
this.requiredFlowHi = (0.7 * requiredFlowHi) + (0.3 * this.reqFlowAve); /// Move the upper limit 15% of the range down
if (flowBox == null) throw new ArgumentNullException("flowBox");
this.flowBox = flowBox;
this.reTryCommands = reTryCmds;
this.timeout = timeout;
this.leaveMeasurementRunning = leaveMeasurementRunning;
log.Debug(this.ToString());
}
/// <summary>
/// Set required water flow - Do not leave the measurement running.
/// Events: FlowSet
/// </summary>
public SetFlowOp(ControlBoardDev controlBoard, IRegulValve regValve, IFlowMeter flowMeter, double requiredFlowLo, double requiredFlowHi,
DoubleBox flowbox, bool reTryCmds, int timeout)
: this(controlBoard, regValve, flowMeter, requiredFlowLo, requiredFlowHi, flowbox, reTryCmds, timeout, false)
{
}
/// <summary>
/// Set required water flow - No timeout.
/// Events: FlowSet
/// </summary>
public SetFlowOp(ControlBoardDev controlBoard, IRegulValve regValve, IFlowMeter flowMeter, double requiredFlowLo, double requiredFlowHi,
DoubleBox flowbox, bool reTryCmds)
: this(controlBoard, regValve, flowMeter, requiredFlowLo, requiredFlowHi, flowbox, reTryCmds, int.MaxValue, false)
{
}
/// <summary>
/// Fetch target position limits from the dictionary or return false
/// </summary>
/// <param name="avgReqFlow">Average of the flow targer range (input)</param>
/// <param name="positionLo">Target valve position low limit (output)</param>
/// <param name="positionHi">Target valve position high limit (output)</param>
/// <returns>true when positions for the target flow are stored in the memory, otherwise return false</returns>
bool FetchTargetPosition(double avgReqFlow, out float positionLo, out float positionHi)
{
float targetPosition;
if (regulValve.Dict.TryGetValue(avgReqFlow, out targetPosition))
{
positionLo = Math.Max(targetPosition * 0.95f, 0.0f);
positionHi = Math.Min(targetPosition * 1.05f, 100.0f);
return true;
}
else
{
positionLo = 0.0f;
positionHi = 0.0f;
return false;
}
}
void StoreTargetPosition(double avgReqFlow, float actPosition)
{
if (!regulValve.Dict.ContainsKey(reqFlowAve))
{
regulValve.Dict.Add(new KeyValuePair<double, float>(avgReqFlow, actPosition));
}
return;
}
/// <summary>Start this operation</summary>
public void Start()
{
startTime = StateMachine.Time;
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
double flowMtrFreq = flowMeter.ReadFrequency();
double flow = flowMeter.ReadFlow();
currentReqFlowLo = requiredFlowLo; /// Default lower limit
currentReqFlowHi = requiredFlowHi; /// Default upper limit
if (flow != 0)
{
flowBox.Val = flow;
if (flow >= reqFlowAve) currentReqFlowHi = reqFlowAve; /// Decrease upper limit
if (flow <= reqFlowAve) currentReqFlowLo = reqFlowAve; /// Increase lower limit
}
flowWithinBoundsTime = 0;
if (regulValve.RegulValveCfg.StoredPositionReuse && FetchTargetPosition(reqFlowAve, out targetPositionLo, out targetPositionHi))
{
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3} FETCHED: posLo={4} posHi={5}",
regulValveNr, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi, targetPositionLo, targetPositionHi);
opState = OpState.ValveMoveToPosition1;
}
else
{
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
opState = OpState.ValveMoveToFlow1;
}
/// Start flow measurement
controlBoard.SendCommand(Command.Start, flowMeter.Idx1, int.MaxValue, int.MaxValue, 0, 0); /// TestMethods=0, StopDevs=0
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.OpArgumentError
/// Event.Starting
/// Event.Busy
/// Event.FlowReached
/// Event.RegulValveTimeOut
/// </returns>
public Event Run()
{
float rvPosition = controlBoard.RValvePosition(regulValveNr);
double flowMtrFreq = flowMeter.ReadFrequency();
double flow = flowMeter.ReadFlow();
if (flow != 0)
{
flowBox.Val = flow;
}
log.InfoFormat("SetFlowOp:Run(T={0}) rv#={1} pos={2}% freq={3} flow={4} opState={5}",
StateMachine.Time - startTime, regulValveNr, rvPosition.ToString("F1"), flowMtrFreq, flow, opState);
if (StateMachine.Time > expireTime)
{
return Event.RegulValveTimeOut;
}
else if (opState == OpState.SendCommandAgain)
{
flowWithinBoundsTime = 0;
if (regulValve.RegulValveCfg.StoredPositionReuse && FetchTargetPosition(reqFlowAve, out targetPositionLo, out targetPositionHi))
{
log.InfoFormat("Run(): rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3} FETCHED: posLo={4} posHi={5}",
regulValveNr, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi, targetPositionLo, targetPositionHi);
opState = OpState.ValveMoveToPosition1;
}
else
{
log.InfoFormat("Run(): rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
opState = OpState.ValveMoveToFlow1;
}
/// Start flow measurement
controlBoard.SendCommand(Command.Start, flowMeter.Idx1, int.MaxValue, int.MaxValue, 0, 0); /// TestMethods=0, StopDevs=0
return Event.Starting;
}
else if (opState == OpState.ValveMoveToPosition1)
{
opState = OpState.ValveMoveToPosition2;
return Event.Starting;
}
else if (opState == OpState.ValveMoveToPosition2) /// Move to position
{
/// Issues the appropriate ValveMove(...) command
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetPosition,
new float[2] { targetPositionLo, targetPositionHi },
regulValve.StableTime,
true);
opState = OpState.SettingPosition;
return Event.Starting;
}
else if (opState == OpState.ValveMoveToPosition3)
{
if (reTryCommands)
{
opState = OpState.CheckStatePosition;
}
else
{
opState = OpState.SettingPosition;
}
return Event.Starting;
}
else if (opState == OpState.CheckStatePosition) /// Verify
{
if (((ulong)controlBoard.StatusP & (ulong)StatusP.RefPulsesMsrmnt) == 0)
{
opState = OpState.SendCommandAgain;
return Event.Starting;
}
else if (controlBoard.RegulValveState(regulValveNr) != RegulValveState.DacValueRegul)
{
/// Repeat appropriate ValveMove(...) command
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetPosition,
new float[2] { targetPositionLo, targetPositionHi },
regulValve.StableTime,
true);
log.InfoFormat("SetFlowOp: ValveMove({0}, Position, {1}, {2}, {3})",
regulValveNr, targetPositionLo, targetPositionHi, regulValve.StableTime);
opState = OpState.ValveMoveToPosition3;
return Event.Starting;
}
else
{
opState = OpState.SettingPosition;
return Event.Starting;
}
}
else if (opState == OpState.SettingPosition)
{
/// Repeated untill position is reached
if ((targetPositionLo <= rvPosition) && (rvPosition <= targetPositionHi))
{
opState = OpState.ValveMoveToFlow1;
}
return Event.Starting;
}
else if (opState == OpState.ValveMoveToFlow1)
{
opState = OpState.ValveMoveToFlow2;
return Event.Starting;
}
else if (opState == OpState.ValveMoveToFlow2) /// Move to flow
{
///
/// Done once, issues an appropriate ValveMove(...) command
///
if ((currentReqFlowLo >= currentReqFlowHi) || (currentReqFlowLo > maximalFlow) || (currentReqFlowHi <= 0))
{
return Event.OpArgumentError;
}
log.InfoFormat("Run(): rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
double freqLo = 2000.0 * currentReqFlowLo / nominalFlow;
double freqHi = 2000.0 * currentReqFlowHi / nominalFlow;
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { (float)freqLo, (float)freqHi },
regulValve.StableTime,
true);
opState = OpState.ValveMoveToFlow3;
return Event.Starting;
}
else if (opState == OpState.ValveMoveToFlow3)
{
if (reTryCommands)
{
opState = OpState.CheckStateFlow;
}
else
{
opState = OpState.SettingFlow;
}
return Event.Starting;
}
else if (opState == OpState.CheckStateFlow) /// Verify the flow setting
{
if ( ((ulong)controlBoard.StatusP & (ulong)StatusP.RefPulsesMsrmnt) == 0 ||
(controlBoard.RegulValveState(regulValveNr) & RegulValveState.PwOrFreqRegul) != RegulValveState.PwOrFreqRegul)
{
opState = OpState.SendCommandAgain;
return Event.Starting;
}
else if (controlBoard.RegulValveState(regulValveNr) != RegulValveState.PwOrFreqRegul)
{
/// Done once, issues an appropriate ValveMove(...) command
double freqLo = 2000.0 * currentReqFlowLo / nominalFlow;
double freqHi = 2000.0 * currentReqFlowHi / nominalFlow;
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { (float)freqLo, (float)freqHi },
regulValve.StableTime,
true);
log.InfoFormat("SetFlowOp: ValveMove({0}, Frequency, {1}, {2}, {3})",
regulValveNr, freqLo, freqHi, regulValve.StableTime);
opState = OpState.ValveMoveToFlow3;
return Event.Starting;
}
else
{
opState = OpState.SettingFlow;
return Event.Busy;
}
}
else if (opState == OpState.SettingFlow)
{
/// Regulation valve is setting flow to the required value
if ((currentReqFlowLo <= flow) && (flow <= currentReqFlowHi))
{
/// Flow is within range
if (flowWithinBoundsTime++ >= regulValve.FlowStableSec)
{
/// Flow is within range for sufficiently long time
if (regulValve.RegulValveCfg.StoredPositionReuse)
{
float storedPosition;
if (regulValve.Dict.TryGetValue(reqFlowAve, out storedPosition))
{
/// update the stored valve position
StoreTargetPosition(reqFlowAve, (rvPosition + storedPosition) / 2.0f);
log.InfoFormat("Run(): rv#={0} reqFlow={1} pos={2}% stored={3} <--- Updating a stored position",
regulValveNr, reqFlowAve, rvPosition.ToString("F1"), storedPosition);
}
else
{
/// store the valve position
StoreTargetPosition(reqFlowAve, rvPosition);
log.InfoFormat("Run(): rv#={0} reqFlow={1} pos={2}% <--- Storing a new position",
regulValveNr, reqFlowAve, rvPosition.ToString("F1"));
}
}
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, REACHED)", flow, currentReqFlowLo, currentReqFlowHi);
opState = OpState.FlowReached;
return Event.FlowReached;
}
else
{
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, FLOW_OK_TIMER={3}s)", flow, currentReqFlowLo, currentReqFlowHi, flowWithinBoundsTime);
return Event.Busy;
}
}
else if (StateMachine.Time > expireTime)
{
return Event.RegulValveTimeOut;
}
else
{
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2})", flow, currentReqFlowLo, currentReqFlowHi);
flowWithinBoundsTime = 0;
return Event.Busy;
}
}
else /// opState == OpState.FlowReached
{
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, REACHED)", flow, currentReqFlowLo, currentReqFlowHi);
return Event.FlowReached;
}
}
/// <summary>Start this operation</summary>
public void Stop()
{
if (!leaveMeasurementRunning)
{
/// Stop measurement
controlBoard.SendCommand(Command.Stop, flowMeter.Idx1, 50000, 50000, 0, StopDevs.RegValveRegulation); /// TestMethods=0
}
opState = OpState.Idle;
}
}
}

View File

@ -0,0 +1,167 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
namespace TBF.BenchControl.Elde.RegulValveMilwaukee
{
public class SetRegulValvePositionOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(SetRegulValvePositionOp));
public override string ToString()
{
return string.Format("SetRegulValvePositionOp({0},{1},{2})", regulValve.Name, posLoPct, posHiPct);
}
const int CoaxValveNr = 7; /// Coax. valve has number 7
///
/// Internal states of this operation
///
enum OpState
{
Idle = 0,
MoveToPosition, /// Send commend to move to position
CheckState, /// Check RV state by reading statos word
MovingToPosition, /// Command passed OK, RV is moving to a position
}
OpState opState;
/// Set by the constructor
readonly ControlBoardDev controlBoard;
readonly RegulValve regulValve;
readonly int regulValveNr;
readonly float posLoPct;
readonly float posHiPct;
readonly int timeout;
/// Process values
bool firstRun;
int expireTime;
bool positionReached;
/// <summary>
/// Set required water flow.
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="_regulValve">Regulation valve component</param>
/// <param name="posLoPct">Lower limit of the position to be achieved</param>
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
/// <param name="timeout">Timeout in sec. for setting the flow</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public SetRegulValvePositionOp(ControlBoardDev controlBoard, RegulValve regulValve, float posLoPct, float posHiPct, int timeout)
{
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.controlBoard = controlBoard;
this.regulValve = regulValve as RegulValve;
if (regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
this.regulValveNr = this.regulValve.Idx1;
this.posLoPct = posLoPct;
this.posHiPct = posHiPct;
this.timeout = timeout;
log.Debug(this.ToString());
}
/// <summary>
/// Set required water flow - no timeout.
/// Events: FlowSet
/// </summary>
public SetRegulValvePositionOp(ControlBoardDev controlBoard, RegulValve regValve, float posLoPct, float posHiPct)
: this(controlBoard, regValve, posLoPct, posHiPct, int.MaxValue)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
firstRun = true;
positionReached = false;
expireTime = StateMachine.Time + timeout;
log.InfoFormat("Start(): RV#={0}, reqPosLo={1}%, reqPosHi={2}%", regulValveNr, posLoPct.ToString("F1"), posHiPct.ToString("F1"));
opState = OpState.MoveToPosition;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.None . . . . . . . busy adjusting position
/// Event.PositionReached . . position reached
/// Event.OpArgumentError . . invalid required position
/// </returns>
public Event Run()
{
if (opState == OpState.MoveToPosition)
{
if (posLoPct >= posHiPct || posLoPct > 100.0f || posHiPct < 0)
{
return Event.OpArgumentError;
}
firstRun = false;
controlBoard.ValveMove(regulValveNr,
RegulValveMode.TargetPosition,
new float[2] { posLoPct, posHiPct },
regulValve.StableTime,
true);
opState = OpState.CheckState;
return Event.None;
}
if (positionReached) return Event.PositionReached;
float positionPct = controlBoard.RValvePosition(regulValveNr);
log.WarnFormat("Run(): RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
if (opState == OpState.CheckState)
{
if (regulValveNr == CoaxValveNr && ((ulong)controlBoard.StatusP & (ulong)StatusP.CoaxRegValveBusy) == 0)
{
opState = OpState.MoveToPosition;
return Event.None;
}
else if (posLoPct <= positionPct && positionPct <= posHiPct)
{
positionReached = true;
return Event.PositionReached;
}
else if ((regulValveNr < 6) && (controlBoard.RegulValveState(regulValveNr) != RegulValveState.DacValueRegul))
{
opState = OpState.MoveToPosition; /// Resend move command again in the next run
return Event.None;
}
else
{
opState = OpState.MovingToPosition;
return Event.None;
}
}
else if (StateMachine.Time > expireTime)
{
return Event.RegulValveTimeOut;
}
else if (opState == OpState.MovingToPosition)
{
if (posLoPct <= positionPct && positionPct <= posHiPct)
{
positionReached = true;
return Event.PositionReached;
}
return Event.None;
}
return Event.None;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -81,17 +81,23 @@ namespace TBF.BenchControl.Elde
this.regulValve = outputPath.RegulValve;
if (regulValve is Elde.RegulValve.RegulValve)
{
Elde.RegulValve.RegulValve rv = outputPath.RegulValve as Elde.RegulValve.RegulValve;
var rv = outputPath.RegulValve as Elde.RegulValve.RegulValve;
regulValveNr = rv.Idx1;
regulValveStableTime = rv.StableTime;
}
else if (regulValve is Elde.RegulValveCoax.RegulValve)
{
Elde.RegulValveCoax.RegulValve rv = outputPath.RegulValve as Elde.RegulValveCoax.RegulValve;
var rv = outputPath.RegulValve as Elde.RegulValveCoax.RegulValve;
regulValveNr = rv.Idx1;
regulValveStableTime = rv.StableTime;
}
else if (!(regulValve is Dummy.RegulValve.RegulValve))
else if (regulValve is Elde.RegulValveMilwaukee.RegulValve)
{
var rv = outputPath.RegulValve as Elde.RegulValveMilwaukee.RegulValve;
regulValveNr = rv.Idx1;
regulValveStableTime = rv.StableTime;
}
else if (!(regulValve is Dummy.RegulValve.RegulValve))
{
throw new ArgumentNullException("Regulation valve is not compatible with Elde Control Board");
}
@ -122,7 +128,7 @@ namespace TBF.BenchControl.Elde
int flowMeterIdxAndDiv = flowMeterNr + 8 * (diverterNr - 1);
#elif FILIPINY_50
int flowMeterIdxAndDiv = flowMeterNr + ((flowMeterNr == 3) ? (4 * (diverterNr - 1)) : 0);
#elif GELSENWASSER
#elif GELSENWASSER || MILWAUKEE
int flowMeterIdxAndDiv = flowMeterNr + ((diverterNr == 2) ? 16 : 0);
#else
int flowMeterIdxAndDiv = flowMeterNr;
@ -204,12 +210,20 @@ namespace TBF.BenchControl.Elde
double freqLo = 2000.0 * reqFlowLo / nominalFlow;
double freqHi = 2000.0 * reqFlowHi / nominalFlow;
if (regulValve.IsCoax)
{
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { (float)((freqLo + freqHi) / 2), (float)((freqLo + freqHi) / 2) },
regulValveStableTime);
}
else if (regulValve is RegulValveMilwaukee.RegulValve)
{
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { (float)freqLo, (float)freqHi },
regulValveStableTime,
true);
}
else
{
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,

View File

@ -0,0 +1,26 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Modbus.Novus
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
public void ResetStaticProperties() { Novus.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Novus(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Novus(cfg, components); }
public IComponentCfg DefaultConfig() { return new NovusCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(NovusCfg.Serializer, component, this);
}
}
}

View File

@ -0,0 +1,224 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.Generic;
using TBF.Boxes;
using Config.Entities;
namespace TBF.BenchControl.Modbus.Novus
{
public class Novus : ComponentBase, IDevice, GenericDevices.ITempMeter
{
private static readonly ILog log = LogManager.GetLogger(typeof(Novus));
public override string ToString() { return string.Format("Novus({0})", Cfg.ToString(1)); }
const ushort SetpointAddress = 0; /// Temperature setpoint
const ushort ProcessValueAddress = 1; /// Actual temperature
readonly NovusCfg novusCfg;
readonly GenericDevices.IModbus modbus;
private float temperatureSetPoint;
private bool temperatureSetPointValid;
private bool temperatureSetPointRequested;
public float requiredTemp { get { return novusCfg.ProcParams.RequiredTemp; } }
public Novus()
{
}
public Novus(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
novusCfg = cfg as NovusCfg;
modbus = (GenericDevices.IModbus)TbfComponents.FindComponent(cfg.ParentName, components);
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
log.Warn(this.ToString());
}
/// <summary>Initialize this device</summary>
public void Initialize()
{
if (novusCfg.DebugLevel == DebugMode.Simulate) return;
temperatureSetPointValid = false;
temperatureSetPointRequested = false;
actualTemperatureIsValid = false;
}
/// <summary>Run this device</summary>
public void RunDeviceBefore()
{
if (novusCfg.DebugLevel == DebugMode.Simulate) return;
if (modbus.ReceivedTelegrams[novusCfg.ModbusAddress].Count > 0)
{
byte[] telegram = modbus.ReceivedTelegrams[novusCfg.ModbusAddress].Dequeue();
if (telegram.Length == 7 && telegram[1] == (byte)Function.ReadHoldingRegisters && telegram[2] == 2)
{
ushort value = (ushort)(256 * telegram[3] + telegram[4]);
temperatureSetPoint = (float)value * 0.1f; /// setpoint in 0.1 °C
temperatureSetPointValid = true;
log.InfoFormat("{0} - Received current temperature setpoint = {1}", Name, temperatureSetPoint);
}
else if (telegram.Length == 7 && telegram[1] == (byte)Function.ReadInputRegister && telegram[2] == 2)
{
ushort value = (ushort)(256 * telegram[3] + telegram[4]);
actualTemperature = (double)value * 0.1; /// temperature in 0.1 °C
actualTemperatureIsValid = true;
log.InfoFormat("{0} - Received actual temperature = {1}", Name, actualTemperature);
if (novusCfg.ReservoirNr > 0 && novusCfg.ReservoirNr <= 3)
{
if (temperatureSetPointValid)
{
StateMachine.ControlBoard.SetReservoirTemp(novusCfg.ReservoirNr, temperatureSetPoint);
}
else
{
StateMachine.ControlBoard.SetReservoirTemp(novusCfg.ReservoirNr, 0);
}
StateMachine.ControlBoard.SetReservoirTemp(novusCfg.ReservoirNr + 1, (float)actualTemperature);
}
}
}
if (!temperatureSetPointValid && !temperatureSetPointRequested)
{
RequestTemperatureSetpoint();
temperatureSetPointRequested = true;
}
else if (temperatureSetPointValid && requiredTemp != temperatureSetPoint)
{
SetTemperatureSetpoint(requiredTemp);
log.InfoFormat("{0} - Set new temperature setpoint = {1}", Name, requiredTemp);
}
else if ((StateMachine.Time % 10) == (novusCfg.ModbusAddress % 10)) /// This is to prevent overflow of the Modbus component queue for sending data
{
RequestActualTemperature();
}
}
public void RunDeviceAfter() { }
public void StopDevice() { }
public void StopDevice2() { }
/// <summary>
/// Set Easytherm controller to required temperature procedure parameter
/// </summary>
/// <returns>true = OK, false = any error</returns>
public bool SetTemperatureSetpoint()
{
return SetTemperatureSetpoint(requiredTemp);
}
/// <summary>
/// Set Easytherm controller to specified temperature
/// </summary>
/// <param name="temperature">Temperature in °C</param>
/// <returns>true = OK, false = any error</returns>
public bool SetTemperatureSetpoint(float temperature)
{
if (temperature != 0 && (temperature < 5 || temperature > 95.0f))
{
return false; /// required temperature out of range
}
if (temperatureSetPointValid && (temperature == temperatureSetPoint))
{
return true; /// already set to the required temperature
}
if (temperature != 0) /// temperature==0 disables sending the setpoint
{
ushort usTempSetpoint = Convert.ToUInt16(Math.Round(10 * temperature)); /// setpoint in 0.1 °C
ushort destAddress = SetpointAddress;
///
SendValueToEasytherm(Function.PresetSingleRegister, destAddress, usTempSetpoint);
}
temperatureSetPoint = temperature;
temperatureSetPointValid = true;
return true;
}
public void RequestTemperatureSetpoint()
{
SendValueToEasytherm(Function.ReadHoldingRegisters, SetpointAddress, (ushort)1); /// rel.address=2, 1 word
}
public void RequestActualTemperature()
{
SendValueToEasytherm(Function.ReadInputRegister, ProcessValueAddress, (ushort)1); // rel.address=x, 1 word
}
void SendValueToEasytherm(Function function, ushort address, ushort value)
{
byte[] msg = new byte[8];
msg[0] = novusCfg.ModbusAddress;
msg[1] = (byte)function;
msg[2] = (byte)(address >> 8); /// Relative address Hi
msg[3] = (byte)(address & 0xFF); /// Relative address Lo
msg[4] = (byte)(value >> 8); /// Data Hi
msg[5] = (byte)(value & 0xFF); /// Data Lo
modbus.SendMessage(msg);
}
///
/// Operations, etc.
///
double actualTemperature;
bool actualTemperatureIsValid;
public double ReadTemperature()
{
return actualTemperature;
}
/// <summary>
/// Events: SetOpututsDone, Error
/// </summary>
/// <returns>SetOutputsOp instance reference casted to IOperaton</returns>
public IOperation SetRequiredTemperatureOp()
{
return new SetRequiredTemperatureOp(this);
}
/// <summary>
/// Events: SetOpututsDone, Error
/// </summary>
/// <param name="temperature">Reference to a variable for the pressure in Bar</param>
/// <returns>SetOutputsOp instance reference casted to IOperaton</returns>
public IOperation SetTemperatureOp(float temperature)
{
return new SetTemperatureOp(this, temperature);
}
public IOperation ReadTempOp(ref DoubleBox temp)
{
return new ReadTempOp(this, ref temp);
}
public IOperation ReadTempOp(ref DoubleBox temp, Event eventDone)
{
return new ReadTempOp(this, ref temp, eventDone);
}
}
}

View File

@ -0,0 +1,55 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Modbus.Novus
{
public class NovusCfg : ComponentCfgBase, Generic.IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(NovusCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new NovusCfgCtrl(); }
///
/// Serialized parameters
///
public byte ModbusAddress; /// 1..254
public int ReservoirNr;
/// <summary> Procedure parameters </summary>
[XmlIgnore]
public ProcParams ProcParams;
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
public override IParamsProvider CreateProcParamsProvider() { return new ProcParams(true); }
/// Private parameterless constructor invoked by all other (public) constructors
NovusCfg()
{
Name = "Novus";
ParentName = "Modbus";
ModbusAddress = 1;
ProcParams = CreateProcParamsProvider() as ProcParams;
}
public NovusCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, ModbusAddr={1}, Parent={2}",
Name,
ModbusAddress,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName));
}
}
}

View File

@ -0,0 +1,112 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Modbus.Novus
{
public partial class NovusCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
NovusCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as NovusCfg;
Redraw();
}
}
public NovusCfgCtrl()
{
InitializeComponent();
}
private void QuidoRSCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.TbfComponents != null)
{
foreach (var cmpnt in parent.TbfComponents)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.Common.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
componentNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
modbusAddressTextBox.Text = config.ModbusAddress.ToString();
reservoirNrTextBox.Text = config.ReservoirNr.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
modbusAddressTextBox.Enabled = true;
reservoirNrTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!int.TryParse(modbusAddressTextBox.Text, out dummy) || dummy < 0 || dummy > 255)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Modbus Address' should be between 0 and 255";
}
if (!int.TryParse(reservoirNrTextBox.Text, out dummy) || dummy < 0 || dummy > 3)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Reservoir Nr.' should be between 0 and 3";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
config.ModbusAddress = (byte)int.Parse(modbusAddressTextBox.Text);
config.ReservoirNr = int.Parse(reservoirNrTextBox.Text);
return flags;
}
}
}

View File

@ -0,0 +1,156 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
namespace TBF.BenchControl.Modbus.Novus
{
partial class NovusCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.componentNameLabel = new System.Windows.Forms.Label();
this.modbusAddressLabel = new System.Windows.Forms.Label();
this.modbusAddressTextBox = new System.Windows.Forms.TextBox();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.reservoirNrTextBox = new System.Windows.Forms.TextBox();
this.reservoirNrLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(28, 81);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
this.parentNameLabel.TabIndex = 3;
this.parentNameLabel.Text = "Parent Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(138, 52);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(28, 55);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// componentNameLabel
//
this.componentNameLabel.AutoSize = true;
this.componentNameLabel.Location = new System.Drawing.Point(135, 28);
this.componentNameLabel.Name = "componentNameLabel";
this.componentNameLabel.Size = new System.Drawing.Size(83, 13);
this.componentNameLabel.TabIndex = 0;
this.componentNameLabel.Text = "ComonentName";
//
// modbusAddressLabel
//
this.modbusAddressLabel.AutoSize = true;
this.modbusAddressLabel.Location = new System.Drawing.Point(28, 108);
this.modbusAddressLabel.Name = "modbusAddressLabel";
this.modbusAddressLabel.Size = new System.Drawing.Size(86, 13);
this.modbusAddressLabel.TabIndex = 7;
this.modbusAddressLabel.Text = "Modbus Address";
//
// modbusAddressTextBox
//
this.modbusAddressTextBox.Enabled = false;
this.modbusAddressTextBox.Location = new System.Drawing.Point(138, 105);
this.modbusAddressTextBox.Name = "modbusAddressTextBox";
this.modbusAddressTextBox.Size = new System.Drawing.Size(46, 20);
this.modbusAddressTextBox.TabIndex = 8;
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(138, 78);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 4;
//
// reservoirNrTextBox
//
this.reservoirNrTextBox.Enabled = false;
this.reservoirNrTextBox.Location = new System.Drawing.Point(138, 130);
this.reservoirNrTextBox.Name = "reservoirNrTextBox";
this.reservoirNrTextBox.Size = new System.Drawing.Size(46, 20);
this.reservoirNrTextBox.TabIndex = 10;
//
// reservoirNrLabel
//
this.reservoirNrLabel.AutoSize = true;
this.reservoirNrLabel.Location = new System.Drawing.Point(28, 133);
this.reservoirNrLabel.Name = "reservoirNrLabel";
this.reservoirNrLabel.Size = new System.Drawing.Size(67, 13);
this.reservoirNrLabel.TabIndex = 9;
this.reservoirNrLabel.Text = "Reservoir nr.";
//
// EasythermCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.reservoirNrTextBox);
this.Controls.Add(this.reservoirNrLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.modbusAddressTextBox);
this.Controls.Add(this.modbusAddressLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.componentNameLabel);
this.Name = "EasythermCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.QuidoRSCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label componentNameLabel;
private System.Windows.Forms.Label modbusAddressLabel;
private System.Windows.Forms.TextBox modbusAddressTextBox;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.TextBox reservoirNrTextBox;
private System.Windows.Forms.Label reservoirNrLabel;
}
}

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,139 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.IO;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Resources;
namespace TBF.BenchControl.Modbus.Novus
{
public class ProcParams : ProcedureParamsBase, IParamsProvider, IProcedureParams
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ProcParams) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public float RequiredTemp; /// [°C] target temperature for a temperature controller or 0=not communicated to the controller
public override void InitializeAll()
{
RequiredTemp = 0.0f;
}
string[] paramNames = new string[]
{
Strings.Required_temperature_C,
};
public override string ParamName(int i) { return paramNames[i]; }
public override int ParamsCount() { return paramNames.Length; }
public override string ToString(int i)
{
switch (i)
{
case 0: return (RequiredTemp == 0) ? "---" : RequiredTemp.ToString();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0:
if (strValue == "-" || strValue == "--" || strValue == "---")
{
RequiredTemp = 0;
}
else
{
RequiredTemp = Utils.ParseUFloat(strValue);
}
return CfgUpdateFlags.None;
default:
return CfgUpdateFlags.None;
}
}
/// <summary>
/// Verifiy the string representation of the parameter
/// </summary>
/// <param name="i">Parameter ID</param>
/// <param name="strValue">String representation of the parameter</param>
/// <param name="message">In case false is returned this is the error messsage to be displayed</param>
/// <returns>true = parameter OK, false = parameter NOK</returns>
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
float temp;
switch (i)
{
case 0: /// T_hot_heating
if (strValue == "-" || strValue == "--" || strValue == "---" ||
(Utils.TryParseUFloat(strValue, out temp) && (temp == 0 || (temp >= 5 && temp <= 95.0f))))
{
return true;
}
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(ProcParams prms)
{
prms.RequiredTemp = this.RequiredTemp;
}
public IParamsProvider Clone()
{
ProcParams pars = new ProcParams();
CopyContentTo(pars);
return pars;
}
public override void UpdateFromDbEntity(ComponentProcedure dbEntity)
{
if (dbEntity == null) return;
try
{
ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams;
procedureParamsEntity = dbEntity;
componentName = dbEntity.CmpntName;
procedure = dbEntity.Procedure;
if (tmp != null) tmp.CopyContentTo(this);
}
catch
{
}
}
/// <summary>
/// Parameterless constructor initializes the parameters
/// </summary>
public ProcParams()
{
}
public ProcParams(bool initialize)
{
if (initialize) InitializeAll();
}
public ProcParams(ComponentProcedure procParamsEntity, string componentName, Procedure procedure)
{
this.procedureParamsEntity = procParamsEntity;
this.componentName = componentName;
this.procedure = procedure;
}
}
}

View File

@ -0,0 +1,61 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.BenchControl.Modbus.Novus
{
public class ReadTempOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadTempOp));
public override string ToString() { return string.Format("ReadTempOp({0},.,{1})", novus.Name, eventDone); }
/// Set by the constructor
Novus novus;
Event eventDone;
DoubleBox temp;
/// <summary>
/// Events: TempInDone, TempOutDone, TempDivDone or Error
/// </summary>
/// <param name="easytherm">TempMeter reference</param>
/// <param name="temp">Reference to the variable, value is in degree Celsius</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadTempOp(Novus easytherm, ref DoubleBox temp, Event eventDone)
{
if (easytherm == null) throw new ArgumentNullException("easytherm");
this.novus = easytherm;
this.temp = temp;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public ReadTempOp(Novus tempMeter, ref DoubleBox temp)
: this(tempMeter, ref temp, Event.TempDone)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
temp.Val = novus.ReadTemperature();
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.TempInDone, Event.TempOutDone or Event.TempDivDone
/// </returns>
public Event Run()
{
temp.Val = novus.ReadTemperature();
return eventDone;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -0,0 +1,55 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.BenchControl.Modbus.Novus
{
public class SetRequiredTemperatureOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(SetRequiredTemperatureOp));
public override string ToString() { return string.Format("SetRequiredTemperatureOp({0})", eventDone); }
/// Set by the constructor
readonly Novus easytherm;
readonly Event eventDone;
/// <summary>
/// Events: PressureInDone, PressureOutDone or Error
/// </summary>
/// <param name="easytherm">Pressure meter reference</param>
/// <param name="pressure">Reference to the measured pressure variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public SetRequiredTemperatureOp(Novus easytherm, Event eventDone)
{
if (easytherm == null) throw new ArgumentNullException("easytherm");
this.easytherm = easytherm;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public SetRequiredTemperatureOp(Novus easytherm)
: this(easytherm, Event.ConditionMet)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
easytherm.SetTemperatureSetpoint();
}
/// <summary>Run this operation</summary>
public Event Run()
{
return eventDone;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -0,0 +1,57 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.BenchControl.Modbus.Novus
{
public class SetTemperatureOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(SetTemperatureOp));
public override string ToString() { return string.Format("SetTemperatureOp({0},{1})", temperatureSetpoint, eventDone); }
/// Set by the constructor
readonly Novus easytherm;
readonly Event eventDone;
float temperatureSetpoint;
/// <summary>
/// Events: PressureInDone, PressureOutDone or Error
/// </summary>
/// <param name="easytherm">Pressure meter reference</param>
/// <param name="pressure">Reference to the measured pressure variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public SetTemperatureOp(Novus easytherm, float temperatureSetpoint, Event eventDone)
{
if (easytherm == null) throw new ArgumentNullException("easytherm");
this.easytherm = easytherm;
this.temperatureSetpoint = temperatureSetpoint;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public SetTemperatureOp(Novus easytherm, float temperatureSetpoint)
: this(easytherm, temperatureSetpoint, Event.SetOutputsDone)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
easytherm.SetTemperatureSetpoint(temperatureSetpoint);
}
/// <summary>Run this operation</summary>
public Event Run()
{
return eventDone;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -119,7 +119,8 @@ namespace TBF.BenchControl
Factories.Add(new Modbus.CometAmbient.Factory()); /// Modbus.CometAmbient.Ambient
Factories.Add(new Modbus.Common.Factory()); /// Modbus
Factories.Add(new Modbus.Easytherm.Factory()); /// Modbus.Easytherm
Factories.Add(new Modbus.PressureMeter.Meret.Factory()); /// Modbus.PressureMeter.Meret - Meret pressure meter connected via modbus
Factories.Add(new Modbus.Novus.Factory()); /// Modbus.Novus
Factories.Add(new Modbus.PressureMeter.Meret.Factory()); /// Modbus.PressureMeter.Meret - Meret pressure meter connected via modbus
Factories.Add(new Modbus.QuidoRS.Factory()); /// Modbus.QuidoRS
Factories.Add(new Modbus.TankSelector.Factory()); /// Modbus.TankSelector
Factories.Add(new Modbus.UltrasoundLevelMeter.Factory());
@ -180,7 +181,8 @@ namespace TBF.BenchControl
Factories.Add(new RegisterReaders.KPackE.Radio.Factory()); /// Radio for KPackE register readers
Factories.Add(new Elde.RegulValve.RegulValveFactory());
Factories.Add(new Elde.RegulValveCoax.Factory());
Factories.Add(new Elde.RegulValveTandem.RegulValveTandemFactory());
Factories.Add(new Elde.RegulValveMilwaukee.Factory());
Factories.Add(new Elde.RegulValveTandem.RegulValveTandemFactory());
Factories.Add(new Elde.TempMeter.TempMeterFactory());
Factories.Add(new Elde.TempMeterInternal.TempMeterFactory());
Factories.Add(new Elde.TempMeterMeret.Factory()); /// Meret temp. meter connected to control board Modbus

View File

@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Sensus")]
[assembly: AssemblyProduct("TestBenchFramework")]
[assembly: AssemblyCopyright("Copyright © 2013 - 2020 Sensus Slovensko, a.s.")]
[assembly: AssemblyCopyright("Copyright © 2013 - 2021 Sensus Slovensko, a.s.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("2.26.1569.0")]
[assembly: AssemblyFileVersion("2.26.1569.0")]
[assembly: AssemblyVersion("2.26.1573.0")]
[assembly: AssemblyFileVersion("2.26.1573.0")]

View File

@ -653,6 +653,20 @@
<Compile Include="BenchControl\Elde\RegulValveCoax\Factory.cs" />
<Compile Include="BenchControl\Elde\RegulValveCoax\SetFlowOp.cs" />
<Compile Include="BenchControl\Elde\RegulValveCoax\SetRegulValvePositionOp.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\ChangeValvePositionOp.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\Handlers.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\RegulValve.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\RegulValveCfg.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\RegulValveCfgChangeArgs.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\RegulValveCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\RegulValveCfgCtrl.designer.cs">
<DependentUpon>RegulValveCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\Factory.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\SetFlowOp.cs" />
<Compile Include="BenchControl\Elde\RegulValveMilwaukee\SetRegulValvePositionOp.cs" />
<Compile Include="BenchControl\Elde\SendCommandArgs.cs" />
<Compile Include="BenchControl\Elde\SetValvesOp.cs" />
<Compile Include="BenchControl\Elde\StopFlowRegulationOp.cs" />
@ -806,6 +820,19 @@
<DependentUpon>ModbusCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="BenchControl\Modbus\Common\Factory.cs" />
<Compile Include="BenchControl\Modbus\Novus\Novus.cs" />
<Compile Include="BenchControl\Modbus\Novus\NovusCfg.cs" />
<Compile Include="BenchControl\Modbus\Novus\NovusCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="BenchControl\Modbus\Novus\NovusCfgCtrl.designer.cs">
<DependentUpon>NovusCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="BenchControl\Modbus\Novus\Factory.cs" />
<Compile Include="BenchControl\Modbus\Novus\ProcParams.cs" />
<Compile Include="BenchControl\Modbus\Novus\ReadTempOp.cs" />
<Compile Include="BenchControl\Modbus\Novus\SetRequiredTemperatureOp.cs" />
<Compile Include="BenchControl\Modbus\Novus\SetTemperatureOp.cs" />
<Compile Include="BenchControl\Modbus\PressureMeter\Meret\Factory.cs" />
<Compile Include="BenchControl\Modbus\PressureMeter\Meret\PressureMeter.cs" />
<Compile Include="BenchControl\Modbus\PressureMeter\Meret\PressureMeterCfg.cs" />
@ -2940,6 +2967,9 @@
<EmbeddedResource Include="BenchControl\Elde\RegulValveCoax\RegulValveCfgCtrl.resx">
<DependentUpon>RegulValveCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Elde\RegulValveMilwaukee\RegulValveCfgCtrl.resx">
<DependentUpon>RegulValveCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Elde\RegulValveTandem\RegulValveTandemCfgCtrl.resx">
<DependentUpon>RegulValveTandemCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@ -2979,6 +3009,9 @@
<EmbeddedResource Include="BenchControl\Modbus\Easytherm\EasythermCfgCtrl.resx">
<DependentUpon>EasythermCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Modbus\Novus\NovusCfgCtrl.resx">
<DependentUpon>NovusCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Modbus\PressureMeter\Meret\PressureMeterCfgCtrl.resx">
<DependentUpon>PressureMeterCfgCtrl.cs</DependentUpon>
</EmbeddedResource>

View File

@ -317,6 +317,7 @@ namespace TBF.UI.Procedures
{
if (cmpnt is TBF.BenchControl.Output.DB.SensusOracle.Database) other.Add(cmpnt);
if (cmpnt is TBF.BenchControl.Modbus.Easytherm.Easytherm) other.Add(cmpnt);
if (cmpnt is TBF.BenchControl.Modbus.Novus.Novus) other.Add(cmpnt);
}
if (other.Count > 0)