Elde.RegulValveCoax component added, coax support in Elde.RegulValve dropped, ver. 2.15.631

This commit is contained in:
Milan Hanajik 2017-07-27 10:09:06 +03:00
parent 1cb0345b37
commit 62cb5cdba7
14 changed files with 1539 additions and 9 deletions

View File

@ -15,9 +15,6 @@ namespace TBF.BenchControl.Elde.RegulValve
public override string ToString() { return string.Format("RegulValve({0})", Cfg.ToString(1)); }
const int COAX_IDX = 7; /// COAX has always Idx1 = 7
public readonly RegulValveCfg RegulValveCfg;
IDictionary<float, float> dict;
@ -32,7 +29,7 @@ namespace TBF.BenchControl.Elde.RegulValve
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 (Idx1 == COAX_IDX); } }
public bool IsCoax { get { return false; } }
///
public float Position { get { return ControlBoard.RValvePosition(Idx1); } }
@ -98,7 +95,7 @@ namespace TBF.BenchControl.Elde.RegulValve
this.dict = new Dictionary<float, float>();
if (Idx1 != COAX_IDX && Idx1 < ControlBoard.RegValveCalib.GetLength(0))
if (Idx1 < ControlBoard.RegValveCalib.GetLength(0))
{
this.ControlBoard.RegValveCalib[Idx1 - 1, 0] = (uint)DacValueClosed;
this.ControlBoard.RegValveCalib[Idx1 - 1, 1] = (uint)DacValueOpen;

View File

@ -99,8 +99,7 @@ namespace TBF.BenchControl.Elde.RegulValve
{
if (opState == OpState.MoveToPosition)
{
if (posLoPct > posHiPct || (!regulValve.IsCoax && posLoPct == posHiPct) ||
posLoPct > 100.0f || posHiPct < 0)
if (posLoPct >= posHiPct || posLoPct > 100.0f || posHiPct < 0)
{
return Event.OpArgumentError;
}

View File

@ -0,0 +1,78 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
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);
}
/// <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) 2017 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
public class Factory : IComponentFactory
{
public string ClassName { get { return "RegulationValve-Coax"; } }
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,100 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Boxes;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
public class RegulValve : ComponentBase, 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<float, float> dict;
public IDictionary<float, 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 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 true; } }
///
public float Position { get { return ControlBoard.RValvePosition(Idx1); } }
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<float, float>();
log.Debug(this.ToString());
}
/// <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, float requiredFlowLo, float requiredFlowHi, float pidCoef, DoubleBox measuredFlow, int timeout)
{
return new SetFlowOp(ControlBoard, this, flowMeter, requiredFlowLo, requiredFlowHi, pidCoef, 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, float requiredFlowLo, float requiredFlowHi, float pidCoef, DoubleBox measuredFlow, int timeout, float filterConstant)
{
return new SetFlowOp(ControlBoard, this, flowMeter, requiredFlowLo, requiredFlowHi, pidCoef, 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,66 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
public class RegulValveCfg : ComponentCfgBase, IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(RegulValveCfg) })[0];
protected override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new RegulValveCfgCtrl(); }
///
/// Serialized parameters
///
public int Idx1; /// 1..8
public ValveCategory Category; /// Feeding, Output or All
public int StableTimeMs; /// 200..1500 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;
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,
StableTimeMs,
FlowStableSec,
StoredPositionReuse,
ReTryCommands);
}
}
}

View File

@ -0,0 +1,271 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
namespace TBF.BenchControl.Elde.RegulValveCoax
{
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.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.groupBox3 = new System.Windows.Forms.GroupBox();
this.closeButton = new System.Windows.Forms.Button();
this.openButton = new System.Windows.Forms.Button();
this.categoryComboBox = new System.Windows.Forms.ComboBox();
this.categoryLabel = new System.Windows.Forms.Label();
this.reTryCommandsCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// positionTextBox
//
this.positionTextBox.Enabled = false;
this.positionTextBox.Location = new System.Drawing.Point(138, 115);
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, 118);
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";
//
// 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, 192);
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, 139);
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, 142);
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, 163);
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, 166);
this.flowStableSecLabel.Name = "flowStableSecLabel";
this.flowStableSecLabel.Size = new System.Drawing.Size(74, 13);
this.flowStableSecLabel.TabIndex = 15;
this.flowStableSecLabel.Text = "Flow stable [s]";
//
// 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);
//
// 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, 215);
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.groupBox3);
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.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.groupBox3.ResumeLayout(false);
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.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 groupBox3;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.Button openButton;
private System.Windows.Forms.ComboBox categoryComboBox;
private System.Windows.Forms.Label categoryLabel;
private System.Windows.Forms.CheckBox reTryCommandsCheckBox;
}
}

