Refactorization : BenchControl -> Rig

This commit is contained in:
Milan Hanajik
2021-03-05 16:12:24 +01:00
parent 84c8ec26b6
commit 6cf3bd6160
1461 changed files with 6330 additions and 6330 deletions
+203
View File
@@ -0,0 +1,203 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
namespace TBF.Rig.ControlBoard.Papouch
{
partial class CBoardCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.classNameLabel = new System.Windows.Forms.Label();
this.nameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeLoTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeLoLabel = new System.Windows.Forms.Label();
this.vValveRangeHiTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeHiLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.modbusAddressTextBox = new System.Windows.Forms.TextBox();
this.modbusAddressLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.variantComboBox = new System.Windows.Forms.ComboBox();
this.variantLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(175, 26);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 2;
this.classNameLabel.Text = "ComonentName";
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(42, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 3;
this.nameLabel.Text = "Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(178, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 4;
//
// vValveRangeLoTextBox
//
this.vValveRangeLoTextBox.Enabled = false;
this.vValveRangeLoTextBox.Location = new System.Drawing.Point(178, 161);
this.vValveRangeLoTextBox.Name = "vValveRangeLoTextBox";
this.vValveRangeLoTextBox.Size = new System.Drawing.Size(46, 20);
this.vValveRangeLoTextBox.TabIndex = 6;
//
// vValveRangeLoLabel
//
this.vValveRangeLoLabel.AutoSize = true;
this.vValveRangeLoLabel.Location = new System.Drawing.Point(42, 164);
this.vValveRangeLoLabel.Name = "vValveRangeLoLabel";
this.vValveRangeLoLabel.Size = new System.Drawing.Size(118, 13);
this.vValveRangeLoLabel.TabIndex = 5;
this.vValveRangeLoLabel.Text = "Virtual valves range Lo:";
//
// vValveRangeHiTextBox
//
this.vValveRangeHiTextBox.Enabled = false;
this.vValveRangeHiTextBox.Location = new System.Drawing.Point(178, 186);
this.vValveRangeHiTextBox.Name = "vValveRangeHiTextBox";
this.vValveRangeHiTextBox.Size = new System.Drawing.Size(46, 20);
this.vValveRangeHiTextBox.TabIndex = 8;
//
// vValveRangeHiLabel
//
this.vValveRangeHiLabel.AutoSize = true;
this.vValveRangeHiLabel.Location = new System.Drawing.Point(42, 189);
this.vValveRangeHiLabel.Name = "vValveRangeHiLabel";
this.vValveRangeHiLabel.Size = new System.Drawing.Size(116, 13);
this.vValveRangeHiLabel.TabIndex = 7;
this.vValveRangeHiLabel.Text = "Virtual valves range Hi:";
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(178, 83);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 10;
//
// modbusAddressTextBox
//
this.modbusAddressTextBox.Enabled = false;
this.modbusAddressTextBox.Location = new System.Drawing.Point(178, 136);
this.modbusAddressTextBox.Name = "modbusAddressTextBox";
this.modbusAddressTextBox.Size = new System.Drawing.Size(46, 20);
this.modbusAddressTextBox.TabIndex = 12;
//
// modbusAddressLabel
//
this.modbusAddressLabel.AutoSize = true;
this.modbusAddressLabel.Location = new System.Drawing.Point(42, 140);
this.modbusAddressLabel.Name = "modbusAddressLabel";
this.modbusAddressLabel.Size = new System.Drawing.Size(86, 13);
this.modbusAddressLabel.TabIndex = 11;
this.modbusAddressLabel.Text = "Modbus Address";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(42, 86);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
this.parentNameLabel.TabIndex = 9;
this.parentNameLabel.Text = "Parent Name";
//
// variantComboBox
//
this.variantComboBox.Enabled = false;
this.variantComboBox.FormattingEnabled = true;
this.variantComboBox.Location = new System.Drawing.Point(178, 110);
this.variantComboBox.Name = "variantComboBox";
this.variantComboBox.Size = new System.Drawing.Size(130, 21);
this.variantComboBox.TabIndex = 14;
//
// variantLabel
//
this.variantLabel.AutoSize = true;
this.variantLabel.Location = new System.Drawing.Point(42, 113);
this.variantLabel.Name = "variantLabel";
this.variantLabel.Size = new System.Drawing.Size(40, 13);
this.variantLabel.TabIndex = 13;
this.variantLabel.Text = "Variant";
//
// CBoardCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.variantComboBox);
this.Controls.Add(this.variantLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.modbusAddressTextBox);
this.Controls.Add(this.modbusAddressLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.vValveRangeHiTextBox);
this.Controls.Add(this.vValveRangeHiLabel);
this.Controls.Add(this.vValveRangeLoTextBox);
this.Controls.Add(this.vValveRangeLoLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "CBoardCfgCtrl";
this.Size = new System.Drawing.Size(400, 300);
this.Load += new System.EventHandler(this.ControlBoardCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.TextBox vValveRangeLoTextBox;
private System.Windows.Forms.Label vValveRangeLoLabel;
private System.Windows.Forms.TextBox vValveRangeHiTextBox;
private System.Windows.Forms.Label vValveRangeHiLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.TextBox modbusAddressTextBox;
private System.Windows.Forms.Label modbusAddressLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.ComboBox variantComboBox;
private System.Windows.Forms.Label variantLabel;
}
}
@@ -0,0 +1,143 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.ControlBoard.Papouch
{
public partial class CBoardCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
PapouchCBCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as PapouchCBCfg;
Redraw();
}
}
public CBoardCfgCtrl()
{
InitializeComponent();
}
private void ControlBoardCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.Common.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
for (QuidoVariant v = 0; v < QuidoVariant.Count; v++) variantComboBox.Items.Add(v.ToString());
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
variantComboBox.Text = config.Variant.ToString();
modbusAddressTextBox.Text = config.ModbusAddress.ToString();
vValveRangeLoTextBox.Text = config.VirtualValvesRangeLo.ToString();
vValveRangeHiTextBox.Text = config.VirtualValvesRangeHi.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
variantComboBox.Enabled = true;
modbusAddressTextBox.Enabled = true;
vValveRangeLoTextBox.Enabled = true;
vValveRangeHiTextBox.Enabled = true;
}
/// <summary>
/// Verify current user controls for validity.
/// Called when user wants to close/save the configuration.
/// </summary>
/// <returns>See VerifyFlags</returns>
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!variantComboBox.Items.Contains(variantComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Variant'";
}
if (!int.TryParse(modbusAddressTextBox.Text, out dummy) || dummy < 0 || dummy > 255)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Modbus Address' should be between 0 and 255";
}
if (!int.TryParse(vValveRangeLoTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
{
message += "Virtual valves range Lo is invalid";
flags |= CfgUpdateFlags.Error;
}
if (!int.TryParse(vValveRangeHiTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
{
message += "Virtual valves range Hi is invalid";
flags |= CfgUpdateFlags.Error;
}
return flags;
}
/// <summary>
/// Save settings to the configuration class.
/// </summary>
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
this.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
for (QuidoVariant v = 0; v < QuidoVariant.Count; v++)
{
if (variantComboBox.Text == v.ToString()) { config.Variant = v; break; }
}
config.ModbusAddress = (byte)int.Parse(modbusAddressTextBox.Text);
config.VirtualValvesRangeLo = int.Parse(vValveRangeLoTextBox.Text);
config.VirtualValvesRangeHi = int.Parse(vValveRangeHiTextBox.Text);
return flags;
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+30
View File
@@ -0,0 +1,30 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Papouch
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { PapouchCB.ResetStaticProperties(); }
/// <summary>Max. number of components of this class in the system</summary>
public int MaxCount { get { return 1; } }
public IComponent DummyComponent() { return new PapouchCB(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new PapouchCB(cfg, components); }
public IComponentCfg DefaultConfig() { return new PapouchCBCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(PapouchCBCfg.Serializer, component, this);
}
}
}
+489
View File
@@ -0,0 +1,489 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using log4net;
using Config.Entities;
using Dirichlet.Numerics;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.Modbus;
using TBF.Rig.Sequences;
namespace TBF.Rig.ControlBoard.Papouch
{
public class PapouchCB : ComponentBase, IControlBoard, IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(PapouchCB));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly PapouchCBCfg cbCfg;
readonly GenericDevices.IModbus modbus;
UInt32 currentOutputs;
bool outputsInitialized;
DateTime lastOutputsChange;
int lastStateMachineTime = 0;
///
UInt128 benchModelRoute;
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
readonly UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor
///
OutputPath devices;
enum SelectedOp
{
None,
SetFlow,
QueryMeasurementEnd,
}
SelectedOp scheduledOp;
SelectedOp runningOp;
///
bool opCompleted; /// true = Operation was completed and waits for Stop();
public PapouchCB()
{
}
/// <summary>
/// Constructor
/// </summary>
public PapouchCB(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
cbCfg = cfg as PapouchCBCfg;
modbus = (GenericDevices.IModbus)TbfComponents.FindComponent(cfg.ParentName, components);
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
routeMask = 0;
for (int i = 0; i < 128; i++)
{
if (i < cbCfg.VirtualValvesRangeLo || i > cbCfg.VirtualValvesRangeHi)
{
routeMask = routeMask | ((UInt128)1 << i);
}
}
TBF.UiBridge.Bridge.RouteChangeHandler += delegate(object sndr, TBF.UiBridge.RouteChangeArgs args)
{
UInt128 mask = ((UInt128)1) << args.BitNr;
if ((benchModelRoute & mask) == 0)
{
benchModelRoute |= mask;
}
else
{
benchModelRoute &= (~mask);
}
};
log.Warn(this.ToString());
}
public void SpecifyInvertedValves(UInt128 valvesToInvert)
{
this.valvesToInvert = valvesToInvert;
this.benchModelRoute = valvesToInvert;
}
///
/// IDevice interface
///
public void Initialize()
{
outputsInitialized = false;
runningOp = SelectedOp.None;
}
public void RunDeviceBefore()
{
if (cbCfg.DebugLevel == Config.Entities.DebugMode.Simulate) return;
if (modbus.ReceivedTelegrams[cbCfg.ModbusAddress].Count > 0)
{
byte[] telegram = modbus.ReceivedTelegrams[cbCfg.ModbusAddress].Dequeue();
if ((telegram.Length >= 8) && (telegram[1] == 0x11) && (telegram[2] == telegram.Length - 5))
{
int msgLen = telegram.Length - 7;
byte modbusAddress = telegram[3];
string msg = Encoding.ASCII.GetString(telegram, 5, msgLen);
string s = string.Format("QuidoRS detected: Address={0}, Message={1}", modbusAddress, msg);
Debug.WriteLine(s);
log.Warn(s);
}
if ((telegram.Length == 6) && (telegram[1] == 0x02) && (telegram[2] == telegram.Length - 5))
{
int inputData = telegram[3];
string s = string.Format("QuidoRS inputs: {0}", inputData);
Debug.WriteLine(s);
log.Warn(s);
}
}
}
public void RunDeviceAfter()
{
if (currentOutputs != (UInt32)(benchModelRoute & 0xFFFFFFFF) || !outputsInitialized || (StateMachine.Time - lastStateMachineTime) >= 3)
{
SetOutputs((UInt32)(benchModelRoute & 0xFFFFFFFF));
}
else
{
RequestInputs();
}
ProcessData.UpdateMeasuredValuesAndSetpoints();
TBF.UiBridge.Bridge.OnStateMachineTick(this, new TBF.UiBridge.StateMachineTickEventArgs(benchModelRoute,
ProcessData.MsrmntAvailableFlags,
ProcessData.MeasuredValues,
ProcessData.AltStrings,
ProcessData.Setpoints));
}
public void StopDevice()
{
SendOutputs(0);
}
public void StopDevice2() { }
/// <summary>
/// Set outputs of QuidoRS board
/// </summary>
/// <param name="outputs">output value</param>
public void SetOutputs(UInt32 outputs)
{
lock (this)
{
currentOutputs = outputs;
}
SendOutputs(currentOutputs);
}
/// <summary>
/// Set bit(s) specified by a bitMask. Leave other bits unaffeced.
/// </summary>
/// <param name="bitMask">Specifies bit(s) to set</param>
/// <param name="outputs">output value</param>
public void SetBit(UInt32 bitMask)
{
lock (this)
{
currentOutputs = currentOutputs | bitMask;
}
SendOutputs(currentOutputs);
}
/// <summary>
/// Reset bit(s) specified by a bitMask. Leave other bits unaffeced.
/// </summary>
/// <param name="bitMask">Specifies bit(s) to reset</param>
/// <param name="outputs">output value</param>
public void ResetBit(UInt32 bitMask)
{
lock (this)
{
currentOutputs = currentOutputs & (~bitMask);
}
SendOutputs(currentOutputs);
}
private void RequestInputs()
{
byte addr = cbCfg.ModbusAddress;
byte cmd = (byte)Function.ReadSingleInput;
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 2, 0, 0 });
}
private void SendOutputs(UInt32 outputs)
{
byte addr = cbCfg.ModbusAddress;
byte cmd = (byte)Function.ForceMultipleCoils;
byte dataLo = (byte)(outputs & 0xFF);
byte data2 = (byte)(outputs >> 8);
byte data3 = (byte)(outputs >> 16);
byte dataHi = (byte)(outputs >> 24);
if (cbCfg.Variant == QuidoVariant.QuidoRS_4_4)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 4, 1, dataLo, 0, 0 });
}
else if (cbCfg.Variant == QuidoVariant.QuidoRS_8_8)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 8, 1, dataLo, 0, 0 });
}
else if (cbCfg.Variant == QuidoVariant.QuidoRS_2_16)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 16, 2, dataLo, data2, 0, 0 });
}
else if (cbCfg.Variant == QuidoVariant.QuidoRS_2_32)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 32, 4, dataLo, data2, data3, dataHi, 0, 0 });
}
outputsInitialized = true;
lastOutputsChange = DateTime.Now;
lastStateMachineTime = StateMachine.Time;
}
///
/// IControlBoard interface
///
public OutputPath Devices
{
set { devices = value; }
get { return devices; }
}
/// <summary>
/// Route: 128-bit word representing the current state of all valves and pumps
/// </summary>
public UInt128 Route { get { return benchModelRoute; } }
public UInt64 DigitalInputs { get { return 0; } }
public double RefFrequency { get { return 0; } }
public double RefFlow { get { return 0; } }
///
/// Last test result
///
public int RefPulses { get { return 0; } }
public double TestTime { get { return 1.0; } }
public int RefPulsesWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? 0 : 0; }
public int PulsesWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? 0 : 0; }
public double TestTimeWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? 1.0 : 1.0; }
public void ClearProcessValues() { }
/// <summary>
/// Set valves to new positions.
/// </summary>
/// <param name="valvesToOpen">'UInt128' with bits of valves to open set to '1'</param>
/// <param name="valvesToClose">'UInt128' with bits of valves to close set to '1'</param>
/// <returns>'UInt128' with bits of valves that have changed set to '1'</returns>
public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList<BuiltIn.ValveEx.Valve> extendedValves)
{
UInt128 oldRoute = benchModelRoute;
benchModelRoute = (((benchModelRoute ^ valvesToInvert) | valvesToOpen) & (~valvesToClose)) ^ valvesToInvert;
foreach (var extV in extendedValves) extV.UpdateRoute(ref benchModelRoute);
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute));
UInt128 retVal = oldRoute ^ benchModelRoute;
log.DebugFormat("{0}.SetValves({1}, {2}) returns {3}", Name, valvesToOpen.ToString("X"), valvesToClose.ToString("X"), retVal.ToString("X"));
return retVal;
}
/// <summary>
/// Open one valve and/or close one valve.
/// Events: ValvesSet
/// </summary>
/// <param name="valveOpen">Valve to be opened</param>
/// <param name="valveClose">Valve to be closed</param>
/// <returns>Created operation</returns>
public IOperation SetValvesOp(IValve valveOpen, IValve valveClose)
{
IOperation op = new BuiltIn.SetValvesOp(this, valveOpen, valveClose);
log.DebugFormat("{0}.SetValvesOp(vO, vC) returns {1}", Name, (op != null) ? op.ToString() : "null");
return op;
}
/// <summary>
/// Open and/or close multiple valves.
/// Events: ValvesSet
/// </summary>
/// <param name="valvesOpen">A list of valves to be opened</param>
/// <param name="valvesClose">A list of valves to be closed</param>
/// <returns>Created operation</returns>
public IOperation SetValvesOp(IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
IOperation op = new BuiltIn.SetValvesOp(this, valvesOpen, valvesClose);
log.DebugFormat("{0}.SetValvesOp(vlvsO, vlvsC) returns {1}", Name, (op != null) ? op.ToString() : "null");
return op;
}
/// <summary>
/// Open start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation OpenStartValveOp()
{
IOperation op = new BuiltIn.SetValvesOp(this, true, devices);
log.DebugFormat("{0}.OpenStartValveOp({1}) returns {2}", Name, devices.StartValve1.Name, (op != null) ? op.ToString() : "null");
return op;
}
/// <summary>
/// Close start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation CloseStartValveOp()
{
IOperation op = new BuiltIn.SetValvesOp(this, false, devices);
log.DebugFormat("{0}.CloseStartValveOp({1}) returns {2}", Name, devices.StartValve1.Name, (op != null) ? op.ToString() : "null");
return op;
}
public float ValveOpenCloseTime { get { return 0.1f; } }
/// <summary>
/// Returns operation to display a prompt message to set the flow.
/// </summary>
/// <param name="reqrdFlowLo">Lower limit</param>
/// <param name="reqrdFlowHi">Upper limit</param>
/// <param name="measuredFlow">Reference to a box for the measured flow or null</param>
/// <param name="timeout">Flow set timeout</param>
/// <returns>Operation</returns>
public IOperation SetFlowOp(double reqrdFlowLo, double reqrdFlowHi, TBF.Boxes.DoubleBox measuredFlow, int timeout)
{
string loLimStr = reqrdFlowLo.ToString(Config.Utils.SignificantDigitsToFmt(reqrdFlowLo, 2));
string hiLimStr = reqrdFlowHi.ToString(Config.Utils.SignificantDigitsToFmt(reqrdFlowHi, 2));
this.promptMsg = string.Format("Set flow measured by {0} withing {1} and {2} m3/h by regulation valve {3}",
devices.FlowMeter.Name, loLimStr, hiLimStr, devices.RegValve.Name);
this.backColor = System.Drawing.Color.LightSalmon;
scheduledOp = SelectedOp.SetFlow;
return this;
}
public IOperation StopFlowRegulationOp()
{
return new Operations.ReturnGivenEventOp(Event.FlowRegulationStopped);
}
/// <summary>
/// Start a test, Events: MeasurementStarted
/// </summary>
/// <param name="iParam">Int32 parameter 1</param>
/// <param name="dParam1">Double parameter 1 (alternative lower flow limit)</param>
/// <param name="dParam2">Double parameter 2 (alternative upper flow limit)</param>
/// <returns>Operation</returns>
public IOperation StartTestOp(Test test, int iParam = 0, double dParam1 = 0, double dParam2 = 0)
{
currentTest = test;
return new Operations.ReturnGivenEventOp(Event.MeasurementStarted);
}
public IOperation QueryMeasurementEndOp()
{
scheduledOp = SelectedOp.QueryMeasurementEnd;
return this;
}
public IOperation ReadDiverterTransitionOp(bool isStart, Sequences.Statistics plotter, int batchNr, string testName, int repetition)
{
return null;
}
public IOperation StopPreviousOp()
{
return new Operations.ReturnGivenEventOp(Event.PreviousStopped);
}
Test currentTest;
string promptMsg;
System.Drawing.Color backColor;
TBF.Rig.Operations.MessageBoxForm messageBoxForm;
///
delegate void MessageBoxFormDlgt(PapouchCB myRef);
///
void OpenFormDlg(PapouchCB myRef)
{
myRef.messageBoxForm = new TBF.Rig.Operations.MessageBoxForm(promptMsg, backColor);
messageBoxForm.Show();
}
/// <summary>
/// Start selected operation
/// </summary>
public void Start()
{
if (scheduledOp == SelectedOp.None || runningOp != SelectedOp.None)
{
throw new Exception("Sequence error");
}
runningOp = scheduledOp;
scheduledOp = SelectedOp.None;
if (runningOp == SelectedOp.SetFlow)
{
Program.MainWnd.Invoke(new MessageBoxFormDlgt(OpenFormDlg), this);
}
else if (runningOp == SelectedOp.QueryMeasurementEnd)
{
}
}
/// <summary>
/// Run selected operation
/// </summary>
/// <returns>Event.None or Event.FlowReached or Event.MeasurementCompleted </returns>
public Event Run()
{
if (runningOp == SelectedOp.SetFlow)
{
if (opCompleted || messageBoxForm.Completed)
{
opCompleted = true;
messageBoxForm = null;
return Event.FlowReached;
}
}
else if (runningOp == SelectedOp.QueryMeasurementEnd)
{
if (opCompleted) return Event.MeasurementCompleted;
double currentMass = TBF.Rig.Sequences.ProcessData.Mass.Val;
if (currentMass - TBF.Rig.Sequences.ProcessData.StartMass.Val >= currentTest.Volume)
{
opCompleted = true;
return Event.MeasurementCompleted;
}
}
return Event.None;
}
/// <summary>
/// Stop this operation
/// </summary>
public void Stop()
{
if (runningOp == SelectedOp.SetFlow)
{
if (messageBoxForm != null)
{
messageBoxForm.OnCloseThisForm(this, null);
messageBoxForm = null;
}
}
runningOp = SelectedOp.None;
opCompleted = false;
}
}
}
@@ -0,0 +1,62 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Papouch
{
public enum QuidoVariant
{
QuidoRS_4_4,
QuidoRS_8_8,
QuidoRS_2_16,
QuidoRS_2_32,
Count
}
public class PapouchCBCfg : ComponentCfgBase, Generic.IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PapouchCBCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new CBoardCfgCtrl(); }
///
/// Serialized parameters
///
public byte ModbusAddress; /// 1..254
public QuidoVariant Variant; /// QuidoRS_2_16, QuidoRS_4_4 or QuidoRS_8_8
public int VirtualValvesRangeLo;
public int VirtualValvesRangeHi;
/// Private parameterless constructor invoked by all other (public) constructors
PapouchCBCfg()
{
Name = "CB";
ParentName = "Modbus";
ModbusAddress = 1;
Variant = QuidoVariant.QuidoRS_2_32;
VirtualValvesRangeLo = 50;
VirtualValvesRangeHi = 59;
}
public PapouchCBCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("name={0}({1}) address={2} variant={3} vvLo={4} vvHi={5}",
Name,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName),
ModbusAddress,
Variant,
VirtualValvesRangeLo,
VirtualValvesRangeHi);
}
}
}