ControlBoard.Papouch modified for 4 QuidoRS boards, ver. 3.1.1604

This commit is contained in:
Milan Hanajik
2021-04-09 11:26:52 +02:00
parent 02747a975a
commit d84588650f
7 changed files with 452 additions and 628 deletions
-203
View File
@@ -1,203 +0,0 @@
///
/// 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;
}
}
@@ -1,143 +0,0 @@
///
/// 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;
}
}
}
@@ -1,120 +0,0 @@
<?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>
+167 -117
View File
@@ -22,17 +22,24 @@ namespace TBF.Rig.ControlBoard.Papouch
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly PapouchCBCfg cbCfg;
readonly GenericDevices.IModbus modbus;
GenericDevices.IModbus modbus;
UInt32 currentOutputs;
const int quidosCount = 4;
QuidoVariant[] quidoVariants;
int[] modbusAddresses;
int[] offsetsOutputs;
int[] offsetsInputs;
UInt128[] routeOutputMasks;
UInt128[] routeInputMasks;
int[] lastStateMachineTimes;
bool outputsInitialized;
DateTime lastOutputsChange;
int lastStateMachineTime = 0;
///
UInt128 currentOutputs;
UInt128 benchModelRoute;
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor
///
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
OutputPath devices;
@@ -57,11 +64,6 @@ namespace TBF.Rig.ControlBoard.Papouch
: base(cfg)
{
cbCfg = cfg as PapouchCBCfg;
modbus = (GenericDevices.IModbus)TbfComponents.FindComponent(cfg.ParentName, components);
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
log.Warn(this.ToString());
}
public void SpecifyInvertedValves(UInt128 valvesToInvert)
@@ -70,73 +72,119 @@ namespace TBF.Rig.ControlBoard.Papouch
this.benchModelRoute = valvesToInvert;
}
///
/// IDevice interface
///
public override void Initialize()
{
outputsInitialized = false;
runningOp = SelectedOp.None;
routeMask = 0;
modbus = (GenericDevices.IModbus)TbfComponents.FindComponent(cbCfg.ParentName);
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
quidoVariants = new QuidoVariant[quidosCount] { cbCfg.Variant1, cbCfg.Variant2, cbCfg.Variant3, cbCfg.Variant4 };
modbusAddresses = new int[quidosCount] { cbCfg.ModbusAddress1, cbCfg.ModbusAddress2, cbCfg.ModbusAddress3, cbCfg.ModbusAddress4 };
offsetsOutputs = new int[quidosCount] { cbCfg.OffsetOutputs1, cbCfg.OffsetOutputs2, cbCfg.OffsetOutputs3, cbCfg.OffsetOutputs4 };
offsetsInputs = new int[quidosCount] { cbCfg.OffsetInputs1, cbCfg.OffsetInputs2, cbCfg.OffsetInputs3, cbCfg.OffsetInputs4 };
routeOutputMasks = new UInt128[quidosCount] { 0, 0, 0, 0 };
routeInputMasks = new UInt128[quidosCount] { 0, 0, 0, 0 };
lastStateMachineTimes = new int[quidosCount] { 0, 0, 0, 0 };
for (int i = 0; i < 128; i++)
{
if (i < cbCfg.VirtualValvesRangeLo || i > cbCfg.VirtualValvesRangeHi)
bool conflictAvoidanceFlag = false;
for (int quidoIx = 0; quidoIx < quidosCount; quidoIx++)
{
routeMask = routeMask | ((UInt128)1 << i);
if (i >= offsetsOutputs[quidoIx] && i < offsetsOutputs[quidoIx] + OutputsCount(quidoIx))
{
if (conflictAvoidanceFlag) throw new Exception("Overlapping input/output bits");
conflictAvoidanceFlag = true;
routeOutputMasks[quidoIx] = routeOutputMasks[quidoIx] | ((UInt128)1 << i);
}
if (i >= offsetsInputs[quidoIx] && i < offsetsInputs[quidoIx] + InputsCount(quidoIx))
{
if (conflictAvoidanceFlag) throw new Exception("Overlapping input/output bits");
conflictAvoidanceFlag = true;
routeInputMasks[quidoIx] = routeInputMasks[quidoIx] | ((UInt128)1 << i);
}
}
}
outputsInitialized = false;
runningOp = SelectedOp.None;
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);
}
};
UInt128 mask = ((UInt128)1) << args.BitNr;
if ((benchModelRoute & mask) == 0)
{
benchModelRoute |= mask;
}
else
{
benchModelRoute &= (~mask);
}
};
if (cbCfg.DebugLevel == DebugMode.Normal)
log.FatalFormat("{0} initialized: {1}", cbCfg.Name, this);
else
log.FatalFormat("{0} simulated: {1}", cbCfg.Name, this);
}
///
/// IDevice interface
///
public void RunDeviceBefore()
{
if (cbCfg.DebugLevel == Config.Entities.DebugMode.Simulate) return;
if (modbus.ReceivedTelegrams[cbCfg.ModbusAddress].Count > 0)
for (int quidoIx = 0; quidoIx < quidosCount; quidoIx++ )
{
byte[] telegram = modbus.ReceivedTelegrams[cbCfg.ModbusAddress].Dequeue();
if ((telegram.Length >= 8) && (telegram[1] == 0x11) && (telegram[2] == telegram.Length - 5))
if (modbus.ReceivedTelegrams[modbusAddresses[quidoIx]].Count > 0)
{
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);
}
byte[] telegram = modbus.ReceivedTelegrams[modbusAddresses[quidoIx]].Dequeue();
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);
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("Quido{0} detected: Address={1}, Message={2}", quidoIx + 1, modbusAddress, msg);
Debug.WriteLine(s);
log.Warn(s);
}
if ((telegram.Length == 6) && (telegram[1] == 0x02) && (telegram[2] == telegram.Length - 5))
{
UInt128 inputData = telegram[3];
benchModelRoute = (benchModelRoute & ~routeInputMasks[quidoIx]) | ((inputData << offsetsInputs[quidoIx]) & routeInputMasks[quidoIx]);
string s = string.Format("Quido{0} inputs: {1}", quidoIx + 1, telegram[3].ToString("X2"));
Debug.WriteLine(s);
log.Warn(s);
}
}
}
}
public void RunDeviceAfter()
{
if (currentOutputs != (UInt32)(benchModelRoute & 0xFFFFFFFF) || !outputsInitialized || (StateMachine.Time - lastStateMachineTime) >= 3)
if (!outputsInitialized)
{
SetOutputs((UInt32)(benchModelRoute & 0xFFFFFFFF));
SendAllOutputs(benchModelRoute);
outputsInitialized = true;
}
else
{
RequestInputs();
for (int quidoIx = 0; quidoIx < quidosCount; quidoIx++)
{
if ((currentOutputs & routeOutputMasks[quidoIx]) != (benchModelRoute & routeOutputMasks[quidoIx]) ||
(StateMachine.Time - lastStateMachineTimes[quidoIx]) >= 5)
{
SendOutputs(quidoIx, benchModelRoute, offsetsOutputs[quidoIx]);
}
else
{
RequestInputs(quidoIx);
}
}
}
ProcessData.UpdateMeasuredValuesAndSetpoints();
@@ -149,92 +197,94 @@ namespace TBF.Rig.ControlBoard.Papouch
public void StopDevice()
{
SendOutputs(0);
SendAllOutputs(0);
}
public void StopDevice2() { }
/// <summary>
/// Set outputs of QuidoRS board
/// </summary>
/// <param name="outputs">output value</param>
public void SetOutputs(UInt32 outputs)
private void RequestAllInputs()
{
lock (this)
for (int quidoIx = 0; quidoIx < quidosCount; quidoIx++)
{
currentOutputs = outputs;
RequestInputs(quidoIx);
}
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)
private void RequestInputs(int quidoIx)
{
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 addr = (byte)modbusAddresses[quidoIx];
byte cmd = (byte)Function.ReadSingleInput;
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 2, 0, 0 });
}
private void SendOutputs(UInt32 outputs)
/// <summary>
/// Set outputs of QuidoRS board
/// </summary>
/// <param name="outputs">output value</param>
private void SendAllOutputs(UInt128 route)
{
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)
for (int quidoIx = 0; quidoIx < quidosCount; quidoIx++)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 4, 1, dataLo, 0, 0 });
SendOutputs(quidoIx, route, offsetsOutputs[quidoIx]);
}
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;
}
private void SendOutputs(int quidoIx, UInt128 outputs, int offset)
{
if (cbCfg.DebugLevel == Config.Entities.DebugMode.Normal)
{
byte addr = (byte)modbusAddresses[quidoIx];
byte cmd = (byte)Function.ForceMultipleCoils;
byte loByte = (byte)(outputs >> offset);
switch (quidoVariants[quidoIx])
{
case QuidoVariant.QuidoRS_4_4:
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 4, 1, loByte, 0, 0 });
break;
case QuidoVariant.QuidoRS_8_8:
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 8, 1, loByte, 0, 0 });
break;
case QuidoVariant.QuidoRS_2_16:
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 16, 2, loByte, (byte)(outputs >> (offset + 8)), 0, 0 });
break;
case QuidoVariant.QuidoRS_2_32:
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 32, 4, loByte, (byte)(outputs >> (offset + 8)),
(byte)(outputs >> (offset + 16)),
(byte)(outputs >> (offset + 24)), 0, 0 });
break;
}
}
currentOutputs = (currentOutputs & ~routeOutputMasks[quidoIx]) | (outputs & routeOutputMasks[quidoIx]);
lastStateMachineTimes[quidoIx] = StateMachine.Time;
}
int InputsCount(int quidoIx)
{
switch (quidoVariants[quidoIx])
{
case QuidoVariant.QuidoRS_4_4: return 4;
case QuidoVariant.QuidoRS_8_8: return 8;
case QuidoVariant.QuidoRS_2_16: return 2;
case QuidoVariant.QuidoRS_2_32: return 2;
default: return 0;
}
}
int OutputsCount(int quidoIx)
{
switch (quidoVariants[quidoIx])
{
case QuidoVariant.QuidoRS_4_4: return 4;
case QuidoVariant.QuidoRS_8_8: return 8;
case QuidoVariant.QuidoRS_2_16: return 16;
case QuidoVariant.QuidoRS_2_32: return 32;
default: return 0;
}
}
///
/// IControlBoard interface
+283 -34
View File
@@ -1,7 +1,9 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
using Config.Entities;
///
/// Copyright (c) 2020-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using TBF.Rig.Generic;
@@ -9,6 +11,7 @@ namespace TBF.Rig.ControlBoard.Papouch
{
public enum QuidoVariant
{
None,
QuidoRS_4_4,
QuidoRS_8_8,
QuidoRS_2_16,
@@ -16,47 +19,293 @@ namespace TBF.Rig.ControlBoard.Papouch
Count
}
public class PapouchCBCfg : ComponentCfgBase, Generic.IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PapouchCBCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public class PapouchCBCfg : ComponentCfgBase, Generic.IChildComponentCfg, IParamsProvider
{
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(); }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
{
var parents = cmpntEntities.Where(x => x.ClassName == "Modbus.Common");
return new Configs.ParamsProvider.ComponentCfgCtrl(this, parents);
}
///
/// 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;
///
/// Serialized parameters
///
public QuidoVariant Variant1; /// None, QuidoRS_4_4, QuidoRS_8_8, QuidoRS_2_16 or QuidoRS_2_32
public int ModbusAddress1; /// 1 .. 254
public int OffsetOutputs1; /// 0 .. (128 - output bits count)
public int OffsetInputs1; /// 0 .. (128 - input bits count)
/// 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 QuidoVariant Variant2; /// None, QuidoRS_4_4, QuidoRS_8_8, QuidoRS_2_16 or QuidoRS_2_32
public int ModbusAddress2; /// 1 .. 254
public int OffsetOutputs2; /// 0 .. (128 - output bits count)
public int OffsetInputs2; /// 0 .. (128 - input bits count)
public QuidoVariant Variant3; /// None, QuidoRS_4_4, QuidoRS_8_8, QuidoRS_2_16 or QuidoRS_2_32
public int ModbusAddress3; /// 1 .. 254
public int OffsetOutputs3; /// 0 .. (128 - output bits count)
public int OffsetInputs3; /// 0 .. (128 - input bits count)
public QuidoVariant Variant4; /// None, QuidoRS_4_4, QuidoRS_8_8, QuidoRS_2_16 or QuidoRS_2_32
public int ModbusAddress4; /// 1 .. 254
public int OffsetOutputs4; /// 0 .. (128 - output bits count)
public int OffsetInputs4; /// 0 .. (128 - input bits count)
/// Private parameterless constructor invoked by all other (public) constructors
PapouchCBCfg() { }
public PapouchCBCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
Name = "CB";
ParentName = "Modbus";
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
Variant1 = QuidoVariant.QuidoRS_8_8;
ModbusAddress1 = 1;
OffsetOutputs1 = 0;
OffsetInputs1 = 64;
Variant2 = QuidoVariant.None;
ModbusAddress2 = 0;
OffsetOutputs2 = 0;
OffsetInputs2 = 0;
Variant3 = QuidoVariant.None;
ModbusAddress3 = 0;
OffsetOutputs3 = 0;
OffsetInputs3 = 0;
Variant4 = QuidoVariant.None;
ModbusAddress4 = 0;
OffsetOutputs4 = 0;
OffsetInputs4 = 0;
}
string[] paramNames = new string[]
{
"Board 1: Variant", /// 0
"Board 1: Modbus address", /// 1
"Board 1: Offset outputs", /// 2
"Board 1: Offset inputs", /// 3
"Board 2: Variant", /// 4
"Board 2: Modbus address", /// 5
"Board 2: Offset outputs", /// 6
"Board 2: Offset inputs", /// 7
"Board 3: Variant", /// 8
"Board 3: Modbus address", /// 9
"Board 3: Offset outputs", /// 10
"Board 3: Offset inputs", /// 11
"Board 4: Variant", /// 12
"Board 4: Modbus address", /// 13
"Board 4: Offset outputs", /// 14
"Board 4: Offset inputs", /// 15
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 0:
case 4:
case 8:
case 12:
return new string[] { QuidoVariant.None.ToString(),
QuidoVariant.QuidoRS_4_4.ToString(),
QuidoVariant.QuidoRS_8_8.ToString(),
QuidoVariant.QuidoRS_2_16.ToString(),
QuidoVariant.QuidoRS_2_32.ToString() };
default:
return null;
}
}
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);
}
}
switch (i)
{
case 0: return Variant1.ToString();
case 1: return ModbusAddress1.ToString();
case 2: return OffsetOutputs1.ToString();
case 3: return OffsetInputs1.ToString();
case 4: return Variant2.ToString();
case 5: return ModbusAddress2.ToString();
case 6: return OffsetOutputs2.ToString();
case 7: return OffsetInputs2.ToString();
case 8: return Variant3.ToString();
case 9: return ModbusAddress3.ToString();
case 10: return OffsetOutputs3.ToString();
case 11: return OffsetInputs3.ToString();
case 12: return Variant4.ToString();
case 13: return ModbusAddress4.ToString();
case 14: return OffsetOutputs4.ToString();
case 15: return OffsetInputs4.ToString();
default:
return string.Format("name={0}({1}) {2}/a{3}/o{4}/i{5} {6}/a{7}/o{8}/i{9} {10}/a{11}/o{12}/i{13} {14}/a{15}/o{16}/i{17}",
Name, (string.IsNullOrEmpty(ParentName) ? "-" : ParentName),
Variant1, ModbusAddress1, OffsetOutputs1, OffsetInputs1,
Variant2, ModbusAddress2, OffsetOutputs2, OffsetInputs2,
Variant3, ModbusAddress3, OffsetOutputs3, OffsetInputs3,
Variant4, ModbusAddress4, OffsetOutputs4, OffsetInputs4);
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0:
foreach (var v in new QuidoVariant[] { QuidoVariant.QuidoRS_4_4, QuidoVariant.QuidoRS_8_8, QuidoVariant.QuidoRS_2_16, QuidoVariant.QuidoRS_2_32 })
{
if (str == v.ToString())
{
Variant1 = v;
return CfgUpdateFlags.RestartRqrd;
}
}
Variant1 = QuidoVariant.None;
return CfgUpdateFlags.None;
case 1: ModbusAddress1 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 2: OffsetOutputs1 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 3: OffsetInputs1 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 4:
foreach (var v in new QuidoVariant[] { QuidoVariant.QuidoRS_4_4, QuidoVariant.QuidoRS_8_8, QuidoVariant.QuidoRS_2_16, QuidoVariant.QuidoRS_2_32 })
{
if (str == v.ToString())
{
Variant2 = v;
return CfgUpdateFlags.RestartRqrd;
}
}
Variant2 = QuidoVariant.None;
return CfgUpdateFlags.None;
case 5: ModbusAddress2 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 6: OffsetOutputs2 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 7: OffsetInputs2 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 8:
foreach (var v in new QuidoVariant[] { QuidoVariant.QuidoRS_4_4, QuidoVariant.QuidoRS_8_8, QuidoVariant.QuidoRS_2_16, QuidoVariant.QuidoRS_2_32 })
{
if (str == v.ToString())
{
Variant3 = v;
return CfgUpdateFlags.RestartRqrd;
}
}
Variant3 = QuidoVariant.None;
return CfgUpdateFlags.None;
case 9: ModbusAddress3 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 10: OffsetOutputs3 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 11: OffsetInputs3 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 12:
foreach (var v in new QuidoVariant[] { QuidoVariant.QuidoRS_4_4, QuidoVariant.QuidoRS_8_8, QuidoVariant.QuidoRS_2_16, QuidoVariant.QuidoRS_2_32 })
{
if (str == v.ToString())
{
Variant4 = v;
return CfgUpdateFlags.RestartRqrd;
}
}
Variant4 = QuidoVariant.None;
return CfgUpdateFlags.None;
case 13: ModbusAddress4 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 14: OffsetOutputs4 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 15: OffsetInputs4 = (byte)int.Parse(str); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string str, out string message)
{
message = string.Empty;
int idummy;
switch (i)
{
case 0:
case 4:
case 8:
case 12:
if (ParamValues(i).Contains(str)) return true;
break;
case 1:
case 5:
case 9:
case 13:
if (int.TryParse(str, out idummy) && idummy >= 1 && idummy <= 254) return true;
break;
case 2:
case 3:
case 6:
case 7:
case 10:
case 11:
case 14:
case 15:
if (int.TryParse(str, out idummy) && idummy >= 0 && idummy <= 127) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(PapouchCBCfg prms)
{
prms.ParentName = ParentName;
prms.Variant1 = Variant1;
prms.ModbusAddress1 = ModbusAddress1;
prms.OffsetOutputs1 = OffsetOutputs1;
prms.OffsetInputs1 = OffsetInputs1;
prms.Variant2 = Variant2;
prms.ModbusAddress2 = ModbusAddress2;
prms.OffsetOutputs2 = OffsetOutputs2;
prms.OffsetInputs2 = OffsetInputs2;
prms.Variant3 = Variant3;
prms.ModbusAddress3 = ModbusAddress3;
prms.OffsetOutputs3 = OffsetOutputs3;
prms.OffsetInputs3 = OffsetInputs3;
prms.Variant4 = Variant4;
prms.ModbusAddress4 = ModbusAddress4;
prms.OffsetOutputs4 = OffsetOutputs4;
prms.OffsetInputs4 = OffsetInputs4;
}
public IParamsProvider Clone()
{
PapouchCBCfg pars = new PapouchCBCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}