View File

@ -0,0 +1,208 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using log4net;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
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.All.ToString());
categoryComboBox.Items.Add(ValveCategory.Feeding.ToString());
categoryComboBox.Items.Add(ValveCategory.Output.ToString());
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
categoryComboBox.Text = config.Category.ToString();
positionTextBox.Text = config.Idx1.ToString();
stableTimeTextBox.Text = config.StableTimeMs.ToString();
flowStableSecTextBox.Text = config.FlowStableSec.ToString();
storedPosReuseCheckBox.Checked = config.StoredPositionReuse;
reTryCommandsCheckBox.Checked = config.ReTryCommands;
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
categoryComboBox.Enabled = true;
positionTextBox.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.All.ToString()) &&
!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(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.All.ToString())) newCategory = ValveCategory.All;
else if (categoryComboBox.Text.Equals(ValveCategory.Feeding.ToString())) newCategory = ValveCategory.Feeding;
else if (categoryComboBox.Text.Equals(ValveCategory.Bench.ToString())) newCategory = ValveCategory.Bench;
else if (categoryComboBox.Text.Equals(ValveCategory.Output.ToString())) newCategory = ValveCategory.Output;
else newCategory = ValveCategory.None;
if (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(stableTimeTextBox.Text);
if (config.StableTimeMs != tmp)
{
config.StableTimeMs = tmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
tmp = int.Parse(flowStableSecTextBox.Text);
if (config.FlowStableSec != tmp)
{
config.FlowStableSec = tmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
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;
}
return flags;
}
private void openButton_Click(object sender, EventArgs e)
{
/// TODO
}
private void closeButton_Click(object sender, EventArgs e)
{
/// TODO
}
}
}

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,483 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
using TBF.Boxes;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
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}, PID={3})", regulValve.Name, reqFlowLo, reqFlowHi, pidCoef);
}
const int CoaxValveNr = 7; /// Coax. valve has number 7
/// Set by the constructor
readonly ControlBoardDev controlBoard;
readonly Elde.RegulValve.RegulValve regulValve;
readonly int regulValveNr;
readonly int flowMeterNr;
readonly float reqFlowLo;
readonly float reqFlowHi;
readonly float reqFlowAve;
readonly float pidCoef;
readonly int timeout;
readonly bool leaveMeasurementRunning;
readonly bool reTryCommands;
readonly float nominalFlow;
///
/// 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;
float targetPositionLo;
float targetPositionHi;
int expireTime;
DoubleBox measuredFlow;
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,
float requiredFlowLo, float requiredFlowHi, float pidCoef, DoubleBox measuredFlow,
bool reTryCmds, int timeout, bool leaveMeasurementRunning)
{
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.controlBoard = controlBoard;
regulValve = _regulValve as Elde.RegulValve.RegulValve;
if (regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
regulValveNr = this.regulValve.Idx1;
if (flowMeter is Elde.FlowMeter.FlowMeter)
{
this.flowMeterNr = (flowMeter as Elde.FlowMeter.FlowMeter).Idx1;
}
else if (flowMeter is Elde.FlowMeterTwins.FlowMeter)
{
this.flowMeterNr = 0;
}
else
{
throw new ArgumentNullException("flowMeter is null or not Elde");
}
nominalFlow = flowMeter.NominalFlow;
this.reqFlowLo = requiredFlowLo;
this.reqFlowHi = requiredFlowHi;
this.reqFlowAve = (reqFlowLo + reqFlowHi) / 2.0f;
this.pidCoef = pidCoef;
this.measuredFlow = measuredFlow;
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,
float requiredFlowLo, float requiredFlowHi, float pidCoef, DoubleBox measuredFlow, bool reTryCmds, int timeout)
: this(controlBoard, regValve, flowMeter, requiredFlowLo, requiredFlowHi, pidCoef, measuredFlow, reTryCmds, timeout, false)
{
}
/// <summary>
/// Set required water flow - No timeout.
/// Events: FlowSet
/// </summary>
public SetFlowOp(ControlBoardDev controlBoard, IRegulValve regValve, IFlowMeter flowMeter,
float requiredFlowLo, float requiredFlowHi, float pidCoef, DoubleBox measuredFlow, bool reTryCmds)
: this(controlBoard, regValve, flowMeter, requiredFlowLo, pidCoef, requiredFlowHi, measuredFlow, 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(float 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(float avgReqFlow, float actPosition)
{
if (!regulValve.Dict.ContainsKey(reqFlowAve))
{
regulValve.Dict.Add(new KeyValuePair<float, float>(avgReqFlow, actPosition));
}
return;
}
/// <summary>Start this operation</summary>
public void Start()
{
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, flowMeterNr, reqFlowLo, reqFlowHi, targetPositionLo, targetPositionHi);
opState = OpState.ValveMoveToPosition1;
}
else
{
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeterNr, reqFlowLo, reqFlowHi);
opState = OpState.ValveMoveToFlow1;
}
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
TestMethods tm = 0;
StopDevs sd = 0;
// '_regulValve.RegulValveCfg.PidCoef' replaced by a casted operation parameter 'pidCoef'
controlBoard.SendCommand(Command.Start, flowMeterNr, controlBoard.Route,
int.MaxValue, int.MaxValue, tm,
0.0f, (int)pidCoef, 0, sd);
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.None, Event.FlowReached, Event.RegulValveTimeOut, Event.OpArgumentError
/// </returns>
public Event Run()
{
float rvPosition = controlBoard.RValvePosition(regulValveNr);
double flowMtrFreq = controlBoard.ReferenceFreq;
double flow = flowMtrFreq * nominalFlow / 2000.0;
if (flowMtrFreq != 0)
{
if (measuredFlow != null) measuredFlow.Val = flow;
}
log.InfoFormat("SetFlowOp:Run() rv#={0} pos={1}% freq={2} flow={3} opState={4}",
regulValveNr, rvPosition.ToString("F1"), flowMtrFreq, flow, opState);
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, flowMeterNr, reqFlowLo, reqFlowHi, targetPositionLo, targetPositionHi);
opState = OpState.ValveMoveToPosition1;
}
else
{
log.InfoFormat("Run(): rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeterNr, reqFlowLo, reqFlowHi);
opState = OpState.ValveMoveToFlow1;
}
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
TestMethods tm = 0;
StopDevs sd = 0;
// '_regulValve.RegulValveCfg.PidCoef' replaced by a casted operation parameter 'pidCoef'
controlBoard.SendCommand(Command.Start, flowMeterNr, controlBoard.Route,
int.MaxValue, int.MaxValue, tm,
0.0f, (int)pidCoef, 0, sd);
return Event.None;
}
else if (opState == OpState.ValveMoveToPosition1)
{
opState = OpState.ValveMoveToPosition2;
return Event.None;
}
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);
opState = OpState.SettingPosition;
return Event.None;
}
else if (opState == OpState.ValveMoveToPosition3)
{
if (reTryCommands)
{
opState = OpState.CheckStatePosition;
}
else
{
opState = OpState.SettingPosition;
}
return Event.None;
}
else if (opState == OpState.CheckStatePosition) /// Verify
{
if (((ulong)controlBoard.StatusP & (ulong)StatusP.RefPulsesMsrmnt) == 0)
{
opState = OpState.SendCommandAgain;
return Event.None;
}
else if (regulValveNr == CoaxValveNr && ((ulong)controlBoard.StatusP & (ulong)StatusP.CoaxRegValveBusy) == 0)
{
/// Repeat appropriate ValveMove(...) command
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetPosition,
new float[2] { (targetPositionLo + targetPositionHi) / 2, (targetPositionLo + targetPositionHi) / 2 },
regulValve.StableTime);
log.InfoFormat("SetFlowOp: ValveMove({0}, Position, {1}, {2}, {3})",
regulValveNr, (targetPositionLo + targetPositionHi) / 2, (targetPositionLo + targetPositionHi) / 2, regulValve.StableTime);
opState = OpState.ValveMoveToPosition3;
return Event.None;
}
else if (regulValveNr < 6 && controlBoard.RegulValveState(regulValveNr) != RegulValveState.DacValueRegul)
{
/// Repeat appropriate ValveMove(...) command
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetPosition,
new float[2] { targetPositionLo, targetPositionHi },
regulValve.StableTime);
log.InfoFormat("SetFlowOp: ValveMove({0}, Position, {1}, {2}, {3})",
regulValveNr, targetPositionLo, targetPositionHi, regulValve.StableTime);
opState = OpState.ValveMoveToPosition3;
return Event.None;
}
else
{
opState = OpState.SettingPosition;
return Event.None;
}
}
else if (opState == OpState.SettingPosition)
{
/// Repeated untill position is reached
if ((targetPositionLo <= rvPosition) && (rvPosition <= targetPositionHi))
{
opState = OpState.ValveMoveToFlow1;
}
return Event.None;
}
else if (opState == OpState.ValveMoveToFlow1)
{
opState = OpState.ValveMoveToFlow2;
return Event.None;
}
else if (opState == OpState.ValveMoveToFlow2) /// Move to flow
{
///
/// Done once, issues an appropriate ValveMove(...) command
///
if (reqFlowLo >= reqFlowHi || reqFlowLo > nominalFlow || reqFlowHi <= 0)
{
return Event.OpArgumentError;
}
log.InfoFormat("Run(): rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeterNr, reqFlowLo, reqFlowHi);
float freqLo = 2000.0f * reqFlowLo / nominalFlow;
float freqHi = 2000.0f * reqFlowHi / nominalFlow;
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { freqLo, freqHi },
regulValve.StableTime);
opState = OpState.ValveMoveToFlow3;
return Event.None;
}
else if (opState == OpState.ValveMoveToFlow3)
{
if (reTryCommands)
{
opState = OpState.CheckStateFlow;
}
else
{
opState = OpState.SettingFlow;
}
return Event.None;
}
else if (opState == OpState.CheckStateFlow) /// Verify the flow setting
{
if (regulValveNr != CoaxValveNr && (((ulong)controlBoard.StatusP & (ulong)StatusP.RefPulsesMsrmnt) == 0 ||
(controlBoard.RegulValveState(regulValveNr) & RegulValveState.PwOrFreqRegul) != RegulValveState.PwOrFreqRegul))
{
opState = OpState.SendCommandAgain;
return Event.None;
}
else if (regulValveNr == CoaxValveNr && ((ulong)controlBoard.StatusP & (ulong)StatusP.CoaxRegValveBusy) == 0)
{
/// Done once, issues an appropriate ValveMove(...) command
float freqLo = 2000.0f * reqFlowLo / nominalFlow;
float freqHi = 2000.0f * reqFlowHi / nominalFlow;
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { (freqLo + freqHi) / 2.0f, (freqLo + freqHi) / 2.0f },
regulValve.StableTime);
log.InfoFormat("SetFlowOp: ValveMove({0}, Frequency, {1}, {2}, {3})",
regulValveNr, (freqLo + freqHi) / 2.0f, (freqLo + freqHi) / 2.0f, regulValve.StableTime);
opState = OpState.ValveMoveToFlow3;
return Event.None;
}
else if (regulValveNr < 6 && controlBoard.RegulValveState(regulValveNr) != RegulValveState.PwOrFreqRegul)
{
/// Done once, issues an appropriate ValveMove(...) command
float freqLo = 2000.0f * reqFlowLo / nominalFlow;
float freqHi = 2000.0f * reqFlowHi / nominalFlow;
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new float[2] { freqLo, freqHi },
regulValve.StableTime);
log.InfoFormat("SetFlowOp: ValveMove({0}, Frequency, {1}, {2}, {3})",
regulValveNr, freqLo, freqHi, regulValve.StableTime);
opState = OpState.ValveMoveToFlow3;
return Event.None;
}
else
{
opState = OpState.SettingFlow;
return Event.None;
}
}
else if (opState == OpState.SettingFlow)
{
///
/// Repeated untill the required flow is reached
///
if ((reqFlowLo <= flow) && (flow <= reqFlowHi))
{
if (flowWithinBoundsTime++ >= regulValve.FlowStableSec)
{
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, reqFlowLo, reqFlowHi);
opState = OpState.FlowReached;
return Event.FlowReached;
}
else
{
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, FLOW_OK_TIMER={3}s)", flow, reqFlowLo, reqFlowHi, flowWithinBoundsTime);
return Event.None;
}
}
else if (StateMachine.Time > expireTime)
{
return Event.RegulValveTimeOut;
}
else
{
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2})", flow, reqFlowLo, reqFlowHi);
flowWithinBoundsTime = 0;
return Event.None;
}
}
else /// opState == OpState.FlowReached
{
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, REACHED)", flow, reqFlowLo, reqFlowHi);
return Event.FlowReached;
}
}
/// <summary>Start this operation</summary>
public void Stop()
{
opState = OpState.Idle;
if (leaveMeasurementRunning) return;
/// Stop measurement
TestMethods tm = 0;
StopDevs sd = StopDevs.RegValveRegulation;
controlBoard.SendCommand(Command.Stop, flowMeterNr, controlBoard.Route,
50000, 50000, tm,
0.0f, (int)pidCoef, 0, sd);
}
}
}

View File

@ -0,0 +1,166 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
namespace TBF.BenchControl.Elde.RegulValveCoax
{
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);
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

@ -111,6 +111,7 @@ namespace TBF.BenchControl
Factories.Add(new Elde.FixedStartRegisterReader.RegisterReaderFactory());
Factories.Add(new TestMethods.iPerlCommunication.iPerlHead.Factory()); /// iPerl head
Factories.Add(new Elde.RegulValve.RegulValveFactory());
Factories.Add(new Elde.RegulValveCoax.Factory());
Factories.Add(new Elde.RegulValveTandem.RegulValveTandemFactory());
Factories.Add(new ResultsPrinters.Cevak.PrinterFactory());
Factories.Add(new ResultsPrinters.Munich.PrinterFactory());

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("2.15.630.1")]
[assembly: AssemblyFileVersion("2.15.630.1")]
[assembly: AssemblyVersion("2.15.631.1")]
[assembly: AssemblyFileVersion("2.15.631.1")]

View File

@ -440,6 +440,18 @@
<Compile Include="BenchControl\Elde\PressureMeterInternal\PressureMeterFactory.cs" />
<Compile Include="BenchControl\Elde\PressureMeterInternal\ReadPressureOp.cs" />
<Compile Include="BenchControl\Elde\ExecuteCommandOp.cs" />
<Compile Include="BenchControl\Elde\RegulValveCoax\ChangeValvePositionOp.cs" />
<Compile Include="BenchControl\Elde\RegulValveCoax\RegulValve.cs" />
<Compile Include="BenchControl\Elde\RegulValveCoax\RegulValveCfg.cs" />
<Compile Include="BenchControl\Elde\RegulValveCoax\RegulValveCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="BenchControl\Elde\RegulValveCoax\RegulValveCfgCtrl.designer.cs">
<DependentUpon>RegulValveCfgCtrl.cs</DependentUpon>
</Compile>
<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\SetValvesOp.cs" />
<Compile Include="BenchControl\Elde\TempMeterInternal\ReadTempOp.cs" />
<Compile Include="BenchControl\Elde\TempMeterInternal\TempMeter.cs" />
@ -1957,6 +1969,9 @@
<EmbeddedResource Include="BenchControl\Elde\RegisterReader\RegisterReaderCfgCtrl.resx">
<DependentUpon>RegisterReaderCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Elde\RegulValveCoax\RegulValveCfgCtrl.resx">
<DependentUpon>RegulValveCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Elde\RegulValveTandem\RegulValveTandemCfgCtrl.resx">
<DependentUpon>RegulValveTandemCfgCtrl.cs</DependentUpon>
</EmbeddedResource>