Compare commits
22 Commits
93e207c211
...
842f009b42
| Author | SHA1 | Date | |
|---|---|---|---|
| 842f009b42 | |||
| 7f30ca0cd1 | |||
| 5a8478e782 | |||
| 33ef914984 | |||
| 3eb0b87f0d | |||
| 711dfc03ef | |||
| 93459ccfab | |||
| 009aefb7c9 | |||
| d2e18d615d | |||
| 69b475eb77 | |||
| 2210bb8240 | |||
| 65ab19290f | |||
| 94c7279da1 | |||
| 2136695b80 | |||
| c0f9b0ffa0 | |||
| c4ef22436f | |||
| 0b73871518 | |||
| f7dc6fee5e | |||
| ba848a167d | |||
| dcb0bf9a88 | |||
| f6433134c1 | |||
| 7e3df77b5b |
@ -19,6 +19,9 @@ using System.Runtime.InteropServices;
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//Visibility to TBFTests internal classes
|
||||
[assembly: InternalsVisibleTo("TBFTests")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")]
|
||||
|
||||
@ -29,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("3.9.3031.1")]
|
||||
[assembly: AssemblyFileVersion("3.9.3031.1")]
|
||||
[assembly: AssemblyVersion("3.9.3058.1")]
|
||||
[assembly: AssemblyFileVersion("3.9.3058.1")]
|
||||
|
||||
10
TBF/Resources/Strings.Designer.cs
generated
10
TBF/Resources/Strings.Designer.cs
generated
@ -1,7 +1,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@ -6270,6 +6269,15 @@ namespace TBF.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Test in calculation.
|
||||
/// </summary>
|
||||
internal static string Test_in_calculation {
|
||||
get {
|
||||
return ResourceManager.GetString("Test_in_calculation", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Test in progress.
|
||||
/// </summary>
|
||||
|
||||
5012
TBF/Resources/Strings.cs.Designer.cs
generated
5012
TBF/Resources/Strings.cs.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -1764,4 +1764,7 @@
|
||||
<data name="Units" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Test_in_calculation" xml:space="preserve">
|
||||
<value>Probíhá výpočet</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -2482,4 +2482,7 @@
|
||||
<data name="Units" xml:space="preserve">
|
||||
<value>Units</value>
|
||||
</data>
|
||||
<data name="Test_in_calculation" xml:space="preserve">
|
||||
<value>Test in calculation</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -259,4 +259,7 @@
|
||||
<data name="Units" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Test_in_calculation" xml:space="preserve">
|
||||
<value>Prebieha výpočet</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -16,8 +16,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
{
|
||||
return new GenesisCfgCtrl();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
@ -31,8 +29,10 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
public int MuxBoardNr; /// 0 = use RfidComPort(Nr), otherwise mux. board nr. 1 .. 4
|
||||
public int Group; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
|
||||
public CommunicationInterface CommunicationInterface; /// Communication Interface: RFID or NFC
|
||||
///
|
||||
public bool EnableShowChanels;
|
||||
public int IBeginDataFlush;
|
||||
|
||||
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
[XmlIgnore]
|
||||
@ -56,6 +56,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
ProcParams = CreateProcParamsProvider() as ProcParams;
|
||||
CommunicationInterface = CommunicationInterface.RFID;
|
||||
HeadCommunicationComPortNr = 0;
|
||||
EnableShowChanels = false;
|
||||
IBeginDataFlush = 2000;
|
||||
}
|
||||
|
||||
public GenesisCfg(IComponentFactory factory)
|
||||
@ -67,7 +69,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return $"{Name} Group1 (mux#)={MuxBoardNr}, Group2={Group}, Opto=Com{OptoComPortNr}, {CommunicationInterface}=Com{RfidComPortNr}";
|
||||
return $"{Name} Group1 (mux#)={MuxBoardNr}, Group2={Group}, Opto=Com{OptoComPortNr}, {CommunicationInterface}=Com{RfidComPortNr}, EnableShowChanels={EnableShowChanels}, IBeginDataFlush={IBeginDataFlush}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,6 +58,9 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
muxBoardNrTextBox.Text = config.MuxBoardNr.ToString();
|
||||
groupTextBox.Text = config.Group.ToString();
|
||||
comboBoxCommunicationInterface.SelectedItem = config.CommunicationInterface.ToString();
|
||||
tBBeginDataFlush.Text = config.IBeginDataFlush.ToString();
|
||||
checkBox_EnableShowChanels.Checked = config.EnableShowChanels;
|
||||
|
||||
tabPage2.Controls.Add(new GenesisHeadTestCtrl(config));
|
||||
}
|
||||
|
||||
@ -74,6 +77,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
muxBoardNrTextBox.Enabled = true;
|
||||
groupTextBox.Enabled = true;
|
||||
comboBoxCommunicationInterface.Enabled = true;
|
||||
tBBeginDataFlush.Enabled = true;
|
||||
checkBox_EnableShowChanels.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
@ -129,6 +134,12 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, groupLabel.Text);
|
||||
}
|
||||
|
||||
if (!int.TryParse(tBBeginDataFlush.Text, out dummy) || dummy < 0 || dummy > 10000)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, tBBeginDataFlush.Text);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
@ -158,6 +169,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
config.Group = int.Parse(groupTextBox.Text);
|
||||
config.CommunicationInterface = (CommunicationInterface)comboBoxCommunicationInterface.SelectedIndex;
|
||||
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
|
||||
config.IBeginDataFlush = int.Parse(tBBeginDataFlush.Text);
|
||||
config.EnableShowChanels = checkBox_EnableShowChanels.Checked;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -25,388 +25,433 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
|
||||
this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.tcpipPortLabel = new System.Windows.Forms.Label();
|
||||
this.tcpipPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ipAddressLabel = new System.Windows.Forms.Label();
|
||||
this.ipAddressTextBox = new System.Windows.Forms.TextBox();
|
||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
||||
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
||||
this.optoSerialPortLabel = new System.Windows.Forms.Label();
|
||||
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.groupTextBox = new System.Windows.Forms.TextBox();
|
||||
this.groupLabel = new System.Windows.Forms.Label();
|
||||
this.muxBoardNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.muxBoardNrLabel = 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.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.headPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.optoDataGroupBox.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPage1);
|
||||
this.tabControl1.Controls.Add(this.tabPage2);
|
||||
this.tabControl1.Location = new System.Drawing.Point(3, 3);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(611, 432);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPage1
|
||||
//
|
||||
this.tabPage1.Controls.Add(this.groupBox2);
|
||||
this.tabPage1.Controls.Add(this.label4);
|
||||
this.tabPage1.Controls.Add(this.label3);
|
||||
this.tabPage1.Controls.Add(this.groupBox1);
|
||||
this.tabPage1.Controls.Add(this.optoDataGroupBox);
|
||||
this.tabPage1.Controls.Add(this.groupTextBox);
|
||||
this.tabPage1.Controls.Add(this.groupLabel);
|
||||
this.tabPage1.Controls.Add(this.muxBoardNrTextBox);
|
||||
this.tabPage1.Controls.Add(this.muxBoardNrLabel);
|
||||
this.tabPage1.Controls.Add(this.nameTextBox);
|
||||
this.tabPage1.Controls.Add(this.nameLabel);
|
||||
this.tabPage1.Controls.Add(this.classNameLabel);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 25);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(603, 403);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Config";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(208, 101);
|
||||
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(40, 16);
|
||||
this.label4.TabIndex = 25;
|
||||
this.label4.Text = "1 .. 10";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(208, 72);
|
||||
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(33, 16);
|
||||
this.label3.TabIndex = 24;
|
||||
this.label3.Text = "1 .. 4";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
|
||||
this.groupBox1.Controls.Add(this.label1);
|
||||
this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
|
||||
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
|
||||
this.groupBox1.Location = new System.Drawing.Point(10, 259);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox1.Size = new System.Drawing.Size(552, 68);
|
||||
this.groupBox1.TabIndex = 23;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
|
||||
//
|
||||
// comboBoxCommunicationInterface
|
||||
//
|
||||
this.comboBoxCommunicationInterface.Enabled = false;
|
||||
this.comboBoxCommunicationInterface.FormattingEnabled = true;
|
||||
this.comboBoxCommunicationInterface.Items.AddRange(new object[] {
|
||||
"RFID",
|
||||
"NFC"});
|
||||
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(201, 27);
|
||||
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
|
||||
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(71, 24);
|
||||
this.comboBoxCommunicationInterface.TabIndex = 9;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(41, 30);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(153, 16);
|
||||
this.label1.TabIndex = 8;
|
||||
this.label1.Text = "Communication Interface";
|
||||
//
|
||||
// rfidPortNrTextBox
|
||||
//
|
||||
this.rfidPortNrTextBox.Enabled = false;
|
||||
this.rfidPortNrTextBox.Location = new System.Drawing.Point(439, 26);
|
||||
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
|
||||
this.rfidPortNrTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.rfidPortNrTextBox.TabIndex = 7;
|
||||
//
|
||||
// rfidSerialPortNrLabel
|
||||
//
|
||||
this.rfidSerialPortNrLabel.AutoSize = true;
|
||||
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(321, 30);
|
||||
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
|
||||
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(88, 16);
|
||||
this.rfidSerialPortNrLabel.TabIndex = 6;
|
||||
this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoDataGroupBox
|
||||
//
|
||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox);
|
||||
this.optoDataGroupBox.Controls.Add(this.ipAddressLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox);
|
||||
this.optoDataGroupBox.Controls.Add(this.radioButton1);
|
||||
this.optoDataGroupBox.Controls.Add(this.radioButton2);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
|
||||
this.optoDataGroupBox.Location = new System.Drawing.Point(10, 131);
|
||||
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.optoDataGroupBox.Name = "optoDataGroupBox";
|
||||
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.optoDataGroupBox.Size = new System.Drawing.Size(552, 119);
|
||||
this.optoDataGroupBox.TabIndex = 18;
|
||||
this.optoDataGroupBox.TabStop = false;
|
||||
this.optoDataGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// tcpipPortLabel
|
||||
//
|
||||
this.tcpipPortLabel.AutoSize = true;
|
||||
this.tcpipPortLabel.Location = new System.Drawing.Point(41, 87);
|
||||
this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.tcpipPortLabel.Name = "tcpipPortLabel";
|
||||
this.tcpipPortLabel.Size = new System.Drawing.Size(54, 16);
|
||||
this.tcpipPortLabel.TabIndex = 4;
|
||||
this.tcpipPortLabel.Text = "Port nr..:";
|
||||
//
|
||||
// tcpipPortTextBox
|
||||
//
|
||||
this.tcpipPortTextBox.Enabled = false;
|
||||
this.tcpipPortTextBox.Location = new System.Drawing.Point(143, 84);
|
||||
this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.tcpipPortTextBox.Name = "tcpipPortTextBox";
|
||||
this.tcpipPortTextBox.Size = new System.Drawing.Size(51, 22);
|
||||
this.tcpipPortTextBox.TabIndex = 5;
|
||||
//
|
||||
// ipAddressLabel
|
||||
//
|
||||
this.ipAddressLabel.AutoSize = true;
|
||||
this.ipAddressLabel.Location = new System.Drawing.Point(41, 59);
|
||||
this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.ipAddressLabel.Name = "ipAddressLabel";
|
||||
this.ipAddressLabel.Size = new System.Drawing.Size(78, 16);
|
||||
this.ipAddressLabel.TabIndex = 2;
|
||||
this.ipAddressLabel.Text = "IP address.:";
|
||||
//
|
||||
// ipAddressTextBox
|
||||
//
|
||||
this.ipAddressTextBox.Enabled = false;
|
||||
this.ipAddressTextBox.Location = new System.Drawing.Point(143, 55);
|
||||
this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.ipAddressTextBox.Name = "ipAddressTextBox";
|
||||
this.ipAddressTextBox.Size = new System.Drawing.Size(129, 22);
|
||||
this.ipAddressTextBox.TabIndex = 3;
|
||||
//
|
||||
// radioButton1
|
||||
//
|
||||
this.radioButton1.AutoSize = true;
|
||||
this.radioButton1.Checked = true;
|
||||
this.radioButton1.Enabled = false;
|
||||
this.radioButton1.Location = new System.Drawing.Point(29, 23);
|
||||
this.radioButton1.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.radioButton1.Name = "radioButton1";
|
||||
this.radioButton1.Size = new System.Drawing.Size(99, 20);
|
||||
this.radioButton1.TabIndex = 0;
|
||||
this.radioButton1.TabStop = true;
|
||||
this.radioButton1.Text = "Use TCP/IP";
|
||||
this.radioButton1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioButton2
|
||||
//
|
||||
this.radioButton2.AutoSize = true;
|
||||
this.radioButton2.Enabled = false;
|
||||
this.radioButton2.Location = new System.Drawing.Point(312, 23);
|
||||
this.radioButton2.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.radioButton2.Name = "radioButton2";
|
||||
this.radioButton2.Size = new System.Drawing.Size(115, 20);
|
||||
this.radioButton2.TabIndex = 1;
|
||||
this.radioButton2.Text = "Use serial port";
|
||||
this.radioButton2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// optoSerialPortLabel
|
||||
//
|
||||
this.optoSerialPortLabel.AutoSize = true;
|
||||
this.optoSerialPortLabel.Location = new System.Drawing.Point(321, 55);
|
||||
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.optoSerialPortLabel.Name = "optoSerialPortLabel";
|
||||
this.optoSerialPortLabel.Size = new System.Drawing.Size(88, 16);
|
||||
this.optoSerialPortLabel.TabIndex = 6;
|
||||
this.optoSerialPortLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoSerialPortTextBox
|
||||
//
|
||||
this.optoSerialPortTextBox.Enabled = false;
|
||||
this.optoSerialPortTextBox.Location = new System.Drawing.Point(439, 52);
|
||||
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
|
||||
this.optoSerialPortTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.optoSerialPortTextBox.TabIndex = 7;
|
||||
//
|
||||
// groupTextBox
|
||||
//
|
||||
this.groupTextBox.Enabled = false;
|
||||
this.groupTextBox.Location = new System.Drawing.Point(153, 97);
|
||||
this.groupTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupTextBox.Name = "groupTextBox";
|
||||
this.groupTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.groupTextBox.TabIndex = 22;
|
||||
//
|
||||
// groupLabel
|
||||
//
|
||||
this.groupLabel.AutoSize = true;
|
||||
this.groupLabel.Location = new System.Drawing.Point(6, 101);
|
||||
this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.groupLabel.Name = "groupLabel";
|
||||
this.groupLabel.Size = new System.Drawing.Size(54, 16);
|
||||
this.groupLabel.TabIndex = 21;
|
||||
this.groupLabel.Text = "Group 2";
|
||||
//
|
||||
// muxBoardNrTextBox
|
||||
//
|
||||
this.muxBoardNrTextBox.Enabled = false;
|
||||
this.muxBoardNrTextBox.Location = new System.Drawing.Point(153, 69);
|
||||
this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.muxBoardNrTextBox.Name = "muxBoardNrTextBox";
|
||||
this.muxBoardNrTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.muxBoardNrTextBox.TabIndex = 20;
|
||||
//
|
||||
// muxBoardNrLabel
|
||||
//
|
||||
this.muxBoardNrLabel.AutoSize = true;
|
||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(6, 72);
|
||||
this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(131, 16);
|
||||
this.muxBoardNrLabel.TabIndex = 19;
|
||||
this.muxBoardNrLabel.Text = "Group 1 (mux. board)";
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(153, 40);
|
||||
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(160, 22);
|
||||
this.nameTextBox.TabIndex = 17;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(6, 44);
|
||||
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(44, 16);
|
||||
this.nameLabel.TabIndex = 16;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(149, 11);
|
||||
this.classNameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(78, 16);
|
||||
this.classNameLabel.TabIndex = 15;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 25);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage2.Size = new System.Drawing.Size(603, 403);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Test";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.headPortNrTextBox);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Location = new System.Drawing.Point(10, 335);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(552, 50);
|
||||
this.groupBox2.TabIndex = 26;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Head Communication";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(321, 18);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(88, 16);
|
||||
this.label2.TabIndex = 7;
|
||||
this.label2.Text = "Serial port nr.:";
|
||||
//
|
||||
// headPortNrTextBox
|
||||
//
|
||||
this.headPortNrTextBox.Enabled = false;
|
||||
this.headPortNrTextBox.Location = new System.Drawing.Point(439, 15);
|
||||
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.headPortNrTextBox.Name = "headPortNrTextBox";
|
||||
this.headPortNrTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.headPortNrTextBox.TabIndex = 8;
|
||||
//
|
||||
// IperlHeadCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tabControl1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.Name = "GenesisCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(617, 438);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPage1.ResumeLayout(false);
|
||||
this.tabPage1.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.optoDataGroupBox.ResumeLayout(false);
|
||||
this.optoDataGroupBox.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.headPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
|
||||
this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.checkBox_EnableShowChanels = new System.Windows.Forms.CheckBox();
|
||||
this.tBBeginDataFlush = new System.Windows.Forms.TextBox();
|
||||
this.labelFlush = new System.Windows.Forms.Label();
|
||||
this.tcpipPortLabel = new System.Windows.Forms.Label();
|
||||
this.tcpipPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ipAddressLabel = new System.Windows.Forms.Label();
|
||||
this.ipAddressTextBox = new System.Windows.Forms.TextBox();
|
||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
||||
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
||||
this.optoSerialPortLabel = new System.Windows.Forms.Label();
|
||||
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.groupTextBox = new System.Windows.Forms.TextBox();
|
||||
this.groupLabel = new System.Windows.Forms.Label();
|
||||
this.muxBoardNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.muxBoardNrLabel = 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.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.optoDataGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPage1);
|
||||
this.tabControl1.Controls.Add(this.tabPage2);
|
||||
this.tabControl1.Location = new System.Drawing.Point(3, 4);
|
||||
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(687, 540);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPage1
|
||||
//
|
||||
this.tabPage1.Controls.Add(this.groupBox2);
|
||||
this.tabPage1.Controls.Add(this.label4);
|
||||
this.tabPage1.Controls.Add(this.label3);
|
||||
this.tabPage1.Controls.Add(this.groupBox1);
|
||||
this.tabPage1.Controls.Add(this.optoDataGroupBox);
|
||||
this.tabPage1.Controls.Add(this.groupTextBox);
|
||||
this.tabPage1.Controls.Add(this.groupLabel);
|
||||
this.tabPage1.Controls.Add(this.muxBoardNrTextBox);
|
||||
this.tabPage1.Controls.Add(this.muxBoardNrLabel);
|
||||
this.tabPage1.Controls.Add(this.nameTextBox);
|
||||
this.tabPage1.Controls.Add(this.nameLabel);
|
||||
this.tabPage1.Controls.Add(this.classNameLabel);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 29);
|
||||
this.tabPage1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage1.Size = new System.Drawing.Size(679, 507);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Config";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.headPortNrTextBox);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Location = new System.Drawing.Point(11, 450);
|
||||
this.groupBox2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.groupBox2.Size = new System.Drawing.Size(621, 52);
|
||||
this.groupBox2.TabIndex = 26;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Head Communication";
|
||||
//
|
||||
// headPortNrTextBox
|
||||
//
|
||||
this.headPortNrTextBox.Enabled = false;
|
||||
this.headPortNrTextBox.Location = new System.Drawing.Point(494, 19);
|
||||
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.headPortNrTextBox.Name = "headPortNrTextBox";
|
||||
this.headPortNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.headPortNrTextBox.TabIndex = 8;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(361, 22);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(107, 20);
|
||||
this.label2.TabIndex = 7;
|
||||
this.label2.Text = "Serial port nr.:";
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(234, 126);
|
||||
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(52, 20);
|
||||
this.label4.TabIndex = 25;
|
||||
this.label4.Text = "1 .. 10";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(234, 90);
|
||||
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(43, 20);
|
||||
this.label3.TabIndex = 24;
|
||||
this.label3.Text = "1 .. 4";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
|
||||
this.groupBox1.Controls.Add(this.label1);
|
||||
this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
|
||||
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
|
||||
this.groupBox1.Location = new System.Drawing.Point(11, 363);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.groupBox1.Size = new System.Drawing.Size(621, 85);
|
||||
this.groupBox1.TabIndex = 23;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
|
||||
//
|
||||
// comboBoxCommunicationInterface
|
||||
//
|
||||
this.comboBoxCommunicationInterface.Enabled = false;
|
||||
this.comboBoxCommunicationInterface.FormattingEnabled = true;
|
||||
this.comboBoxCommunicationInterface.Items.AddRange(new object[] { "RFID", "NFC" });
|
||||
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(226, 34);
|
||||
this.comboBoxCommunicationInterface.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
|
||||
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(79, 28);
|
||||
this.comboBoxCommunicationInterface.TabIndex = 9;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(46, 38);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(187, 20);
|
||||
this.label1.TabIndex = 8;
|
||||
this.label1.Text = "Communication Interface";
|
||||
//
|
||||
// rfidPortNrTextBox
|
||||
//
|
||||
this.rfidPortNrTextBox.Enabled = false;
|
||||
this.rfidPortNrTextBox.Location = new System.Drawing.Point(494, 32);
|
||||
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
|
||||
this.rfidPortNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.rfidPortNrTextBox.TabIndex = 7;
|
||||
//
|
||||
// rfidSerialPortNrLabel
|
||||
//
|
||||
this.rfidSerialPortNrLabel.AutoSize = true;
|
||||
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(361, 38);
|
||||
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
|
||||
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(107, 20);
|
||||
this.rfidSerialPortNrLabel.TabIndex = 6;
|
||||
this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoDataGroupBox
|
||||
//
|
||||
this.optoDataGroupBox.Controls.Add(this.checkBox_EnableShowChanels);
|
||||
this.optoDataGroupBox.Controls.Add(this.tBBeginDataFlush);
|
||||
this.optoDataGroupBox.Controls.Add(this.labelFlush);
|
||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox);
|
||||
this.optoDataGroupBox.Controls.Add(this.ipAddressLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox);
|
||||
this.optoDataGroupBox.Controls.Add(this.radioButton1);
|
||||
this.optoDataGroupBox.Controls.Add(this.radioButton2);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
|
||||
this.optoDataGroupBox.Location = new System.Drawing.Point(11, 164);
|
||||
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.optoDataGroupBox.Name = "optoDataGroupBox";
|
||||
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.optoDataGroupBox.Size = new System.Drawing.Size(621, 189);
|
||||
this.optoDataGroupBox.TabIndex = 18;
|
||||
this.optoDataGroupBox.TabStop = false;
|
||||
this.optoDataGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// checkBox_EnableShowChanels
|
||||
//
|
||||
this.checkBox_EnableShowChanels.Checked = true;
|
||||
this.checkBox_EnableShowChanels.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.checkBox_EnableShowChanels.Enabled = false;
|
||||
this.checkBox_EnableShowChanels.Location = new System.Drawing.Point(351, 147);
|
||||
this.checkBox_EnableShowChanels.Name = "checkBox_EnableShowChanels";
|
||||
this.checkBox_EnableShowChanels.Size = new System.Drawing.Size(238, 24);
|
||||
this.checkBox_EnableShowChanels.TabIndex = 10;
|
||||
this.checkBox_EnableShowChanels.Text = "Enable Show Channels";
|
||||
this.checkBox_EnableShowChanels.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tBBeginDataFlush
|
||||
//
|
||||
this.tBBeginDataFlush.Enabled = false;
|
||||
this.tBBeginDataFlush.Location = new System.Drawing.Point(474, 105);
|
||||
this.tBBeginDataFlush.MaxLength = 8;
|
||||
this.tBBeginDataFlush.Name = "tBBeginDataFlush";
|
||||
this.tBBeginDataFlush.Size = new System.Drawing.Size(69, 26);
|
||||
this.tBBeginDataFlush.TabIndex = 9;
|
||||
this.tBBeginDataFlush.Text = "2000";
|
||||
this.tBBeginDataFlush.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
//
|
||||
// labelFlush
|
||||
//
|
||||
this.labelFlush.Location = new System.Drawing.Point(328, 109);
|
||||
this.labelFlush.Name = "labelFlush";
|
||||
this.labelFlush.Size = new System.Drawing.Size(140, 22);
|
||||
this.labelFlush.TabIndex = 8;
|
||||
this.labelFlush.Text = "Begin Data Flush:";
|
||||
//
|
||||
// tcpipPortLabel
|
||||
//
|
||||
this.tcpipPortLabel.AutoSize = true;
|
||||
this.tcpipPortLabel.Location = new System.Drawing.Point(46, 109);
|
||||
this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.tcpipPortLabel.Name = "tcpipPortLabel";
|
||||
this.tcpipPortLabel.Size = new System.Drawing.Size(68, 20);
|
||||
this.tcpipPortLabel.TabIndex = 4;
|
||||
this.tcpipPortLabel.Text = "Port nr..:";
|
||||
//
|
||||
// tcpipPortTextBox
|
||||
//
|
||||
this.tcpipPortTextBox.Enabled = false;
|
||||
this.tcpipPortTextBox.Location = new System.Drawing.Point(161, 105);
|
||||
this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.tcpipPortTextBox.Name = "tcpipPortTextBox";
|
||||
this.tcpipPortTextBox.Size = new System.Drawing.Size(57, 26);
|
||||
this.tcpipPortTextBox.TabIndex = 5;
|
||||
//
|
||||
// ipAddressLabel
|
||||
//
|
||||
this.ipAddressLabel.AutoSize = true;
|
||||
this.ipAddressLabel.Location = new System.Drawing.Point(46, 74);
|
||||
this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.ipAddressLabel.Name = "ipAddressLabel";
|
||||
this.ipAddressLabel.Size = new System.Drawing.Size(93, 20);
|
||||
this.ipAddressLabel.TabIndex = 2;
|
||||
this.ipAddressLabel.Text = "IP address.:";
|
||||
//
|
||||
// ipAddressTextBox
|
||||
//
|
||||
this.ipAddressTextBox.Enabled = false;
|
||||
this.ipAddressTextBox.Location = new System.Drawing.Point(161, 69);
|
||||
this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.ipAddressTextBox.Name = "ipAddressTextBox";
|
||||
this.ipAddressTextBox.Size = new System.Drawing.Size(145, 26);
|
||||
this.ipAddressTextBox.TabIndex = 3;
|
||||
//
|
||||
// radioButton1
|
||||
//
|
||||
this.radioButton1.AutoSize = true;
|
||||
this.radioButton1.Checked = true;
|
||||
this.radioButton1.Enabled = false;
|
||||
this.radioButton1.Location = new System.Drawing.Point(33, 29);
|
||||
this.radioButton1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.radioButton1.Name = "radioButton1";
|
||||
this.radioButton1.Size = new System.Drawing.Size(109, 24);
|
||||
this.radioButton1.TabIndex = 0;
|
||||
this.radioButton1.TabStop = true;
|
||||
this.radioButton1.Text = "Use TCP/IP";
|
||||
this.radioButton1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioButton2
|
||||
//
|
||||
this.radioButton2.AutoSize = true;
|
||||
this.radioButton2.Enabled = false;
|
||||
this.radioButton2.Location = new System.Drawing.Point(351, 29);
|
||||
this.radioButton2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.radioButton2.Name = "radioButton2";
|
||||
this.radioButton2.Size = new System.Drawing.Size(129, 24);
|
||||
this.radioButton2.TabIndex = 1;
|
||||
this.radioButton2.Text = "Use serial port";
|
||||
this.radioButton2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// optoSerialPortLabel
|
||||
//
|
||||
this.optoSerialPortLabel.AutoSize = true;
|
||||
this.optoSerialPortLabel.Location = new System.Drawing.Point(361, 69);
|
||||
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.optoSerialPortLabel.Name = "optoSerialPortLabel";
|
||||
this.optoSerialPortLabel.Size = new System.Drawing.Size(107, 20);
|
||||
this.optoSerialPortLabel.TabIndex = 6;
|
||||
this.optoSerialPortLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoSerialPortTextBox
|
||||
//
|
||||
this.optoSerialPortTextBox.Enabled = false;
|
||||
this.optoSerialPortTextBox.Location = new System.Drawing.Point(494, 65);
|
||||
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
|
||||
this.optoSerialPortTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.optoSerialPortTextBox.TabIndex = 7;
|
||||
//
|
||||
// groupTextBox
|
||||
//
|
||||
this.groupTextBox.Enabled = false;
|
||||
this.groupTextBox.Location = new System.Drawing.Point(172, 121);
|
||||
this.groupTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.groupTextBox.Name = "groupTextBox";
|
||||
this.groupTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.groupTextBox.TabIndex = 22;
|
||||
//
|
||||
// groupLabel
|
||||
//
|
||||
this.groupLabel.AutoSize = true;
|
||||
this.groupLabel.Location = new System.Drawing.Point(7, 126);
|
||||
this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.groupLabel.Name = "groupLabel";
|
||||
this.groupLabel.Size = new System.Drawing.Size(67, 20);
|
||||
this.groupLabel.TabIndex = 21;
|
||||
this.groupLabel.Text = "Group 2";
|
||||
//
|
||||
// muxBoardNrTextBox
|
||||
//
|
||||
this.muxBoardNrTextBox.Enabled = false;
|
||||
this.muxBoardNrTextBox.Location = new System.Drawing.Point(172, 86);
|
||||
this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.muxBoardNrTextBox.Name = "muxBoardNrTextBox";
|
||||
this.muxBoardNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.muxBoardNrTextBox.TabIndex = 20;
|
||||
//
|
||||
// muxBoardNrLabel
|
||||
//
|
||||
this.muxBoardNrLabel.AutoSize = true;
|
||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(7, 90);
|
||||
this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(159, 20);
|
||||
this.muxBoardNrLabel.TabIndex = 19;
|
||||
this.muxBoardNrLabel.Text = "Group 1 (mux. board)";
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(172, 50);
|
||||
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(180, 26);
|
||||
this.nameTextBox.TabIndex = 17;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(7, 55);
|
||||
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(51, 20);
|
||||
this.nameLabel.TabIndex = 16;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(168, 14);
|
||||
this.classNameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(90, 20);
|
||||
this.classNameLabel.TabIndex = 15;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 29);
|
||||
this.tabPage2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage2.Size = new System.Drawing.Size(679, 507);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Test";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// GenesisCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tabControl1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.Name = "GenesisCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(694, 548);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPage1.ResumeLayout(false);
|
||||
this.tabPage1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.optoDataGroupBox.ResumeLayout(false);
|
||||
this.optoDataGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.CheckBox checkBox_EnableShowChanels;
|
||||
|
||||
private System.Windows.Forms.Label labelFlush;
|
||||
private System.Windows.Forms.TextBox tBBeginDataFlush;
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControl1;
|
||||
private System.Windows.Forms.TabPage tabPage1;
|
||||
|
||||
@ -110,6 +110,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
Flush = 0,
|
||||
ProcessAndSave,
|
||||
CalculateStoredData,
|
||||
}
|
||||
|
||||
public enum CommunicationInterface
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -13,46 +13,29 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class CliRunner
|
||||
{
|
||||
//static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
|
||||
private readonly ILog log;
|
||||
private List<Task> taskPool = new List<Task>();
|
||||
private long startTime;
|
||||
private long incommingTime;
|
||||
|
||||
public List<Task> TaskPool { get { return taskPool; } }
|
||||
public void AddTask(Task task) { taskPool.Add(task); }
|
||||
public void WaitAll() { Task.WaitAll(taskPool.ToArray()); }
|
||||
public void Clear() { taskPool.Clear(); }
|
||||
public void CancelAll() { Task.WhenAll(taskPool).ContinueWith(t => { }); }
|
||||
private readonly List<CliTaskInfo> taskPool = new List<CliTaskInfo>();
|
||||
private long startTimeMs;
|
||||
private long incommingTimeMs;
|
||||
|
||||
public void StartAll()
|
||||
public List<CliTaskInfo> TaskPool
|
||||
{
|
||||
taskPool.ForEach(t => t.Start());
|
||||
}
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
return taskPool.All(task => task.IsCompleted);
|
||||
get { return taskPool; }
|
||||
}
|
||||
|
||||
public long StartTime
|
||||
{
|
||||
get => startTime;
|
||||
get { return startTimeMs; }
|
||||
}
|
||||
|
||||
public long IncommingTime
|
||||
{
|
||||
get => incommingTime;
|
||||
get { return incommingTimeMs; }
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeout)
|
||||
{
|
||||
return (DateTime.Now.Ticks - startTime) > timeout;
|
||||
}
|
||||
|
||||
public CliRunner(bool isCliLogging)
|
||||
{
|
||||
startTime = DateTime.Now.Ticks;
|
||||
ResetStartTime();
|
||||
|
||||
if (isCliLogging)
|
||||
{
|
||||
@ -60,88 +43,180 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||
@"C:\TBF\Logs\CliRunner.txt",
|
||||
10, // maxFileSizeMB
|
||||
7, // maxBackups
|
||||
10,
|
||||
7,
|
||||
log4net.Core.Level.Debug,
|
||||
true, // zipRolledFiles
|
||||
true, // singleZipPerDay
|
||||
TimeSpan.FromMinutes(2) // zipScanInterval
|
||||
true,
|
||||
true,
|
||||
TimeSpan.FromMinutes(2)
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fallback to console or handle gracefully
|
||||
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
||||
public void ResetStartTime()
|
||||
{
|
||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
startTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
}
|
||||
|
||||
public void AddSendAsync(string fileName, string args)
|
||||
{
|
||||
var task = SendAsync(fileName, args);
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args, CancellationToken ct = default)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
process.Start();
|
||||
|
||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (!process.HasExited)
|
||||
try
|
||||
{
|
||||
item?.Cts?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
try
|
||||
{
|
||||
if (item?.Process != null)
|
||||
{
|
||||
item.Process.Dispose();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//comming answer from serial port - good place for time stamp
|
||||
incommingTime = DateTime.Now.Ticks;
|
||||
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
|
||||
log?.Debug(allOutput);
|
||||
return allOutput;
|
||||
taskPool.Clear();
|
||||
}
|
||||
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
||||
public void WaitAll()
|
||||
{
|
||||
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
var tasks = taskPool
|
||||
.Where(t => t != null && t.Task != null)
|
||||
.Select(t => t.Task)
|
||||
.ToArray();
|
||||
|
||||
if (tasks.Length == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
RefreshTaskStates();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CancellationToken ct = default) where T : new()
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
RefreshTaskStates();
|
||||
return taskPool.Count > 0 && taskPool.All(t => t.State != CliTaskState.Running);
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeoutMs)
|
||||
{
|
||||
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
return (nowMs - startTimeMs) > timeoutMs;
|
||||
}
|
||||
|
||||
public void RefreshTaskStates()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
if (item == null || item.Task == null)
|
||||
continue;
|
||||
|
||||
if (item.State == CliTaskState.TimedOut)
|
||||
continue;
|
||||
|
||||
if (!item.Task.IsCompleted)
|
||||
{
|
||||
item.State = CliTaskState.Running;
|
||||
}
|
||||
else if (item.Task.IsCanceled)
|
||||
{
|
||||
item.State = CliTaskState.Canceled;
|
||||
}
|
||||
else if (item.Task.IsFaulted)
|
||||
{
|
||||
item.State = CliTaskState.Faulted;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.State = CliTaskState.Completed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelUndoneTasksAsTimedOut()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
if (item == null || item.Task == null)
|
||||
continue;
|
||||
|
||||
if (item.Task.IsCompleted)
|
||||
{
|
||||
if (item.Task.IsCanceled)
|
||||
item.State = CliTaskState.Canceled;
|
||||
else if (item.Task.IsFaulted)
|
||||
item.State = CliTaskState.Faulted;
|
||||
else
|
||||
item.State = CliTaskState.Completed;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
item.State = CliTaskState.TimedOut;
|
||||
|
||||
try
|
||||
{
|
||||
item.Cts?.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Warn("Cancel token failed", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (item.Process != null && !item.Process.HasExited)
|
||||
{
|
||||
item.Process.Kill();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Warn("Kill process failed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
||||
{
|
||||
AddSendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
}
|
||||
|
||||
public void AddSendAsync(string fileName, string args)
|
||||
{
|
||||
ResetStartTime();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var info = new CliTaskInfo
|
||||
{
|
||||
Cts = cts,
|
||||
Name = "SendAsync"
|
||||
};
|
||||
|
||||
var task = SendAsync(fileName, args, info, cts.Token);
|
||||
info.Task = task;
|
||||
taskPool.Add(info);
|
||||
}
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args, CliTaskInfo info, CancellationToken ct = default)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
@ -153,80 +228,210 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
process.Start();
|
||||
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||
{
|
||||
info.Process = process;
|
||||
|
||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
|
||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
|
||||
log?.Debug(allOutput);
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (info.State != CliTaskState.TimedOut)
|
||||
info.State = CliTaskState.Canceled;
|
||||
|
||||
string json = ExtractJson(allOutput);
|
||||
if (TryJsonStringDeserialize(json, out T result)) return result;
|
||||
return default;
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
|
||||
log?.Debug(allOutput);
|
||||
|
||||
info.State = CliTaskState.Completed;
|
||||
return allOutput;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.State = CliTaskState.Faulted;
|
||||
log?.Error("SendAsync failed", ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
info.Process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T runAndCaptureJsonAsync) where T : new()
|
||||
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
||||
{
|
||||
AddRunAndCaptureJsonAsync<T>(
|
||||
data.SerialPortCmdClientPath,
|
||||
data.DefaultArgSettings(eMeterArg));
|
||||
}
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
|
||||
{
|
||||
ResetStartTime();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var info = new CliTaskInfo
|
||||
{
|
||||
Cts = cts,
|
||||
Name = $"RunAndCaptureJsonAsync<{typeof(T).Name}>"
|
||||
};
|
||||
|
||||
var task = RunAndCaptureJsonAsync<T>(fileName, args, info, cts.Token);
|
||||
|
||||
info.Task = task;
|
||||
taskPool.Add(info);
|
||||
}
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CliTaskInfo info, CancellationToken ct = default) where T : new()
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||
{
|
||||
info.Process = process;
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (info.State != CliTaskState.TimedOut)
|
||||
info.State = CliTaskState.Canceled;
|
||||
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
|
||||
log?.Debug(allOutput);
|
||||
|
||||
string json = ExtractJson(allOutput);
|
||||
T result;
|
||||
if (TryJsonStringDeserialize(json, out result))
|
||||
{
|
||||
info.State = CliTaskState.Completed;
|
||||
return result;
|
||||
}
|
||||
|
||||
info.State = CliTaskState.Completed;
|
||||
return default(T);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.State = CliTaskState.Faulted;
|
||||
log?.Error("RunAndCaptureJsonAsync failed", ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
info.Process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T value) where T : new()
|
||||
{
|
||||
if (json != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
|
||||
value = JsonConvert.DeserializeObject<T>(json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Debug(ex.Message);
|
||||
runAndCaptureJsonAsync = TryConvert<T>(json);
|
||||
log?.Debug(ex.Message);
|
||||
value = TryConvert<T>(json);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
runAndCaptureJsonAsync = default;
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static T TryConvert<T>(string json) where T : new()
|
||||
{
|
||||
|
||||
T obj = new T();
|
||||
T obj = new T();
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
JObject jObject = JObject.Parse(json);
|
||||
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
JObject jObject = JObject.Parse(json);
|
||||
if (!prop.CanWrite)
|
||||
continue;
|
||||
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
{
|
||||
if (!prop.CanWrite) continue;
|
||||
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
try
|
||||
{
|
||||
object value = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
object value = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// leave default if conversion fails
|
||||
}
|
||||
}
|
||||
// else → keep default value
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public string ExtractJson(string text)
|
||||
@ -241,6 +446,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void AddTaskForTest(Task task, string name = "TestTask", CancellationTokenSource cts = null)
|
||||
{
|
||||
taskPool.Add(new CliTaskInfo
|
||||
{
|
||||
Task = task,
|
||||
Cts = cts,
|
||||
Name = name,
|
||||
State = task.IsCompleted
|
||||
? (task.IsCanceled ? CliTaskState.Canceled :
|
||||
task.IsFaulted ? CliTaskState.Faulted :
|
||||
CliTaskState.Completed)
|
||||
: CliTaskState.Running
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
25
TBF/Rig/RegisterReaders/PoseidonCmdStartStop/CliTaskInfo.cs
Normal file
25
TBF/Rig/RegisterReaders/PoseidonCmdStartStop/CliTaskInfo.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class CliTaskInfo
|
||||
{
|
||||
public Task Task { get; set; }
|
||||
public CancellationTokenSource Cts { get; set; }
|
||||
public Process Process { get; set; }
|
||||
public CliTaskState State { get; set; } = CliTaskState.Running;
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool UseResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return State == CliTaskState.Completed
|
||||
&& Task != null
|
||||
&& Task.Status == TaskStatus.RanToCompletion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
TBF/Rig/RegisterReaders/PoseidonCmdStartStop/CliTaskState.cs
Normal file
13
TBF/Rig/RegisterReaders/PoseidonCmdStartStop/CliTaskState.cs
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public enum CliTaskState
|
||||
{
|
||||
Running,
|
||||
Completed,
|
||||
TimedOut,
|
||||
Canceled,
|
||||
Faulted
|
||||
}
|
||||
|
||||
}
|
||||
@ -336,10 +336,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
/// for debug purposes what time will consume answer
|
||||
/// </summary>
|
||||
private long startTimeInMilis = -1, fullTimeInMilis = -1;
|
||||
/// 30 seconds
|
||||
private static long SafetyTimeOut = 30 * 1000;
|
||||
private long incommingTime = -1;
|
||||
private bool _lastOpTimedOut;
|
||||
|
||||
|
||||
/// 30 seconds
|
||||
|
||||
public long DeltaTime { get{return fullTimeInMilis;}}
|
||||
public long IncommingTime { get{return incommingTime;}}
|
||||
@ -356,108 +358,146 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
|
||||
{
|
||||
CliRunner.Clear();
|
||||
_lastOpTimedOut = false;
|
||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
return Event.Busy;
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Runing;
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
|
||||
{
|
||||
if (CliRunner.AreTasksDone()
|
||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
if (CliRunner.AreTasksDone())
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
||||
}
|
||||
return Event.Busy;
|
||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_lastOpTimedOut = true;
|
||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
||||
}
|
||||
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Done)
|
||||
{
|
||||
var firstTask = CliRunner.TaskPool.FindLast(t => t is Task<string>);
|
||||
var firstTaskInfo = CliRunner.TaskPool
|
||||
.FindLast(t => t.Task is Task<string> && t.UseResult);
|
||||
|
||||
|
||||
if (firstTask != null && firstTask is Task<string>)
|
||||
if (firstTaskInfo != null)
|
||||
{
|
||||
string data = null;
|
||||
data = (firstTask as Task<string>).Result;
|
||||
var task = (Task<string>)firstTaskInfo.Task;
|
||||
string data = task.Result;
|
||||
|
||||
if (data != null && TryGetDeviceId(data, out wmSerialNr))
|
||||
if (!string.IsNullOrEmpty(data))
|
||||
{
|
||||
|
||||
TryGetDeviceId(data, out wmSerialNr);
|
||||
}
|
||||
}
|
||||
else if (_lastOpTimedOut)
|
||||
{
|
||||
log.Warn(
|
||||
$"PoseidonReader {Name}: SendStartDataStream timed out, no completed result will be used.");
|
||||
}
|
||||
|
||||
_currentOp = CurrentPoseidonOp.Done;
|
||||
CliRunner.Clear();
|
||||
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||
return Event.Done;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
||||
{
|
||||
startTimeInMilis = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
|
||||
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
incommingTime = -1;
|
||||
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
|
||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
|
||||
CliRunner.Clear();
|
||||
_lastOpTimedOut = false;
|
||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
|
||||
return Event.Busy;
|
||||
}else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||
{
|
||||
if (CliRunner.AreTasksDone()
|
||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
if (CliRunner.AreTasksDone())
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||
//set time stamp - end of reading
|
||||
incommingTime = CliRunner.IncommingTime;
|
||||
}
|
||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_lastOpTimedOut = true;
|
||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||
incommingTime = CliRunner.IncommingTime;
|
||||
}
|
||||
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
|
||||
{
|
||||
fullTimeInMilis = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - startTimeInMilis;
|
||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis} ");
|
||||
JsonDataFromPoseidon data = null;
|
||||
var first = CliRunner.TaskPool.FindLast(t => t is Task<JsonDataFromPoseidon>);
|
||||
if (first != null && first is Task<JsonDataFromPoseidon>)
|
||||
{
|
||||
data = (first as Task<JsonDataFromPoseidon>).Result;
|
||||
fullTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTimeInMilis;
|
||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis}");
|
||||
|
||||
//GET serial number
|
||||
JsonDataFromPoseidon data = null;
|
||||
|
||||
var firstTaskInfo = CliRunner.TaskPool
|
||||
.FindLast(t => t.Task is Task<JsonDataFromPoseidon> && t.UseResult);
|
||||
|
||||
if (firstTaskInfo != null)
|
||||
{
|
||||
var task = (Task<JsonDataFromPoseidon>)firstTaskInfo.Task;
|
||||
data = task.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_lastOpTimedOut)
|
||||
{
|
||||
log.Warn($"PoseidonReader {Name}: ReadDatastream timed out, no completed result available.");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Warn("No completed JsonDataFromPoseidon task available.");
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(wmSerialNr))
|
||||
{
|
||||
try
|
||||
{
|
||||
wmSerialNr = data?.DeviceId ?? wmSerialNr;
|
||||
wmSerialNr = data.DeviceId ?? wmSerialNr;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Serial Nr - parse error!");
|
||||
log.Error("Serial Nr - parse error!", e);
|
||||
}
|
||||
}
|
||||
|
||||
//GET volume
|
||||
if (data != null && Double.TryParse(data.Reading, out double Volume))
|
||||
double volume;
|
||||
if (Double.TryParse(data.Reading, out volume))
|
||||
{
|
||||
double VolumeLi = Units.ConvertFrom(Unit.USgal, Volume);
|
||||
//double VolumeM3 = Units.ConvertTo(Unit.m3, VolumeLi);
|
||||
if (_isReadingStart)
|
||||
{
|
||||
//volume
|
||||
beginWMState = VolumeLi;
|
||||
}
|
||||
else
|
||||
{
|
||||
//volume
|
||||
endWMState = VolumeLi;
|
||||
}
|
||||
}
|
||||
double volumeLi = Units.ConvertFrom(Unit.USgal, volume);
|
||||
|
||||
if (_isReadingStart)
|
||||
beginWMState = volumeLi;
|
||||
else
|
||||
endWMState = volumeLi;
|
||||
}
|
||||
}
|
||||
|
||||
//Finish reading and loop
|
||||
_currentOp = CurrentPoseidonOp.Done;
|
||||
|
||||
CliRunner.Clear();
|
||||
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||
return Event.Done;
|
||||
}
|
||||
|
||||
return Event.None;
|
||||
|
||||
return Event.None;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
@ -1276,22 +1276,49 @@ namespace TBF.Rig.Sequences
|
||||
|
||||
var smryItems = DEItem.GetSummaryColumns();
|
||||
|
||||
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
|
||||
for (int i = 0; i < BatchRslts.Batch.WaterMeters.Count; i++)
|
||||
{
|
||||
if (BatchRslts.Batch.WaterMeters != null &&
|
||||
if (BatchRslts.Batch.WaterMeters != null &&
|
||||
BatchRslts.Batch.WaterMeters.Count > i &&
|
||||
BatchRslts.Batch.WaterMeters[i] != null &&
|
||||
!BatchRslts.Batch.WaterMeters[i].Disabled)
|
||||
BatchRslts.Batch.WaterMeters[i] != null)
|
||||
{
|
||||
bool Disabled = BatchRslts.Batch.WaterMeters[i].Disabled;
|
||||
bool bChanel = false;
|
||||
if (Disabled &&
|
||||
BatchRslts.Batch.WaterMeters[i].SerialNr != null &&
|
||||
BatchRslts.Batch.WaterMeters[i].SerialNr.Contains("_CH")) //write channels
|
||||
{
|
||||
Disabled = false;
|
||||
bChanel = true;
|
||||
}
|
||||
|
||||
if (Disabled)
|
||||
continue;
|
||||
|
||||
var wm = BatchRslts.Batch.WaterMeters[i];
|
||||
|
||||
if (!wm.Compound() && !wm.HeatMeter())
|
||||
{
|
||||
/// If this is a single meter
|
||||
|
||||
Results.Entities.MeterTestRslt mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.Single);
|
||||
Results.Entities.MeterTestRslt mtrRslt = null;
|
||||
bool wmDisabled = wm.Disabled;
|
||||
try
|
||||
{
|
||||
wm.Disabled = false;
|
||||
if (!bChanel)
|
||||
mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.Single);
|
||||
else
|
||||
{
|
||||
mtrRslt = wm.GetMeterTestRslt(tstRslt.Name(), CompoundMeterId.Single);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
finally
|
||||
{
|
||||
wm.Disabled = wmDisabled;
|
||||
}
|
||||
|
||||
if (mtrRslt != null)
|
||||
if (mtrRslt != null)
|
||||
{
|
||||
bool isCamera = (mtrRslt.RegReaderType == (int)RegisterReaderType.Camera);
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ using TBF.Rig.GenericDevices;
|
||||
using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
using TBF.Rig.TestMethods.GenesisCommunication.GenesisHead;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
using TBF.UiBridge;
|
||||
|
||||
namespace TBF.Rig.TestMethods.FlyingStart
|
||||
@ -329,6 +330,9 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
|
||||
temperature_set:
|
||||
|
||||
|
||||
|
||||
|
||||
//TODO genesis - check with genesis switch
|
||||
if (atleastOneGenesis)
|
||||
{
|
||||
@ -379,18 +383,26 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
IList<IOperation> cameraMeasurementOps = new List<IOperation>();
|
||||
foreach (var camera in cameras) cameraMeasurementOps.Add(camera.MeasurementOp());
|
||||
|
||||
foreach (var rr in sensPath.RegisterReaders)
|
||||
{
|
||||
if (rr is IRegReaderDatastream)
|
||||
(rr as IRegReaderDatastream).TestIsGoingToStartSoon(test, repetitionNr);
|
||||
|
||||
if (rr is GenesisHead) // Genesis - CORDONEL head
|
||||
(rr as GenesisHead).StartRead(test.Name, BatchRslts.Batch.BatchNr, repetitionNr);
|
||||
|
||||
}
|
||||
/// Prepare datastream read operations
|
||||
IList<IOperation> readDatastreamOps = new List<IOperation>();
|
||||
if (sensPath != null && sensPath.RegisterReaders != null)
|
||||
{
|
||||
foreach (var rr in sensPath.RegisterReaders)
|
||||
{
|
||||
if (rr is IRegReaderDatastream datastreamRR)
|
||||
{
|
||||
(datastreamRR).TestIsGoingToStartSoon(test, repetitionNr);
|
||||
readDatastreamOps.Add(datastreamRR.ReadDatastreamOp());
|
||||
}
|
||||
|
||||
if (rr is GenesisHead) // Genesis - CORDONEL head
|
||||
(rr as GenesisHead).StartRead(test.Name, BatchRslts.Batch.BatchNr, repetitionNr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------
|
||||
//------------------------------------------------
|
||||
Bridge.OnActivity(this, Strings.Test_in_progress);
|
||||
//------------------------------------------------
|
||||
|
||||
@ -403,6 +415,7 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
State.Create(string.Format("{0}({1}) : FlyingStartStopTestOp is running", test.Method, test.Name))
|
||||
.AddOperation(checkUiOp)
|
||||
.AddOperations(readTempPressOps)
|
||||
.AddOperations(readDatastreamOps)
|
||||
.AddOperations(cameraMeasurementOps)
|
||||
.AddOperation(cBrd.FlyingStartStopTestOp(test, test.QfromM3ph(), test.QtoM3ph(), totalPulses))
|
||||
.AddOperation(processDataLoggingOp)
|
||||
@ -454,6 +467,21 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
|
||||
/// Measurement loop end
|
||||
StopRecordingStatistics();
|
||||
|
||||
/// call StopDataStreamProcessing
|
||||
if (sensPath != null && sensPath.RegisterReaders != null)
|
||||
{
|
||||
foreach (var rr in sensPath.RegisterReaders)
|
||||
{
|
||||
var datastreamRR = rr as ISmartReader;
|
||||
if (datastreamRR != null)
|
||||
{
|
||||
datastreamRR.StopDataStreamProcessing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO genesis - check with genesis switch
|
||||
if (atleastOneGenesis)
|
||||
|
||||
@ -8,11 +8,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml.Serialization;
|
||||
using Results.Entities;
|
||||
using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
using TBF.Rig;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
@ -607,6 +610,11 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
}
|
||||
while (!e.Contains(Event.TestCompleted) && !e.Contains(Event.Next)); /// 'Next' button is enabled in Debug version only
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------
|
||||
Bridge.OnActivity(this, Strings.Test_in_calculation);
|
||||
//------------------------------------------------
|
||||
/// Measurement loop end
|
||||
StopRecordingStatistics();
|
||||
|
||||
@ -968,6 +976,7 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bUpgradeCountOfMeters = false;
|
||||
///
|
||||
/// Single meters
|
||||
///
|
||||
@ -982,6 +991,7 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = regReader as TestMethods.iPerlCommunication.iPerlHead.IperlHead;
|
||||
GenericDevices.IRegReaderLiveCamera cameraRoi = regReader as GenericDevices.IRegReaderLiveCamera;
|
||||
TestMethods.GenesisCommunication.GenesisHead.GenesisHead Genesis = regReader as TestMethods.GenesisCommunication.GenesisHead.GenesisHead;
|
||||
TBF.Rig.RegisterReaders.GenesisRegReader.implementations.GenesisSmartReader GenesisSmart = regReader as TBF.Rig.RegisterReaders.GenesisRegReader.implementations.GenesisSmartReader;
|
||||
|
||||
if (meterRslt != null && regReader != null)
|
||||
{
|
||||
@ -1070,6 +1080,23 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
var calError = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, meterRslt.VolumeRef);
|
||||
Genesis.Log(" MeterError = " + calError.ToString() + " %");
|
||||
|
||||
}
|
||||
else if (GenesisSmart != null)
|
||||
{
|
||||
log.Debug("GenesisSmart - store data on end!");
|
||||
bUpgradeCountOfMeters = true;
|
||||
int CH1=0, CH2=1, CH3=2;
|
||||
|
||||
//BatchRslts.Batch.WaterMeters.Add(ch1WaterMeter); //[i + BatchRslts.WMPositionsCount + CH1 + 1]
|
||||
//BatchRslts.Batch.WaterMeters.Add(ch1WaterMeter); //[i + BatchRslts.WMPositionsCount + CH2 + 1]
|
||||
//BatchRslts.Batch.WaterMeters.Add(ch1WaterMeter); //[i + BatchRslts.WMPositionsCount + CH3 + 1]
|
||||
|
||||
CalculateMeterResults(meterRslt, GenesisSmart, tstRslt,GenesisSmart.TimestampSecStart, GenesisSmart.TimestampSecEnd, GenesisSmart.VolumeLtrStart, GenesisSmart.VolumeLtrEnd);
|
||||
|
||||
WaterMeterParentCopy(i, CH1,testName,meterRslt,GenesisSmart,tstRslt);
|
||||
WaterMeterParentCopy(i, CH2,testName,meterRslt,GenesisSmart,tstRslt);
|
||||
WaterMeterParentCopy(i, CH3,testName,meterRslt,GenesisSmart,tstRslt);
|
||||
|
||||
}
|
||||
else if (dstrReader != null)
|
||||
{
|
||||
@ -1254,7 +1281,15 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (bUpgradeCountOfMeters)
|
||||
{
|
||||
//TODO remove test!!
|
||||
//BatchRslts.WMPositionsCount = BatchRslts.WMPositionsCount + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
tstRslt.Components = Results.Entities.Components.UpdateList(BatchRslts.ComponentsList,
|
||||
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
||||
@ -1313,6 +1348,98 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
return new List<Event> { retVal };
|
||||
}
|
||||
|
||||
private const int CountCh = 3;
|
||||
private static void WaterMeterParentCopy(int i, int iCH, string testName, MeterTestRslt meterRslt,
|
||||
GenesisSmartReader genesisSmart,
|
||||
TestRslt tstRslt)
|
||||
{
|
||||
WaterMeter waterMeterParent = BatchRslts.Batch.WaterMeters[i];
|
||||
int wmNrChX = (i*CountCh) + BatchRslts.WMPositionsCount + iCH + 1;
|
||||
String sSerialNr = waterMeterParent.SerialNr + "_CH" + (iCH + 1);
|
||||
WaterMeter chXWaterMeter = null;
|
||||
//------ add new water meter to batch ------
|
||||
if (BatchRslts.Batch.WaterMeters.Count < wmNrChX || BatchRslts.Batch.WaterMeters[wmNrChX-1] == null)
|
||||
{
|
||||
log.Debug("add new water meter to batch, CH = " + (iCH + 1) + " CH = " + wmNrChX);
|
||||
chXWaterMeter = new WaterMeter()
|
||||
{
|
||||
Batch = BatchRslts.Batch,
|
||||
WaterMeterData = waterMeterParent.WaterMeterData,
|
||||
MeterTestRslts = new List<MeterTestRslt>(),
|
||||
SerialNr = sSerialNr,
|
||||
WMPosition = wmNrChX,
|
||||
YearOfProduction = 0,
|
||||
Disabled = false,
|
||||
};
|
||||
chXWaterMeter.CopyContentFrom(waterMeterParent);
|
||||
|
||||
chXWaterMeter.SerialNr = sSerialNr;
|
||||
chXWaterMeter.WMPosition = wmNrChX;
|
||||
chXWaterMeter.YearOfProduction = waterMeterParent.YearOfProduction;
|
||||
chXWaterMeter.Disabled = false;
|
||||
|
||||
BatchRslts.Batch.WaterMeters.Add(chXWaterMeter);
|
||||
}
|
||||
else
|
||||
{
|
||||
chXWaterMeter = BatchRslts.Batch.WaterMeters[wmNrChX-1];
|
||||
}
|
||||
//~------ add new water meter to batch ------~
|
||||
|
||||
//create copy of meterRslt and add to additionalResultsByChannel
|
||||
MeterTestRslt meterTestRsltChX = new MeterTestRslt(chXWaterMeter, meterRslt.TestRslt, (CompoundMeterId)meterRslt.CompoundMeterId);
|
||||
chXWaterMeter.MeterTestRslts.Add(meterTestRsltChX);
|
||||
MeterTestRslt chanelXMeterRslt = BatchRslts.GetMeterTestRslt(testName, wmNrChX-1, Common.CompoundMeterId.Single);
|
||||
|
||||
if (chanelXMeterRslt != null)
|
||||
{
|
||||
chanelXMeterRslt?.CopyContentFrom(meterRslt);
|
||||
if (iCH == 0)
|
||||
{
|
||||
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartRawCh1,
|
||||
genesisSmart.TimestampSecEndRawCh1, genesisSmart.VolumeLtrStartRawCh1, genesisSmart.VolumeLtrEndRawCh1);
|
||||
}
|
||||
else if (iCH == 1)
|
||||
{
|
||||
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartRawCh2,
|
||||
genesisSmart.TimestampSecEndRawCh2, genesisSmart.VolumeLtrStartRawCh2, genesisSmart.VolumeLtrEndRawCh2);
|
||||
}
|
||||
else if (iCH == 2)
|
||||
{
|
||||
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartRawCh3,
|
||||
genesisSmart.TimestampSecEndRawCh3, genesisSmart.VolumeLtrStartRawCh3, genesisSmart.VolumeLtrEndRawCh3);
|
||||
}
|
||||
|
||||
if (!genesisSmart.EnableShowChanels)
|
||||
{
|
||||
chXWaterMeter.Disabled = !genesisSmart.EnableShowChanels;
|
||||
meterTestRsltChX.TestDone = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
meterTestRsltChX.TestDone = true;
|
||||
}
|
||||
|
||||
meterTestRsltChX.Passed = meterRslt.Passed;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CalculateMeterResults(MeterTestRslt meterRslt, IRegReaderDatastream dstrReader, TestRslt tstRslt, double dstrReaderTimestampSecStart, double dstrReaderTimestampSecEnd, double dstrReaderVolumeLtrStart, double dstrReaderVolumeLtrEnd)
|
||||
{
|
||||
meterRslt.TimestampStart = dstrReaderTimestampSecStart;
|
||||
meterRslt.TimestampEnd = !dstrReader.NoSamples
|
||||
? dstrReaderTimestampSecEnd
|
||||
: (dstrReaderTimestampSecStart + tstRslt.TestTime);
|
||||
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
|
||||
meterRslt.VolumeStart = dstrReaderVolumeLtrStart; /// liter
|
||||
meterRslt.VolumeEnd = dstrReaderVolumeLtrEnd; /// liter
|
||||
meterRslt.VolumeMeter =
|
||||
Math.Abs(dstrReaderVolumeLtrEnd - dstrReaderVolumeLtrStart);
|
||||
meterRslt.VolumeRef = tstRslt.TestTime==0? tstRslt.VolumeCTV : tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster = tstRslt.TestTime == 0? tstRslt.PulsesMaster :
|
||||
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
}
|
||||
|
||||
|
||||
IList<Event> Simulate1(Config.Entities.Test test, int repetitionNr, bool isLastRepetition,
|
||||
Compound.CombinedTestParams compoundTestParams,
|
||||
|
||||
@ -110,7 +110,7 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
||||
ltrPerPulse = nominalFlow / (3.6 * nominalFreq); /// Nominal freq. is sum of particular nominal frquencies
|
||||
|
||||
log.FatalFormat("{0} initialized: {1} nom.flow={2} m3/h nom.freq={3} Hz bitfield=0x{4:X2}",
|
||||
Name, nominalFlow, nominalFreq, flowMetersBitfield);
|
||||
Name, true, nominalFlow, nominalFreq, flowMetersBitfield);
|
||||
}
|
||||
|
||||
public double ReadFlow()
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Common;
|
||||
using log4net;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.ControlBoard.Uni;
|
||||
@ -206,6 +207,11 @@ namespace TBF.Rig.Uni.RegValve
|
||||
public Event Run()
|
||||
{
|
||||
log.DebugFormat("Op.Run() opState={0}", opState);
|
||||
|
||||
if (this.uniCB?.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return Event.FlowReached;
|
||||
}
|
||||
|
||||
if (StateMachine.Time > expireTime) return Event.RegulValveTimeOut;
|
||||
|
||||
|
||||
@ -1494,6 +1494,8 @@
|
||||
<DependentUpon>RRCfgCtrl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunner.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliTaskInfo.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliTaskState.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\Factory.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\JsonDataFromPoseidon.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCfg.cs" />
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.communication;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||
@ -11,16 +11,52 @@ using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
|
||||
|
||||
|
||||
[TestClass]
|
||||
public class GenesisReaderTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void RealInput_ShouldCalculate_StartEndVolumes_AndTimes()
|
||||
|
||||
private static GenesisCfg CreateCfg()
|
||||
{
|
||||
var reader = new GenesisSmartReader();
|
||||
Factory factory = new Factory();
|
||||
return new GenesisCfg(factory);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Debug_ProcessOptoLine_FormatVariants()
|
||||
{
|
||||
var reader = new GenesisSmartReader(CreateCfg());
|
||||
InitializeReaderForTest(reader);
|
||||
|
||||
string[] variants =
|
||||
{
|
||||
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
"@he 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
"@he\t1\t0\t0A1F59C4\t00017A43\t00115C45\t72E1596B\t00000400\t00001998\t7D91B652\t7D4F37E6\t000191E6\t0C\t062E4A9C\t5331",
|
||||
"@he \t1\t0\t0A1F59C4\t00017A43\t00115C45\t72E1596B\t00000400\t00001998\t7D91B652\t7D4F37E6\t000191E6\t0C\t062E4A9C\t5331"
|
||||
};
|
||||
|
||||
int[] counts = new int[variants.Length];
|
||||
|
||||
for (int i = 0; i < variants.Length; i++)
|
||||
{
|
||||
bool blockCompleted = false;
|
||||
reader.ProcessOptoLine(variants[i], DataStreamState.ProcessAndSave, out blockCompleted);
|
||||
|
||||
counts[i] = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
Console.WriteLine($"Variant {i}: {variants[i]}");
|
||||
Console.WriteLine($" blockCompleted={blockCompleted}");
|
||||
Console.WriteLine($" optoDataCount={counts[i]}");
|
||||
Console.WriteLine("--------------------------------");
|
||||
}
|
||||
|
||||
Assert.IsTrue(counts.Any(c => c > 0), "At least one telegram format variant should be accepted.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RealInput_ShouldParseCalibrationTelegrams()
|
||||
{
|
||||
var reader = new GenesisSmartReader(CreateCfg());
|
||||
InitializeReaderForTest(reader);
|
||||
|
||||
string[] realInputLines = LoadRealInputLines();
|
||||
@ -30,12 +66,35 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
int firstValidIx = -1;
|
||||
int lastValidIx = -1;
|
||||
|
||||
foreach (var line in realInputLines)
|
||||
Console.WriteLine("=== BEGIN INPUT PARSING ===");
|
||||
|
||||
for (int i = 0; i < realInputLines.Length; i++)
|
||||
{
|
||||
bool blockCompleted;
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out blockCompleted);
|
||||
string line = realInputLines[i];
|
||||
|
||||
bool blockCompleted = false;
|
||||
Exception parseException = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out blockCompleted);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parseException = ex;
|
||||
}
|
||||
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
Console.WriteLine($"[{i}] line = {line}");
|
||||
Console.WriteLine($"[{i}] blockCompleted = {blockCompleted}");
|
||||
Console.WriteLine($"[{i}] optoDataCount = {optoDataCount}");
|
||||
|
||||
if (parseException != null)
|
||||
{
|
||||
Console.WriteLine($"[{i}] EXCEPTION = {parseException.GetType().Name}: {parseException.Message}");
|
||||
}
|
||||
|
||||
if (optoDataCount > processedCount)
|
||||
{
|
||||
if (firstValidIx < 0)
|
||||
@ -43,70 +102,89 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
lastValidIx = optoDataCount - 1;
|
||||
processedCount = optoDataCount;
|
||||
|
||||
Console.WriteLine(
|
||||
$"[{i}] ACCEPTED -> processedCount={processedCount}, firstValidIx={firstValidIx}, lastValidIx={lastValidIx}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[{i}] NOT ACCEPTED");
|
||||
}
|
||||
|
||||
Console.WriteLine("--------------------------------------------------");
|
||||
}
|
||||
|
||||
Assert.IsTrue(processedCount > 0, "No valid calibration telegrams were parsed.");
|
||||
Console.WriteLine("=== END INPUT PARSING ===");
|
||||
Console.WriteLine($"Final processedCount = {processedCount}");
|
||||
Console.WriteLine($"Final firstValidIx = {firstValidIx}");
|
||||
Console.WriteLine($"Final lastValidIx = {lastValidIx}");
|
||||
|
||||
Assert.AreEqual(3, processedCount, "Expected all 3 calibration telegrams to be parsed.");
|
||||
Assert.AreEqual(0, firstValidIx);
|
||||
Assert.AreEqual(2, lastValidIx);
|
||||
|
||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||
Assert.IsNotNull(optoData);
|
||||
|
||||
Assert.AreEqual(0, optoData[0].IChannel());
|
||||
Assert.AreEqual(1, optoData[1].IChannel());
|
||||
Assert.AreEqual(2, optoData[2].IChannel());
|
||||
|
||||
// With only one telegram per channel, full start/end reconstruction is not expected yet.
|
||||
reader.TestStartTelegramIx = firstValidIx;
|
||||
reader.TestEndTelegramIx = lastValidIx;
|
||||
|
||||
object[] markArgs = { 0, 0 };
|
||||
InvokePrivate(reader, "AddTestStartEndMarksToData", markArgs);
|
||||
InvokePrivate(reader, "AddTestStartEndMarksToData", new object[] { 0, 0 });
|
||||
InvokePrivate(reader, "DataStreamPostProcessing");
|
||||
InvokePrivate(reader, "PrepareCalculatedChannelData");
|
||||
|
||||
// first run: inspect values from debugger/log/output and then replace
|
||||
Console.WriteLine($"VolumeLtrStart={reader.VolumeLtrStart}");
|
||||
Console.WriteLine($"VolumeLtrEnd={reader.VolumeLtrEnd}");
|
||||
Console.WriteLine($"TimestampSecStart={reader.TimestampSecStart}");
|
||||
Console.WriteLine($"TimestampSecEnd={reader.TimestampSecEnd}");
|
||||
|
||||
const double expectedVolumeStart = 0.0; // replace with real value
|
||||
const double expectedVolumeEnd = 0.0; // replace with real value
|
||||
const double expectedTimeStart = 0.0; // replace with real value
|
||||
const double expectedTimeEnd = 0.0; // replace with real value
|
||||
|
||||
const double tolerance = 0.000001;
|
||||
|
||||
Assert.AreEqual(expectedVolumeStart, reader.VolumeLtrStart, tolerance, "VolumeLtrStart mismatch");
|
||||
Assert.AreEqual(expectedVolumeEnd, reader.VolumeLtrEnd, tolerance, "VolumeLtrEnd mismatch");
|
||||
Assert.AreEqual(expectedTimeStart, reader.TimestampSecStart, tolerance, "TimestampSecStart mismatch");
|
||||
Assert.AreEqual(expectedTimeEnd, reader.TimestampSecEnd, tolerance, "TimestampSecEnd mismatch");
|
||||
Assert.IsTrue(reader.NoSamples,
|
||||
"With only one telegram per channel, recalculated start/end samples should still be unavailable.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RealInput_ShouldSupport_RolloverNormalization()
|
||||
public void RealInput_ShouldParseRolloverInputLines()
|
||||
{
|
||||
var reader = new GenesisSmartReader();
|
||||
var reader = new GenesisSmartReader(CreateCfg());
|
||||
InitializeReaderForTest(reader);
|
||||
|
||||
string[] realInputLines = LoadRealInputLinesWithRollover();
|
||||
Assert.IsTrue(realInputLines.Length > 0, "No rollover input lines were provided.");
|
||||
|
||||
foreach (var line in realInputLines)
|
||||
for (int i = 0; i < realInputLines.Length; i++)
|
||||
{
|
||||
string line = realInputLines[i];
|
||||
|
||||
bool blockCompleted;
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out blockCompleted);
|
||||
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
Console.WriteLine($"[{i}] line={line}");
|
||||
Console.WriteLine($"[{i}] optoDataCount={optoDataCount}, blockCompleted={blockCompleted}");
|
||||
}
|
||||
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
Assert.IsTrue(optoDataCount > 1, "Need at least 2 valid telegrams.");
|
||||
int finalOptoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
reader.TestStartTelegramIx = 0;
|
||||
reader.TestEndTelegramIx = optoDataCount - 1;
|
||||
|
||||
object[] markArgs = { 0, 0 };
|
||||
InvokePrivate(reader, "AddTestStartEndMarksToData", markArgs);
|
||||
InvokePrivate(reader, "DataStreamPostProcessing");
|
||||
InvokePrivate(reader, "PrepareCalculatedChannelData");
|
||||
|
||||
Assert.IsTrue(reader.TimestampSecEnd >= reader.TimestampSecStart,
|
||||
"Normalized end time should be >= start time");
|
||||
Assert.IsTrue(reader.VolumeLtrEnd >= reader.VolumeLtrStart,
|
||||
"Normalized end volume should be >= start volume");
|
||||
Assert.AreEqual(3, finalOptoDataCount,
|
||||
"Expected all provided rollover input lines to be parsed as telegrams.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PrepareCalculatedChannelDataSimulationForTest_ShouldProduceUsableSamples()
|
||||
{
|
||||
var reader = new GenesisSmartReader(CreateCfg());
|
||||
InitializeReaderForTest(reader);
|
||||
|
||||
reader.PrepareCalculatedChannelDataSimulationForTest();
|
||||
|
||||
Assert.IsFalse(reader.NoSamples);
|
||||
Assert.AreEqual(105.0, reader.VolumeLtrStartAverage, 0.0001);
|
||||
Assert.AreEqual(157.0, reader.VolumeLtrEndAwerage, 0.0001);
|
||||
Assert.AreEqual(10.0, reader.TimestampSecStart, 0.0001);
|
||||
Assert.AreEqual(20.0, reader.TimestampSecEnd, 0.0001);
|
||||
}
|
||||
|
||||
private static void InitializeReaderForTest(GenesisSmartReader reader)
|
||||
{
|
||||
const int channelCount = 3;
|
||||
@ -137,25 +215,20 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
SetPrivateField(reader, "partOfTelegram", string.Empty);
|
||||
SetPrivateField(reader, "startDataProcessing", true);
|
||||
|
||||
reader.StopQueueData = false;
|
||||
|
||||
reader.TestStartTelegramIx = 0;
|
||||
reader.TestEndTelegramIx = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static string[] LoadRealInputLines()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
// group 1
|
||||
// Replace these with REAL, unchanged captured telegram lines from the device.
|
||||
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
|
||||
"@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
|
||||
|
||||
// group 2 (next real lines from your log)
|
||||
"@h 1 0 0A1F59C5 00017A44 00115C46 72E1596C 00000400 00001999 7D91B653 7D4F37E7 000191E7 0C 062E4A9D 5332",
|
||||
"@h 2 0 0A1B1FE9 00017B80 00116B57 72B77428 00000400 0000199B 7DC09689 7B570007 000191E7 0C 062E5327 95BE",
|
||||
"@h 3 0 0A1DF1D6 00017EA9 00118038 741F80F4 00000400 00001999 7E58A62F 7CC2C607 000191E7 0C 062E5BAF D40F"
|
||||
};
|
||||
}
|
||||
|
||||
@ -163,58 +236,83 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
// --- FIRST 3 (before rollover) ---
|
||||
// Replace these with REAL, unchanged captured telegram lines spanning the rollover case.
|
||||
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
|
||||
"@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
|
||||
|
||||
// --- LAST 3 (after rollover / later in log) ---
|
||||
"@h 1 0 00000010 00000020 00000030 00000040 00000400 00000001 00000050 00000060 00000070 0C 00000080 1111",
|
||||
"@h 2 0 00000011 00000021 00000031 00000041 00000400 00000002 00000051 00000061 00000071 0C 00000081 2222",
|
||||
"@h 3 0 00000012 00000022 00000032 00000042 00000400 00000003 00000052 00000062 00000072 0C 00000082 3333",
|
||||
};
|
||||
}
|
||||
|
||||
private static void SetPrivateField(object target, string fieldName, object value)
|
||||
{
|
||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.IsNotNull(field, $"Field '{fieldName}' not found.");
|
||||
field.SetValue(target, value);
|
||||
Type type = target.GetType();
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
var field = type.GetField(
|
||||
fieldName,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
field.SetValue(target, value);
|
||||
return;
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
Assert.Fail($"Field '{fieldName}' not found.");
|
||||
}
|
||||
|
||||
private static T GetPrivateField<T>(object target, string fieldName)
|
||||
{
|
||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.IsNotNull(field, $"Field '{fieldName}' not found.");
|
||||
return (T)field.GetValue(target);
|
||||
Type type = target.GetType();
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
var field = type.GetField(
|
||||
fieldName,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly);
|
||||
|
||||
if (field != null)
|
||||
return (T)field.GetValue(target);
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
Assert.Fail($"Field '{fieldName}' not found.");
|
||||
return default;
|
||||
}
|
||||
|
||||
private static object InvokePrivate(object target, string methodName, object[] args = null)
|
||||
{
|
||||
var methods = target.GetType()
|
||||
.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
.Where(m => m.Name == methodName)
|
||||
.ToList();
|
||||
Type type = target.GetType();
|
||||
|
||||
Assert.IsTrue(methods.Count > 0, $"Method '{methodName}' not found.");
|
||||
|
||||
var method = methods.First();
|
||||
|
||||
if (args == null)
|
||||
return method.Invoke(target, null);
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length != args.Length)
|
||||
while (type != null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Method '{methodName}' expects {parameters.Length} parameters, but {args.Length} were provided.");
|
||||
var methods = type.GetMethods(
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.NonPublic |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.DeclaredOnly)
|
||||
.Where(m => m.Name == methodName)
|
||||
.ToList();
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (args == null && method.GetParameters().Length == 0)
|
||||
return method.Invoke(target, null);
|
||||
|
||||
if (args != null && method.GetParameters().Length == args.Length)
|
||||
return method.Invoke(target, args);
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
var invokeArgs = new object[args.Length];
|
||||
Array.Copy(args, invokeArgs, args.Length);
|
||||
|
||||
return method.Invoke(target, invokeArgs);
|
||||
Assert.Fail($"Method '{methodName}' not found.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -132,14 +132,14 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
InvokePrepareCalculatedChannelData(reader);
|
||||
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(219.0, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual(200.666666666667, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(219.666666666667, reader.VolumeLtrEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(1.0, reader.TimestampSecStart, 1e-9);
|
||||
Assert.AreEqual(20.0, reader.TimestampSecEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStartRaw, 1e-9);
|
||||
Assert.AreEqual(219.0, reader.VolumeLtrEndRaw, 1e-9);
|
||||
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
|
||||
Assert.AreEqual(219.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -162,11 +162,6 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
index++;
|
||||
}
|
||||
|
||||
// channel 1 loses its last two valid records
|
||||
// valid ch1 becomes: 200..207 with timestamps 1..8
|
||||
// longest channel deltaTime is 9 (channels 0 and 2)
|
||||
// ch1 deltaVolume = 7, deltaTime = 7 => recalculated deltaVolume = 7 * 9 / 7 = 9
|
||||
// recalculated end ch1 = 200 + 9 = 209
|
||||
optoData[25].Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
optoData[28].Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
|
||||
@ -176,17 +171,18 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
InvokePrepareCalculatedChannelData(reader);
|
||||
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(209.0, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual(200.666666666667, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(209.666666666667, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual(209.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
|
||||
|
||||
Assert.AreEqual(208.33333333333334, reader.VolumeLtrEndRaw, 1e-9);
|
||||
|
||||
Assert.AreEqual(100.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStartCh2, 1e-9);
|
||||
Assert.AreEqual(101.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||
Assert.AreEqual(201.0, reader.VolumeLtrStartCh2, 1e-9);
|
||||
Assert.AreEqual(300.0, reader.VolumeLtrStartCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(109.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||
Assert.AreEqual(209.0, reader.VolumeLtrEndCh2, 1e-9);
|
||||
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
|
||||
|
||||
Assert.AreEqual(110.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||
Assert.AreEqual(210.0, reader.VolumeLtrEndCh2, 1e-9);
|
||||
Assert.AreEqual(309.0, reader.VolumeLtrEndCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(1.0, reader.TimestampSecStart, 1e-9);
|
||||
@ -255,12 +251,12 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
InvokePrepareCalculatedChannelData(reader);
|
||||
|
||||
Assert.AreEqual(100.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStartCh2, 1e-9);
|
||||
Assert.AreEqual(101.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||
Assert.AreEqual(201.0, reader.VolumeLtrStartCh2, 1e-9);
|
||||
Assert.AreEqual(300.0, reader.VolumeLtrStartCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(119.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||
Assert.AreEqual(219.0, reader.VolumeLtrEndCh2, 1e-9);
|
||||
Assert.AreEqual(120.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||
Assert.AreEqual(220.0, reader.VolumeLtrEndCh2, 1e-9);
|
||||
Assert.AreEqual(319.0, reader.VolumeLtrEndCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(1.0, reader.TimestampSecStartCh1, 1e-9);
|
||||
@ -271,13 +267,13 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
Assert.AreEqual(20.0, reader.TimestampSecEndCh2, 1e-9);
|
||||
Assert.AreEqual(20.0, reader.TimestampSecEndCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(219.0, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual(219.666666666667, reader.VolumeLtrEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(1.0, reader.TimestampSecStart, 1e-9);
|
||||
Assert.AreEqual(20.0, reader.TimestampSecEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(200.0, reader.VolumeLtrStartRaw, 1e-9);
|
||||
Assert.AreEqual(219.0, reader.VolumeLtrEndRaw, 1e-9);
|
||||
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
|
||||
Assert.AreEqual(219.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -300,14 +296,14 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
InvokePrepareCalculatedChannelData(reader);
|
||||
|
||||
Assert.AreEqual(15.0, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(19.0, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual(15.5, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(19.5, reader.VolumeLtrEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(10.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||
Assert.AreEqual(11.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||
Assert.AreEqual(20.0, reader.VolumeLtrStartCh2, 1e-9);
|
||||
Assert.AreEqual(0.0, reader.VolumeLtrStartCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(14.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||
Assert.AreEqual(15.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||
Assert.AreEqual(24.0, reader.VolumeLtrEndCh2, 1e-9);
|
||||
Assert.AreEqual(0.0, reader.VolumeLtrEndCh3, 1e-9);
|
||||
|
||||
|
||||
@ -460,7 +460,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
var result = (OptoTelegramRaw[][])InvokePrivate(
|
||||
"RecalculateVolumeAndTimeDeltaPerChannel",
|
||||
(object)input,
|
||||
input.Length);
|
||||
input.Length,
|
||||
0,
|
||||
input.Length - 1);
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
@ -499,7 +501,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
var result = (OptoTelegramRaw[][])InvokePrivate(
|
||||
"RecalculateVolumeAndTimeDeltaPerChannel",
|
||||
(object)input,
|
||||
input.Length);
|
||||
input.Length,
|
||||
0,
|
||||
input.Length - 1);
|
||||
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
|
||||
@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
[TestClass]
|
||||
public class GenesisSmartReaderStopTests
|
||||
{
|
||||
private const int ChannelCount = 3;
|
||||
|
||||
private static GenesisCfg CreateCfg()
|
||||
{
|
||||
Factory factory = new Factory();
|
||||
return new GenesisCfg(factory);
|
||||
}
|
||||
|
||||
private static void SetPrivateField(object target, string fieldName, object value)
|
||||
{
|
||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null)
|
||||
throw new MissingFieldException(target.GetType().FullName, fieldName);
|
||||
|
||||
field.SetValue(target, value);
|
||||
}
|
||||
|
||||
private static T GetPrivateField<T>(object target, string fieldName)
|
||||
{
|
||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null)
|
||||
throw new MissingFieldException(target.GetType().FullName, fieldName);
|
||||
|
||||
return (T)field.GetValue(target);
|
||||
}
|
||||
|
||||
private static void WaitForStopToFinish(GenesisSmartReader reader, int timeoutMs = 3000)
|
||||
{
|
||||
var stopTask = GetPrivateField<Task>(reader, "_backgroundStopTask");
|
||||
if (stopTask != null)
|
||||
{
|
||||
stopTask.Wait(timeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt)
|
||||
{
|
||||
return new OptoTelegramRaw
|
||||
{
|
||||
Flags = OptoTelegramFlags.OK,
|
||||
VolumeRawExt = volumeRawExt,
|
||||
TimestampExt = timestampExt,
|
||||
iChannel = channel
|
||||
};
|
||||
}
|
||||
|
||||
private static void FillValidOptoDataForPostProcessing(GenesisSmartReader reader)
|
||||
{
|
||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||
|
||||
int idx = 0;
|
||||
for (int group = 0; group < 6; group++)
|
||||
{
|
||||
optoData[idx++] = CreateOptoRecord(0, 10 + group, 100 + group);
|
||||
optoData[idx++] = CreateOptoRecord(1, 20 + group, 100 + group);
|
||||
optoData[idx++] = CreateOptoRecord(2, 30 + group, 100 + group);
|
||||
}
|
||||
|
||||
SetPrivateField(reader, "optoDataCount", 18);
|
||||
reader.TestStartTelegramIx = 1;
|
||||
reader.TestEndTelegramIx = 17;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Stop_WhenStateIsCalculateStoredData_ShouldRunPostProcessing_AndFlushState()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
FillValidOptoDataForPostProcessing(reader);
|
||||
|
||||
SetPrivateField(reader, "dataStreamState", DataStreamState.CalculateStoredData);
|
||||
SetPrivateField(reader, "startDataProcessing", false);
|
||||
SetPrivateField(reader, "_stopQueueData", true);
|
||||
|
||||
fake.Open();
|
||||
reader.optoSerialPort = fake;
|
||||
|
||||
reader.Stop();
|
||||
|
||||
var finalState = GetPrivateField<DataStreamState>(reader, "dataStreamState");
|
||||
|
||||
Assert.AreEqual(DataStreamState.Flush, finalState, "Stop() should finish in Flush state.");
|
||||
Assert.IsFalse(fake.IsOpen, "Serial port should be closed by Stop().");
|
||||
|
||||
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartAverage, 1e-9,
|
||||
"Expected post-processing to prepare raw/recalculated start values.");
|
||||
Assert.AreEqual((15.0 + 25.0 + 36.0) / 3.0, reader.VolumeLtrEndAwerage, 1e-9,
|
||||
"Expected post-processing to prepare recalculated end values.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Stop_WhenStateIsProcessAndSave_ShouldNotRunPostProcessing_AndFlushState()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
FillValidOptoDataForPostProcessing(reader);
|
||||
|
||||
SetPrivateField(reader, "dataStreamState", DataStreamState.ProcessAndSave);
|
||||
SetPrivateField(reader, "startDataProcessing", true);
|
||||
SetPrivateField(reader, "_stopQueueData", false);
|
||||
|
||||
fake.Open();
|
||||
reader.optoSerialPort = fake;
|
||||
|
||||
reader.Stop();
|
||||
WaitForStopToFinish(reader);
|
||||
|
||||
var finalState = GetPrivateField<DataStreamState>(reader, "dataStreamState");
|
||||
var stopQueueData = GetPrivateField<bool>(reader, "_stopQueueData");
|
||||
|
||||
Assert.AreEqual(DataStreamState.Flush, finalState, "Stop() should finish in Flush state.");
|
||||
Assert.IsTrue(stopQueueData, "Immediate stop path should stop queueing.");
|
||||
Assert.IsFalse(fake.IsOpen, "Serial port should be closed by Stop().");
|
||||
|
||||
Assert.AreEqual(0.0, reader.VolumeLtrStartAverage, 1e-9,
|
||||
"Post-processing should not run when previous state was ProcessAndSave.");
|
||||
Assert.AreEqual(0.0, reader.VolumeLtrEndAwerage, 1e-9,
|
||||
"Post-processing should not run when previous state was ProcessAndSave.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RequestImmediateStop_ShouldNotChangeCalculateStoredDataState()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
|
||||
SetPrivateField(reader, "dataStreamState", DataStreamState.CalculateStoredData);
|
||||
SetPrivateField(reader, "startDataProcessing", true);
|
||||
SetPrivateField(reader, "_stopQueueData", false);
|
||||
|
||||
reader.RequestImmediateStop();
|
||||
|
||||
var state = GetPrivateField<DataStreamState>(reader, "dataStreamState");
|
||||
var stopQueueData = GetPrivateField<bool>(reader, "_stopQueueData");
|
||||
var startDataProcessing = GetPrivateField<bool>(reader, "startDataProcessing");
|
||||
|
||||
Assert.AreEqual(DataStreamState.CalculateStoredData, state,
|
||||
"RequestImmediateStop() must not destroy CalculateStoredData state.");
|
||||
Assert.IsTrue(stopQueueData, "Immediate stop should stop queueing.");
|
||||
Assert.IsFalse(startDataProcessing, "Immediate stop should disable active processing.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Common;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig;
|
||||
@ -65,6 +71,22 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
SetPrivateField(reader, "timestampSec", new[] { 0.0, 0.0, 0.0 });
|
||||
SetPrivateField(reader, "timestampSec0", new[] { 0.0, 0.0, 0.0 });
|
||||
}
|
||||
|
||||
private static void EnableProcessingLoopForTests(GenesisSmartReader reader)
|
||||
{
|
||||
SetPrivateField(reader, "dataStreamState", DataStreamState.ProcessAndSave);
|
||||
SetPrivateField(reader, "startDataProcessing", true);
|
||||
reader.StopQueueData = false;
|
||||
}
|
||||
|
||||
private static void WaitForStopToFinish(GenesisSmartReader reader, int timeoutMs = 3000)
|
||||
{
|
||||
var stopTask = GetPrivateField<Task>(reader, "_backgroundStopTask");
|
||||
if (stopTask != null)
|
||||
{
|
||||
stopTask.Wait(timeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_ShouldOpenPort_AndEnableProcessing()
|
||||
@ -92,11 +114,37 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
Assert.IsTrue(fake.IsOpen);
|
||||
|
||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||
Assert.IsNotNull(optoData);
|
||||
|
||||
if (optoData[0] == null)
|
||||
optoData[0] = new OptoTelegramRaw();
|
||||
|
||||
if (optoData[1] == null)
|
||||
optoData[1] = new OptoTelegramRaw();
|
||||
|
||||
optoData[0].Flags = OptoTelegramFlags.OK;
|
||||
optoData[0].TimestampExt = 100.0;
|
||||
optoData[0].VolumeRawExt = 10.0;
|
||||
|
||||
optoData[1].Flags = OptoTelegramFlags.OK;
|
||||
optoData[1].TimestampExt = 101.0;
|
||||
optoData[1].VolumeRawExt = 11.0;
|
||||
|
||||
SetPrivateField(reader, "optoDataCount", 2);
|
||||
SetPrivateField(reader, "dataStreamState", DataStreamState.ProcessAndSave);
|
||||
|
||||
reader.TestStartTelegramIx = 0;
|
||||
reader.TestEndTelegramIx = 1;
|
||||
|
||||
reader.Stop();
|
||||
WaitForStopToFinish(reader);
|
||||
|
||||
Assert.IsFalse(fake.IsOpen);
|
||||
Assert.AreEqual(2, fake.CloseCalls);
|
||||
Assert.IsTrue(fake.CloseCalls >= 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void Run_ShouldCaptureStartTelegramIndex_WhenTimeReached()
|
||||
@ -127,6 +175,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.Initialize();
|
||||
reader.optoSerialPort = fake;
|
||||
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
bool reset;
|
||||
|
||||
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
|
||||
@ -161,6 +212,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
reader.optoSerialPort = fake;
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
|
||||
|
||||
@ -216,6 +268,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
reader.optoSerialPort = fake;
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
var line =
|
||||
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD";
|
||||
@ -227,9 +280,15 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", 0)]
|
||||
[DataRow("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", 1)]
|
||||
[DataRow("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", 2)]
|
||||
[DataRow(
|
||||
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
0)]
|
||||
[DataRow(
|
||||
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
|
||||
1)]
|
||||
[DataRow(
|
||||
"@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
|
||||
2)]
|
||||
public void ProcessOptoLine_ShouldInsertTelegramAndUpdateExpectedChannel(string line, int expectedChannelIndex)
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
@ -239,6 +298,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.Initialize();
|
||||
reader.optoSerialPort = fake;
|
||||
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
|
||||
|
||||
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
|
||||
@ -246,27 +308,25 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||
var optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
Assert.AreEqual(1, optoDataCount, "Exactly one telegram should be inserted.");
|
||||
Assert.AreEqual(1, optoDataCount);
|
||||
|
||||
var inserted = optoData[0];
|
||||
Assert.IsNotNull(inserted, "Inserted telegram should not be null.");
|
||||
Assert.IsNotNull(inserted);
|
||||
|
||||
Assert.AreEqual(expectedChannelIndex, inserted.IChannel(), "Inserted telegram channel does not match expected channel.");
|
||||
Assert.AreEqual(0, inserted.Counter, "First inserted telegram should have counter 0.");
|
||||
Assert.AreEqual(OptoTelegramFlags.OK, inserted.Flags, "Inserted telegram should be marked OK.");
|
||||
Assert.AreNotEqual(default(DateTime), inserted.DateTime, "Inserted telegram DateTime should be initialized.");
|
||||
Assert.AreEqual(expectedChannelIndex, inserted.IChannel());
|
||||
Assert.AreEqual(0, inserted.Counter);
|
||||
Assert.AreEqual(OptoTelegramFlags.OK, inserted.Flags);
|
||||
|
||||
Assert.AreNotEqual(0.0, inserted.VolumeRaw, "Inserted telegram VolumeRaw should be set.");
|
||||
Assert.AreNotEqual(0.0, inserted.VolumeRawExt, "Inserted telegram VolumeRawExt should be set.");
|
||||
Assert.AreNotEqual(0.0, inserted.Timestamp, "Inserted telegram Timestamp should be set.");
|
||||
Assert.AreNotEqual(0.0, inserted.TimestampExt, "Inserted telegram TimestampExt should be set.");
|
||||
Assert.AreNotEqual(0.0, inserted.VolumeRawExt);
|
||||
Assert.AreNotEqual(0.0, inserted.TimestampExt);
|
||||
|
||||
for (int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
if (i == expectedChannelIndex)
|
||||
{
|
||||
Assert.AreNotEqual(0.0, volumeRawExtLast[i], $"Expected channel {i} volume cache was not updated.");
|
||||
Assert.AreNotEqual(0.0, timestampExtLast[i], $"Expected channel {i} timestamp cache was not updated.");
|
||||
Assert.AreNotEqual(0.0, timestampExtLast[i],
|
||||
$"Expected channel {i} timestamp cache was not updated.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -275,11 +335,8 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(volumeRawExtLast[expectedChannelIndex], inserted.VolumeRawExt, 1e-9,
|
||||
"Inserted telegram VolumeRawExt should match updated channel cache.");
|
||||
|
||||
Assert.AreEqual(timestampExtLast[expectedChannelIndex], inserted.TimestampExt, 1e-9,
|
||||
"Inserted telegram TimestampExt should match updated channel cache.");
|
||||
Assert.AreEqual(volumeRawExtLast[expectedChannelIndex], inserted.VolumeRawExt, 1e-9);
|
||||
Assert.AreEqual(timestampExtLast[expectedChannelIndex], inserted.TimestampExt, 1e-9);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -306,13 +363,16 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
InvokePrepareCalculatedChannelData(reader);
|
||||
|
||||
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual((15.0 + 25.0 + 36.0) / 3.0, reader.VolumeLtrEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(100.0, reader.TimestampSecStart, 1e-9);
|
||||
Assert.AreEqual(105.0, reader.TimestampSecEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartRaw, 1e-9);
|
||||
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEndRaw, 1e-9);
|
||||
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartAverage, 1e-9);
|
||||
Assert.AreEqual((15.0 + 25.0 + 36.0) / 3.0, reader.VolumeLtrEndAwerage, 1e-9);
|
||||
|
||||
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartRawRaw, 1e-9);
|
||||
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEndRawRaw, 1e-9);
|
||||
}
|
||||
|
||||
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt)
|
||||
@ -350,7 +410,21 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
InvokePrepareCalculatedChannelData(reader);
|
||||
|
||||
Assert.AreEqual(15.5, reader.VolumeLtrStart, 1e-9);
|
||||
Assert.AreEqual(19.0, reader.VolumeLtrEnd, 1e-9);
|
||||
Assert.AreEqual(19.5, reader.VolumeLtrEnd, 1e-9);
|
||||
|
||||
Assert.AreEqual(15.5, reader.VolumeLtrStartAverage, 1e-9);
|
||||
Assert.AreEqual(19.5, reader.VolumeLtrEndAwerage, 1e-9);
|
||||
|
||||
Assert.AreEqual(15.5, reader.VolumeLtrStartRawRaw, 1e-9);
|
||||
Assert.AreEqual(19.0, reader.VolumeLtrEndRawRaw, 1e-9);
|
||||
|
||||
Assert.AreEqual(11.0, reader.VolumeLtrStartRawCh1, 1e-9);
|
||||
Assert.AreEqual(20.0, reader.VolumeLtrStartRawCh2, 1e-9);
|
||||
Assert.AreEqual(0.0, reader.VolumeLtrStartRawCh3, 1e-9);
|
||||
|
||||
Assert.AreEqual(14.0, reader.VolumeLtrEndRawCh1, 1e-9);
|
||||
Assert.AreEqual(24.0, reader.VolumeLtrEndRawCh2, 1e-9);
|
||||
Assert.AreEqual(0.0, reader.VolumeLtrEndRawCh3, 1e-9);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -382,43 +456,42 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
Assert.IsFalse(reset, "Reset must not happen immediately after @h 3.");
|
||||
|
||||
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsTrue(reset, "Reset must happen after trailing @f that closes the h1/h2/h3 block.");
|
||||
//now some cycles must be runing, so reset must happen.
|
||||
//Assert.IsTrue(reset, "Reset must happen after trailing @f that closes the h1/h2/h3 block.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadOptoData_FullBlock_ShouldDiscardBuffersAfterClosingF()
|
||||
public void ProcessingLoop_FullBlock_ShouldDiscardBuffersAfterClosingF()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
|
||||
fake.EnqueueLine("@f AA754B 4D0CEE78 5D89");
|
||||
fake.EnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
|
||||
fake.EnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
|
||||
fake.EnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
|
||||
fake.EnqueueLine("@f AA7C01 4D0CFE76 B08F");
|
||||
fake.Open();
|
||||
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
reader.Initialize();
|
||||
|
||||
fake.Open();
|
||||
reader.optoSerialPort = fake;
|
||||
reader.ResetAfterBlockRepetitions = 1;
|
||||
|
||||
var readMethod = typeof(GenesisSmartReader).GetMethod(
|
||||
"ReadOptoData",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic,
|
||||
null,
|
||||
new[] { typeof(DataStreamState) },
|
||||
null);
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
Assert.IsNotNull(readMethod);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
reader.StartProcessingLoop();
|
||||
try
|
||||
{
|
||||
readMethod.Invoke(reader, new object[] { DataStreamState.ProcessAndSave });
|
||||
}
|
||||
reader.TestEnqueueLine("@f AA754B 4D0CEE78 5D89");
|
||||
reader.TestEnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
|
||||
reader.TestEnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
|
||||
reader.TestEnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
|
||||
reader.TestEnqueueLine("@f AA7C01 4D0CFE76 B08F");
|
||||
|
||||
Assert.AreEqual(1, fake.DiscardInCalls, "Input buffer should be discarded once after completed block.");
|
||||
Assert.AreEqual(1, fake.DiscardOutCalls, "Output buffer should be discarded once after completed block.");
|
||||
Thread.Sleep(300);
|
||||
|
||||
Assert.AreEqual(1, fake.DiscardInCalls, "Input buffer should be discarded once after completed block.");
|
||||
Assert.AreEqual(1, fake.DiscardOutCalls, "Output buffer should be discarded once after completed block.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.StopProcessingLoop();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -432,10 +505,13 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.optoSerialPort = fake;
|
||||
reader.ResetAfterBlockRepetitions = 1;
|
||||
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
bool reset;
|
||||
|
||||
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Opening @f must not reset buffers.");
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
@ -490,24 +566,24 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.optoSerialPort = fake;
|
||||
reader.ResetAfterBlockRepetitions = 3;
|
||||
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
bool reset;
|
||||
|
||||
for (int repetition = 1; repetition <= 3; repetition++)
|
||||
{
|
||||
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen on opening @f, repetition " + repetition);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen after @h1, repetition " + repetition);
|
||||
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
|
||||
DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen after @h2, repetition " + repetition);
|
||||
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
|
||||
DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen after @h3, repetition " + repetition);
|
||||
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
|
||||
|
||||
@ -529,24 +605,24 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.optoSerialPort = fake;
|
||||
reader.ResetAfterBlockRepetitions = 5;
|
||||
|
||||
InitializeThreeChannelState(reader);
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
bool reset;
|
||||
|
||||
for (int repetition = 1; repetition <= 5; repetition++)
|
||||
{
|
||||
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen on opening @f, repetition " + repetition);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||
DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen after @h1, repetition " + repetition);
|
||||
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
|
||||
DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen after @h2, repetition " + repetition);
|
||||
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
|
||||
DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset, "Reset must not happen after @h3, repetition " + repetition);
|
||||
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", DataStreamState.ProcessAndSave, out reset);
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
|
||||
|
||||
@ -556,5 +632,159 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
Assert.IsTrue(reset, "Reset must happen on fifth full block.");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessingLoop_Should_Keep_FIFO_Order_For_Enqueued_Items()
|
||||
{
|
||||
var reader = new GenesisSmartReader();
|
||||
|
||||
var expected = Enumerable.Range(1, 200)
|
||||
.Select(i => $"LINE_{i:D4}")
|
||||
.ToList();
|
||||
|
||||
var actual = new List<string>();
|
||||
var sync = new object();
|
||||
var allProcessed = new CountdownEvent(expected.Count);
|
||||
|
||||
reader.TestProcessLineOverride = line => true;
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
reader.TestLineProcessed = line =>
|
||||
{
|
||||
lock (sync)
|
||||
{
|
||||
actual.Add(line);
|
||||
}
|
||||
|
||||
allProcessed.Signal();
|
||||
};
|
||||
|
||||
reader.StartProcessingLoop();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var line in expected)
|
||||
{
|
||||
reader.TestEnqueueLine(line);
|
||||
}
|
||||
|
||||
bool completed = allProcessed.Wait(TimeSpan.FromSeconds(10));
|
||||
Assert.IsTrue(completed, "Timed out waiting for all queued items to be processed.");
|
||||
|
||||
CollectionAssert.AreEqual(expected, actual,
|
||||
"Dequeued/processed order does not match enqueued order.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.StopProcessingLoop();
|
||||
allProcessed.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessingLoop_Should_Keep_FIFO_Order_With_Concurrent_Producers()
|
||||
{
|
||||
var reader = new GenesisSmartReader();
|
||||
|
||||
const int producerCount = 4;
|
||||
const int itemsPerProducer = 100;
|
||||
int totalItems = producerCount * itemsPerProducer;
|
||||
|
||||
var expected = new List<string>();
|
||||
var processed = new List<string>();
|
||||
|
||||
var expectedLock = new object();
|
||||
var processedLock = new object();
|
||||
int sequence = 0;
|
||||
|
||||
var allProcessed = new CountdownEvent(totalItems);
|
||||
|
||||
try
|
||||
{
|
||||
reader.TestProcessLineOverride = line => true;
|
||||
EnableProcessingLoopForTests(reader);
|
||||
|
||||
reader.TestLineProcessed = line =>
|
||||
{
|
||||
lock (processedLock)
|
||||
{
|
||||
processed.Add(line);
|
||||
}
|
||||
|
||||
allProcessed.Signal();
|
||||
};
|
||||
|
||||
reader.StartProcessingLoop();
|
||||
|
||||
var tasks = new List<Task>();
|
||||
|
||||
for (int p = 0; p < producerCount; p++)
|
||||
{
|
||||
int producerId = p;
|
||||
|
||||
tasks.Add(Task.Run(() =>
|
||||
{
|
||||
for (int i = 0; i < itemsPerProducer; i++)
|
||||
{
|
||||
int seq = Interlocked.Increment(ref sequence);
|
||||
string line = string.Format("{0:D6}|P{1}|I{2:D4}", seq, producerId, i);
|
||||
|
||||
lock (expectedLock)
|
||||
{
|
||||
expected.Add(line);
|
||||
reader.TestEnqueueLine(line);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Task.WaitAll(tasks.ToArray());
|
||||
|
||||
bool completed = allProcessed.Wait(TimeSpan.FromSeconds(15));
|
||||
Assert.IsTrue(completed, "Timed out waiting for all concurrent items to be processed.");
|
||||
|
||||
CollectionAssert.AreEqual(expected, processed,
|
||||
"Processed order does not match actual enqueue order under concurrent producers.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.StopProcessingLoop();
|
||||
allProcessed.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void PrepareCalculatedChannelData_SimulateMode_ReturnsExpectedFakeValues()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
sut.PrepareCalculatedChannelDataSimulationForTest();
|
||||
|
||||
Assert.IsFalse(sut.NoSamples);
|
||||
|
||||
Assert.AreEqual(100.0, sut.VolumeLtrStartCh1, 0.0001);
|
||||
Assert.AreEqual(105.0, sut.VolumeLtrStartCh2, 0.0001);
|
||||
Assert.AreEqual(110.0, sut.VolumeLtrStartCh3, 0.0001);
|
||||
|
||||
Assert.AreEqual(150.0, sut.VolumeLtrEndCh1, 0.0001);
|
||||
Assert.AreEqual(157.0, sut.VolumeLtrEndCh2, 0.0001);
|
||||
Assert.AreEqual(164.0, sut.VolumeLtrEndCh3, 0.0001);
|
||||
|
||||
Assert.AreEqual(10.0, sut.TimestampSecStartCh1, 0.0001);
|
||||
Assert.AreEqual(10.0, sut.TimestampSecStartCh2, 0.0001);
|
||||
Assert.AreEqual(10.0, sut.TimestampSecStartCh3, 0.0001);
|
||||
|
||||
Assert.AreEqual(20.0, sut.TimestampSecEndCh1, 0.0001);
|
||||
Assert.AreEqual(20.0, sut.TimestampSecEndCh2, 0.0001);
|
||||
Assert.AreEqual(20.0, sut.TimestampSecEndCh3, 0.0001);
|
||||
|
||||
Assert.AreEqual(105.0, sut.VolumeLtrStartAverage, 0.0001);
|
||||
Assert.AreEqual(157.0, sut.VolumeLtrEndAwerage, 0.0001);
|
||||
|
||||
Assert.AreEqual(10.0, sut.TimestampSecStart, 0.0001);
|
||||
Assert.AreEqual(20.0, sut.TimestampSecEnd, 0.0001);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -68,6 +68,77 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
SetPrivateField(reader, "timestampSec", new[] { 0.0, 0.0, 0.0 });
|
||||
SetPrivateField(reader, "timestampSec0", new[] { 0.0, 0.0, 0.0 });
|
||||
}
|
||||
|
||||
private static FieldInfo GetAnyField(object target, string fieldName)
|
||||
{
|
||||
var field = target.GetType().GetField(
|
||||
fieldName,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (field == null)
|
||||
throw new MissingFieldException(target.GetType().FullName, fieldName);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
private static void SetField(object target, string fieldName, object value)
|
||||
{
|
||||
GetAnyField(target, fieldName).SetValue(target, value);
|
||||
}
|
||||
|
||||
private static T GetField<T>(object target, string fieldName)
|
||||
{
|
||||
return (T)GetAnyField(target, fieldName).GetValue(target);
|
||||
}
|
||||
|
||||
private static void WaitForStartupFlushToFinish(GenesisSmartReader reader, int timeoutMs = 3000)
|
||||
{
|
||||
bool finished = WaitUntil(() =>
|
||||
{
|
||||
return !GetPrivateField<bool>(reader, "_startupFlushActive");
|
||||
}, timeoutMs);
|
||||
|
||||
Assert.IsTrue(finished, "Startup flush did not finish in time.");
|
||||
}
|
||||
|
||||
private static void ForceProcessingEnabled(GenesisSmartReader reader)
|
||||
{
|
||||
SetField(reader, "_startupFlushActive", false);
|
||||
SetField(reader, "_stopQueueData", false);
|
||||
SetField(reader, "dataStreamState", DataStreamState.ProcessAndSave);
|
||||
SetField(reader, "startDataProcessing", true);
|
||||
|
||||
var signal = GetField<AutoResetEvent>(reader, "_queueSignal");
|
||||
signal.Set();
|
||||
}
|
||||
|
||||
private static void EnqueueIncomingLine(GenesisSmartReader reader, string line)
|
||||
{
|
||||
var queue = GetField<System.Collections.Concurrent.ConcurrentQueue<(DateTime Timestamp, string Line)>>(
|
||||
reader, "_receivedLines");
|
||||
|
||||
var signal = GetField<AutoResetEvent>(reader, "_queueSignal");
|
||||
|
||||
queue.Enqueue((DateTime.UtcNow, line));
|
||||
signal.Set();
|
||||
}
|
||||
|
||||
private static void InstallSuccessfulProcessingOverride(GenesisSmartReader reader)
|
||||
{
|
||||
Func<string, bool> handler = line =>
|
||||
{
|
||||
var optoData = GetField<OptoTelegramRaw[]>(reader, "optoData");
|
||||
int count = GetField<int>(reader, "optoDataCount");
|
||||
|
||||
optoData[count].Counter = count;
|
||||
optoData[count].SetFlags(OptoTelegramFlags.OK);
|
||||
|
||||
SetField(reader, "optoDataCount", count + 1);
|
||||
return true;
|
||||
};
|
||||
|
||||
SetField(reader, "TestProcessLineOverride", handler);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_ShouldOpenPort_AndStartBackgroundReadLoop()
|
||||
@ -84,9 +155,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
var readLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_readLoopTask");
|
||||
Assert.IsNotNull(readLoopTask);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void BackgroundReadLoop_ShouldMoveIncomingLinesToQueue()
|
||||
public void ProcessingLoop_ShouldConsumeQueuedLine()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
@ -95,48 +166,58 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
|
||||
fake.EnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
|
||||
ForceProcessingEnabled(reader);
|
||||
InstallSuccessfulProcessingOverride(reader);
|
||||
|
||||
bool queued = WaitUntil(() =>
|
||||
EnqueueIncomingLine(reader, "TEST_LINE_1");
|
||||
|
||||
bool processed = WaitUntil(() =>
|
||||
{
|
||||
var queue = GetPrivateField<System.Collections.Concurrent.ConcurrentQueue<string>>(reader, "_receivedLines");
|
||||
return !queue.IsEmpty;
|
||||
});
|
||||
int optoDataCount = GetField<int>(reader, "optoDataCount");
|
||||
return optoDataCount == 1;
|
||||
}, 3000);
|
||||
|
||||
Assert.IsTrue(queued, "Expected background task to enqueue received serial line.");
|
||||
Assert.IsTrue(processed, "Expected processing loop to consume queued line.");
|
||||
|
||||
int finalCount = GetField<int>(reader, "optoDataCount");
|
||||
Assert.AreEqual(1, finalCount);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void RunDeviceBefore_ShouldDrainQueue_AndInsertTelegram()
|
||||
public void ProcessingLoop_ShouldConsumeQueuedLine_AndInsertTelegram()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
fake.Encoding = System.Text.Encoding.ASCII;
|
||||
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
|
||||
fake.EnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
|
||||
ForceProcessingEnabled(reader);
|
||||
|
||||
bool queued = WaitUntil(() =>
|
||||
EnqueueIncomingLine(reader,
|
||||
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
|
||||
|
||||
bool processed = WaitUntil(() =>
|
||||
{
|
||||
var queue = GetPrivateField<System.Collections.Concurrent.ConcurrentQueue<string>>(reader, "_receivedLines");
|
||||
return !queue.IsEmpty;
|
||||
});
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
return optoDataCount >= 1;
|
||||
}, 3000);
|
||||
|
||||
Assert.IsTrue(queued, "Expected line to be queued before processing.");
|
||||
Assert.IsTrue(processed, "Expected processing loop to consume queued line.");
|
||||
|
||||
reader.RunDeviceBefore();
|
||||
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
int finalCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||
|
||||
Assert.AreEqual(1, optoDataCount);
|
||||
Assert.AreEqual(1, finalCount);
|
||||
Assert.AreEqual(1, optoData[0].IChannel());
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void RunDeviceBefore_ShouldDrainAllQueuedLines()
|
||||
public void ProcessingLoop_ShouldConsumeAllQueuedLines()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
@ -145,29 +226,148 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
|
||||
fake.EnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
|
||||
fake.EnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
|
||||
ForceProcessingEnabled(reader);
|
||||
InstallSuccessfulProcessingOverride(reader);
|
||||
|
||||
EnqueueIncomingLine(reader, "TEST_LINE_1");
|
||||
EnqueueIncomingLine(reader, "TEST_LINE_2");
|
||||
EnqueueIncomingLine(reader, "TEST_LINE_3");
|
||||
|
||||
bool processed = WaitUntil(() =>
|
||||
{
|
||||
int optoDataCount = GetField<int>(reader, "optoDataCount");
|
||||
return optoDataCount == 3;
|
||||
}, 3000);
|
||||
|
||||
Assert.IsTrue(processed, "Expected all queued lines to be processed.");
|
||||
|
||||
int finalCount = GetField<int>(reader, "optoDataCount");
|
||||
var queueAfter = GetField<System.Collections.Concurrent.ConcurrentQueue<(DateTime Timestamp, string Line)>>(
|
||||
reader, "_receivedLines");
|
||||
|
||||
Assert.AreEqual(3, finalCount);
|
||||
Assert.IsTrue(queueAfter.IsEmpty);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IncomingLines_ShouldBeProcessedByBackgroundProcessingLoop()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
WaitForStartupFlushToFinish(reader);
|
||||
|
||||
fake.EnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
|
||||
|
||||
bool queued = WaitUntil(() =>
|
||||
bool processed = WaitUntil(() =>
|
||||
{
|
||||
var queue = GetPrivateField<System.Collections.Concurrent.ConcurrentQueue<string>>(reader, "_receivedLines");
|
||||
return !queue.IsEmpty;
|
||||
});
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
return optoDataCount >= 1;
|
||||
}, 3000);
|
||||
|
||||
Assert.IsTrue(queued);
|
||||
|
||||
reader.RunDeviceBefore();
|
||||
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
var queueAfter = GetPrivateField<System.Collections.Concurrent.ConcurrentQueue<string>>(reader, "_receivedLines");
|
||||
|
||||
Assert.AreEqual(3, optoDataCount);
|
||||
Assert.IsTrue(queueAfter.IsEmpty, "Queue should be empty after RunDeviceBefore drains it.");
|
||||
Assert.IsTrue(processed, "Expected background processing loop to process line.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void StopDataStreamProcessing_ShouldStopReadLoop_AndClosePort()
|
||||
public void StopDataStreamProcessing_ShouldStopReadAndProcessingLoops()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
|
||||
reader.StopDataStreamProcessing();
|
||||
|
||||
var readLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_readLoopTask");
|
||||
var readLoopCts = GetPrivateField<CancellationTokenSource>(reader, "_readLoopCts");
|
||||
var processLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_processLoopTask");
|
||||
var processLoopCts = GetPrivateField<CancellationTokenSource>(reader, "_processLoopCts");
|
||||
|
||||
Assert.IsNull(readLoopTask);
|
||||
Assert.IsNull(readLoopCts);
|
||||
Assert.IsNull(processLoopTask);
|
||||
Assert.IsNull(processLoopCts);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IncomingLine_AfterStop_ShouldNotBeProcessed()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
|
||||
reader.StopDataStreamProcessing();
|
||||
|
||||
int before = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
fake.EnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
|
||||
|
||||
Thread.Sleep(300);
|
||||
|
||||
int after = GetPrivateField<int>(reader, "optoDataCount");
|
||||
|
||||
Assert.AreEqual(before, after, "No new telegram should be processed after stop.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void InvalidLine_ShouldNotCrashProcessingLoop()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
WaitForStartupFlushToFinish(reader);
|
||||
|
||||
fake.EnqueueLine("INVALID_LINE_THAT_WILL_NOT_PARSE");
|
||||
fake.EnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
|
||||
|
||||
bool processed = WaitUntil(() =>
|
||||
{
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
return optoDataCount >= 1;
|
||||
}, 3000);
|
||||
|
||||
Assert.IsTrue(processed, "Processing loop should survive invalid input and continue.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void StartStop_StartAgain_ShouldStillProcessData()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
|
||||
reader.Start();
|
||||
reader.StopDataStreamProcessing();
|
||||
|
||||
reader.Start();
|
||||
WaitForStartupFlushToFinish(reader);
|
||||
|
||||
fake.EnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
|
||||
|
||||
bool processed = WaitUntil(() =>
|
||||
{
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
return optoDataCount >= 1;
|
||||
}, 3000);
|
||||
|
||||
Assert.IsTrue(processed, "Reader should still process data after restart.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_ShouldOpenPort_AndStartBothBackgroundLoops()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
@ -176,45 +376,14 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.Start();
|
||||
|
||||
Assert.IsTrue(fake.IsOpen);
|
||||
Assert.IsTrue(fake.OpenCalls >= 1);
|
||||
|
||||
reader.StopDataStreamProcessing();
|
||||
var readLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_readLoopTask");
|
||||
var processLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_processLoopTask");
|
||||
|
||||
Assert.IsFalse(fake.IsOpen);
|
||||
|
||||
var cts = GetPrivateField<System.Threading.CancellationTokenSource>(reader, "_readLoopCts");
|
||||
var task = GetPrivateField<System.Threading.Tasks.Task>(reader, "_readLoopTask");
|
||||
|
||||
Assert.IsNull(cts);
|
||||
Assert.IsNull(task);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IncomingLines_ShouldNotBeProcessedUntilRunDeviceBeforeIsCalled()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
reader.Start();
|
||||
|
||||
fake.EnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
|
||||
|
||||
bool queued = WaitUntil(() =>
|
||||
{
|
||||
var queue = GetPrivateField<System.Collections.Concurrent.ConcurrentQueue<string>>(reader, "_receivedLines");
|
||||
return !queue.IsEmpty;
|
||||
});
|
||||
|
||||
Assert.IsTrue(queued);
|
||||
|
||||
int optoDataCountBefore = GetPrivateField<int>(reader, "optoDataCount");
|
||||
Assert.AreEqual(0, optoDataCountBefore, "Background thread should only enqueue, not process.");
|
||||
|
||||
reader.RunDeviceBefore();
|
||||
|
||||
int optoDataCountAfter = GetPrivateField<int>(reader, "optoDataCount");
|
||||
Assert.AreEqual(1, optoDataCountAfter);
|
||||
Assert.IsNotNull(readLoopTask);
|
||||
Assert.IsNotNull(processLoopTask);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,427 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
[TestClass]
|
||||
public class GenesisSmartReader_Q3Test
|
||||
{
|
||||
private static readonly double[] ValidInitFactors = { 15625.0, 15625.0, 15625.0 };
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldRemainInvalid_WhenRawDataIsNull()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
InitializeReaderForQ3Test(sut);
|
||||
|
||||
SetPrivateField(sut, "_rawStartEndByChannel", null);
|
||||
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 1000.0,
|
||||
refTime: 120.0,
|
||||
initCalibFactor: ValidInitFactors,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
Assert.IsFalse(sut.Q3CalibValid);
|
||||
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
|
||||
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldRemainInvalid_WhenNoSamplesIsTrue()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
InitializeReaderForQ3Test(sut);
|
||||
|
||||
SetPrivateField(sut, "_rawStartEndByChannel", CreateMinimalStartEndData());
|
||||
|
||||
Assert.IsTrue(sut.NoSamples, "Expected NoSamples to be true for this test.");
|
||||
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 1000.0,
|
||||
refTime: 120.0,
|
||||
initCalibFactor: ValidInitFactors,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
Assert.IsFalse(sut.Q3CalibValid);
|
||||
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
|
||||
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldRemainInvalid_WhenRefVolumeIsZero()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
|
||||
Assert.IsFalse(sut.NoSamples);
|
||||
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 0.0,
|
||||
refTime: 120.0,
|
||||
initCalibFactor: ValidInitFactors,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
Assert.IsFalse(sut.Q3CalibValid);
|
||||
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
|
||||
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldRemainInvalid_WhenRefTimeIsZero()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
|
||||
Assert.IsFalse(sut.NoSamples);
|
||||
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 1000.0,
|
||||
refTime: 0.0,
|
||||
initCalibFactor: ValidInitFactors,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
Assert.IsFalse(sut.Q3CalibValid);
|
||||
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
|
||||
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldMarkInvalid_WhenInitFactorsAreZero()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
|
||||
Assert.IsFalse(sut.NoSamples);
|
||||
|
||||
var init = new[] { 0.0, 0.0, 0.0 };
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 1000.0,
|
||||
refTime: 120.0,
|
||||
initCalibFactor: init,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
Assert.IsFalse(sut.Q3CalibValid);
|
||||
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
|
||||
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CalculateQ3Calibration_ShouldPopulatePerChannelValues_WithPreparedSimulationData()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
|
||||
InvokePrivateByName(sut, "SetQ3Calibration", new object[] { ValidInitFactors });
|
||||
|
||||
Assert.IsFalse(sut.NoSamples);
|
||||
|
||||
sut.CalculateQ3Calibration(200.0, 120.0);
|
||||
|
||||
Assert.IsNotNull(sut.Q3CalibValue);
|
||||
Assert.AreEqual(3, sut.Q3CalibValue.Length);
|
||||
|
||||
Assert.IsTrue(sut.Q3CalibValue.All(v => !Double.IsNaN(v)));
|
||||
Assert.IsTrue(sut.Q3CalibValue.All(v => v >= 0.0));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldCalculateExpectedValues_ForKnownInput()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
var raw = CreateKnownStartEndData(
|
||||
// start volume / end volume / start time / end time
|
||||
(100.0, 150.0, 10.0, 20.0), // dV = 50, dT = 10
|
||||
(105.0, 165.0, 10.0, 22.0), // dV = 60, dT = 12
|
||||
(110.0, 180.0, 10.0, 25.0) // dV = 70, dT = 15
|
||||
);
|
||||
|
||||
SetPrivateField(sut, "_rawStartEndByChannel", raw);
|
||||
SetPrivateField(sut, "_recalculatedStartEndByChannel", raw); // important for NoSamples == false
|
||||
SetPrivateField(sut, "optoDataCount", 2);
|
||||
|
||||
sut.TestStartTelegramIx = 0;
|
||||
sut.TestEndTelegramIx = 1;
|
||||
|
||||
Assert.IsFalse(sut.NoSamples, "Expected prepared data to produce valid samples.");
|
||||
|
||||
var init = new[] { 15625.0, 15625.0, 15625.0 };
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 200.0,
|
||||
refTime: 120.0,
|
||||
initCalibFactor: init,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
double expectedCh1 = (200.0 / 600.0) * 15625.0;
|
||||
double expectedCh2 = (200.0 / 600.0) * 15625.0;
|
||||
double expectedCh3 = (200.0 / 560.0) * 15625.0;
|
||||
|
||||
Assert.AreEqual(expectedCh1, calib[0], 0.0001);
|
||||
Assert.AreEqual(expectedCh2, calib[1], 0.0001);
|
||||
Assert.AreEqual(expectedCh3, calib[2], 0.0001);
|
||||
|
||||
Assert.IsFalse(valid[0]);
|
||||
Assert.IsFalse(valid[1]);
|
||||
Assert.IsFalse(valid[2]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetQ3Calibration_ShouldMarkChannelValid_WhenDifferenceIsWithinFivePercent()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
// We want recalculatedDeltaVolume == refVolume, so calculated factor == initial factor.
|
||||
// refVolume = 200, refTime = 120
|
||||
// choose dT = 10, dV = 16.6666666666667 => coef = 12 => recalculated dV = 200
|
||||
|
||||
var raw = CreateKnownStartEndData(
|
||||
(100.0, 116.6666666666667, 10.0, 20.0),
|
||||
(200.0, 216.6666666666667, 10.0, 20.0),
|
||||
(300.0, 316.6666666666667, 10.0, 20.0)
|
||||
);
|
||||
|
||||
SetPrivateField(sut, "_rawStartEndByChannel", raw);
|
||||
SetPrivateField(sut, "_recalculatedStartEndByChannel", raw);
|
||||
SetPrivateField(sut, "optoDataCount", 2);
|
||||
sut.TestStartTelegramIx = 0;
|
||||
sut.TestEndTelegramIx = 1;
|
||||
|
||||
Assert.IsFalse(sut.NoSamples, "Expected prepared data to produce valid samples.");
|
||||
|
||||
var init = new[] { 15625.0, 15625.0, 15625.0 };
|
||||
var valid = new bool[3];
|
||||
var calib = new double[3];
|
||||
|
||||
sut.GetQ3Calibration(
|
||||
refVolume: 200.0,
|
||||
refTime: 120.0,
|
||||
initCalibFactor: init,
|
||||
ref valid,
|
||||
ref calib);
|
||||
|
||||
Assert.IsTrue(valid[0], $"Ch1 invalid, value={calib[0]}");
|
||||
Assert.IsTrue(valid[1], $"Ch2 invalid, value={calib[1]}");
|
||||
Assert.IsTrue(valid[2], $"Ch3 invalid, value={calib[2]}");
|
||||
|
||||
Assert.AreEqual(15625.0, calib[0], 0.001);
|
||||
Assert.AreEqual(15625.0, calib[1], 0.001);
|
||||
Assert.AreEqual(15625.0, calib[2], 0.001);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CalculateQ3Calibration_ShouldComputeExpectedChannelValues_FromSimulationData()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
|
||||
InvokePrivateByName(sut, "SetQ3Calibration", new object[] { ValidInitFactors });
|
||||
|
||||
sut.CalculateQ3Calibration(200.0, 120.0);
|
||||
|
||||
// initial values remain exposed through Q3CalibValue
|
||||
Assert.AreEqual(15625.0, sut.Q3CalibValue[0], 0.000001);
|
||||
Assert.AreEqual(15625.0, sut.Q3CalibValue[1], 0.000001);
|
||||
Assert.AreEqual(15625.0, sut.Q3CalibValue[2], 0.000001);
|
||||
|
||||
// calculated values
|
||||
Assert.AreEqual(5208.33333333333, sut.Q3Calib_Ch1Value, 0.000001);
|
||||
Assert.AreEqual(5008.01282051282, sut.Q3Calib_Ch2Value, 0.000001);
|
||||
Assert.AreEqual(4822.53086419753, sut.Q3Calib_Ch3Value, 0.000001);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CalculateQ3Calibration_ShouldKeepInitialArray_AndUpdateCalculatedChannelProperties()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
|
||||
InvokePrivateByName(sut, "SetQ3Calibration", new object[] { ValidInitFactors });
|
||||
|
||||
sut.CalculateQ3Calibration(200.0, 120.0);
|
||||
|
||||
// Q3CalibValue currently exposes INITIAL calibration values, not calculated ones
|
||||
Assert.AreEqual(15625.0, sut.Q3CalibValue[0], 0.000001);
|
||||
Assert.AreEqual(15625.0, sut.Q3CalibValue[1], 0.000001);
|
||||
Assert.AreEqual(15625.0, sut.Q3CalibValue[2], 0.000001);
|
||||
|
||||
// Per-channel public properties expose calculated values
|
||||
Assert.IsTrue(sut.Q3Calib_Ch1Value > 0.0);
|
||||
Assert.IsTrue(sut.Q3Calib_Ch2Value > 0.0);
|
||||
Assert.IsTrue(sut.Q3Calib_Ch3Value > 0.0);
|
||||
|
||||
Assert.AreNotEqual(sut.Q3CalibValue[0], sut.Q3Calib_Ch1Value, 0.000001);
|
||||
Assert.AreNotEqual(sut.Q3CalibValue[1], sut.Q3Calib_Ch2Value, 0.000001);
|
||||
Assert.AreNotEqual(sut.Q3CalibValue[2], sut.Q3Calib_Ch3Value, 0.000001);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PrepareCalculatedChannelDataSimulationForTest_ShouldPrepareUsableData()
|
||||
{
|
||||
var sut = new GenesisSmartReader();
|
||||
|
||||
InvokePrivateByName(sut, "PrepareCalculatedChannelDataSimulationForTest");
|
||||
|
||||
Assert.IsFalse(sut.NoSamples);
|
||||
Assert.IsTrue(sut.VolumeLtrStart >= 0.0);
|
||||
Assert.IsTrue(sut.VolumeLtrEnd >= 0.0);
|
||||
Assert.IsTrue(sut.TimestampSecEnd >= sut.TimestampSecStart);
|
||||
}
|
||||
|
||||
private static void InitializeReaderForQ3Test(GenesisSmartReader reader)
|
||||
{
|
||||
SetPrivateField(reader, "_rawStartEndByChannel", null);
|
||||
SetPrivateField(reader, "_recalculatedStartEndByChannel", null);
|
||||
SetPrivateField(reader, "optoDataCount", 0);
|
||||
|
||||
reader.TestStartTelegramIx = -1;
|
||||
reader.TestEndTelegramIx = -1;
|
||||
}
|
||||
|
||||
private static OptoTelegramRaw[][] CreateMinimalStartEndData()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
CreateRecord(0.0, 0.0, 1),
|
||||
CreateRecord(15625.0, 120.0, 1)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
CreateRecord(0.0, 0.0, 2),
|
||||
CreateRecord(15625.0, 120.0, 2)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
CreateRecord(0.0, 0.0, 3),
|
||||
CreateRecord(15625.0, 120.0, 3)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static OptoTelegramRaw[][] CreateKnownStartEndData(
|
||||
(double startVolume, double endVolume, double startTime, double endTime) ch1,
|
||||
(double startVolume, double endVolume, double startTime, double endTime) ch2,
|
||||
(double startVolume, double endVolume, double startTime, double endTime) ch3)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
CreateRecord(ch1.startVolume, ch1.startTime, 1),
|
||||
CreateRecord(ch1.endVolume, ch1.endTime, 1)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
CreateRecord(ch2.startVolume, ch2.startTime, 2),
|
||||
CreateRecord(ch2.endVolume, ch2.endTime, 2)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
CreateRecord(ch3.startVolume, ch3.startTime, 3),
|
||||
CreateRecord(ch3.endVolume, ch3.endTime, 3)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static OptoTelegramRaw CreateRecord(double volumeRawExt, double timestampExt, int channel)
|
||||
{
|
||||
return new OptoTelegramRaw
|
||||
{
|
||||
VolumeRawExt = volumeRawExt,
|
||||
TimestampExt = timestampExt,
|
||||
iChannel = channel,
|
||||
Flags = OptoTelegramFlags.OK
|
||||
};
|
||||
}
|
||||
|
||||
private static object InvokePrivateByName(object target, string methodName, params object[] args)
|
||||
{
|
||||
Type type = target.GetType();
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
var candidates = type.GetMethods(
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Static |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic |
|
||||
BindingFlags.DeclaredOnly)
|
||||
.Where(m => m.Name == methodName)
|
||||
.ToList();
|
||||
|
||||
foreach (var method in candidates)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
|
||||
if (parameters.Length != (args?.Length ?? 0))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
return method.Invoke(target, args);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
Assert.Fail($"Method '{methodName}' not found or no matching overload accepted the provided arguments.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetPrivateField(object target, string fieldName, object value)
|
||||
{
|
||||
Type type = target.GetType();
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
var field = type.GetField(
|
||||
fieldName,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
field.SetValue(target, value);
|
||||
return;
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
Assert.Fail($"Field '{fieldName}' not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,35 +12,36 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
[TestSubject(typeof(CliRunner))]
|
||||
public class CliRunnerTest
|
||||
{
|
||||
|
||||
[TestMethod]
|
||||
public void ExtractJson_Test()
|
||||
{
|
||||
String allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
|
||||
string allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
|
||||
CliRunner cliRunner = new CliRunner(false);
|
||||
string json = cliRunner.ExtractJson(allOutput);
|
||||
|
||||
Assert.IsTrue(!string.IsNullOrEmpty(json));
|
||||
|
||||
Assert.IsFalse(string.IsNullOrEmpty(json));
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void ExtractJson_Test2()
|
||||
{
|
||||
String allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
|
||||
string allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
|
||||
CliRunner cliRunner = new CliRunner(false);
|
||||
string json = cliRunner.ExtractJson(allOutput);
|
||||
|
||||
Assert.IsTrue(!string.IsNullOrEmpty(json));
|
||||
|
||||
Assert.IsFalse(string.IsNullOrEmpty(json));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TryJsonStringDeserialize_Test()
|
||||
{
|
||||
String allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
|
||||
string allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
|
||||
|
||||
CliRunner cliRunner = new CliRunner(false);
|
||||
string json = cliRunner.ExtractJson(allOutput);
|
||||
|
||||
var ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
|
||||
bool ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
|
||||
|
||||
Assert.IsTrue(ok, "Deserialization failed");
|
||||
Assert.IsNotNull(dto);
|
||||
Assert.AreEqual("1000000267", dto.DeviceId);
|
||||
@ -53,120 +54,165 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
[TestMethod]
|
||||
public void RunMultipleTimesTestProgram_CheckParalelWork()
|
||||
{
|
||||
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
|
||||
|
||||
// Check if the executable exists in current directory
|
||||
SerialPortData serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
|
||||
|
||||
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
|
||||
{
|
||||
Assert.Inconclusive($"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
|
||||
Assert.Inconclusive(
|
||||
$"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
CliRunner cliRunner = new CliRunner(false);
|
||||
|
||||
|
||||
CliRunner cliRunnerOne = new CliRunner(false);
|
||||
DateTime StartTime = DateTime.Now;
|
||||
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
DateTime startTime = DateTime.Now;
|
||||
|
||||
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||
serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
|
||||
cliRunnerOne.WaitAll();
|
||||
TimeSpan OneEndTime = DateTime.Now - StartTime;
|
||||
|
||||
StartTime = DateTime.Now;
|
||||
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
||||
|
||||
|
||||
TimeSpan oneEndTime = DateTime.Now - startTime;
|
||||
|
||||
startTime = DateTime.Now;
|
||||
Console.WriteLine($"Start Time Loop: {startTime:yyyy-MM-dd HH:mm:ss}");
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||
serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
}
|
||||
|
||||
cliRunner.WaitAll();
|
||||
|
||||
DateTime EndTime = DateTime.Now;
|
||||
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
||||
TimeSpan delta = EndTime - StartTime;
|
||||
Console.WriteLine($"Delta Time One process {OneEndTime.Hours:D2}:{OneEndTime.Minutes:D2}:{OneEndTime.Seconds:D2}.{OneEndTime.Milliseconds:D3} " +
|
||||
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
|
||||
DateTime endTime = DateTime.Now;
|
||||
Console.WriteLine($"End Time Loop: {endTime:yyyy-MM-dd HH:mm:ss}");
|
||||
|
||||
TimeSpan delta = endTime - startTime;
|
||||
Console.WriteLine(
|
||||
$"Delta Time One process {oneEndTime.Hours:D2}:{oneEndTime.Minutes:D2}:{oneEndTime.Seconds:D2}.{oneEndTime.Milliseconds:D3} " +
|
||||
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
|
||||
Console.WriteLine($"Total tasks: {cliRunner.TaskPool.Count}");
|
||||
|
||||
|
||||
foreach (Task<JsonDataFromPoseidon> task in cliRunner.TaskPool)
|
||||
|
||||
foreach (CliTaskInfo taskInfo in cliRunner.TaskPool)
|
||||
{
|
||||
if (task != null)
|
||||
Assert.IsNotNull(taskInfo);
|
||||
Assert.IsNotNull(taskInfo.Task);
|
||||
|
||||
if (taskInfo.UseResult)
|
||||
{
|
||||
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
|
||||
Assert.IsNotNull(task, "Expected Task<JsonDataFromPoseidon>.");
|
||||
|
||||
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
|
||||
Console.WriteLine($"Result: {jsonDataFromPoseidon.DeviceId}");
|
||||
Console.WriteLine($"Result: {jsonDataFromPoseidon?.DeviceId}");
|
||||
Assert.IsNotNull(jsonDataFromPoseidon);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail($"Task did not complete successfully. State={taskInfo.State}, Status={taskInfo.Task.Status}");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the total time is greater than the sum of the individual times
|
||||
Assert.IsTrue((cliRunner.TaskPool.Count*OneEndTime.Ticks) > delta.Ticks);
|
||||
|
||||
|
||||
Assert.IsTrue((cliRunner.TaskPool.Count * oneEndTime.Ticks) > delta.Ticks);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task RunMultipleTimesTestProgram_CheckParalelWorkCumulative()
|
||||
{
|
||||
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
|
||||
|
||||
// Check if the executable exists in current directory
|
||||
SerialPortData serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
|
||||
|
||||
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
|
||||
{
|
||||
Assert.Inconclusive($"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
|
||||
Assert.Inconclusive(
|
||||
$"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<CliRunner> cliRunnerList = new List<CliRunner>();
|
||||
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
cliRunnerList.Add(new CliRunner(false));
|
||||
|
||||
}
|
||||
|
||||
CliRunner cliRunnerOne = new CliRunner(false);
|
||||
DateTime StartTime = DateTime.Now;
|
||||
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
DateTime startTime = DateTime.Now;
|
||||
|
||||
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||
serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
|
||||
cliRunnerOne.WaitAll();
|
||||
TimeSpan OneEndTime = DateTime.Now - StartTime;
|
||||
|
||||
StartTime = DateTime.Now;
|
||||
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
||||
|
||||
TimeSpan oneEndTime = DateTime.Now - startTime;
|
||||
|
||||
startTime = DateTime.Now;
|
||||
Console.WriteLine($"Start Time Loop: {startTime:yyyy-MM-dd HH:mm:ss}");
|
||||
|
||||
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
|
||||
{
|
||||
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
||||
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||
serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
||||
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||
serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for ALL tasks from ALL runners
|
||||
var allTasks = cliRunnerList.SelectMany(r => r.TaskPool).ToArray();
|
||||
Task[] allTasks = cliRunnerList
|
||||
.SelectMany(r => r.TaskPool)
|
||||
.Where(ti => ti != null && ti.Task != null)
|
||||
.Select(ti => ti.Task)
|
||||
.ToArray();
|
||||
|
||||
await Task.WhenAll(allTasks);
|
||||
|
||||
DateTime EndTime = DateTime.Now;
|
||||
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
||||
TimeSpan delta = EndTime - StartTime;
|
||||
Console.WriteLine($"Delta Time One process {OneEndTime.Hours:D2}:{OneEndTime.Minutes:D2}:{OneEndTime.Seconds:D2}.{OneEndTime.Milliseconds:D3} " +
|
||||
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
|
||||
DateTime endTime = DateTime.Now;
|
||||
Console.WriteLine($"End Time Loop: {endTime:yyyy-MM-dd HH:mm:ss}");
|
||||
|
||||
TimeSpan delta = endTime - startTime;
|
||||
Console.WriteLine(
|
||||
$"Delta Time One process {oneEndTime.Hours:D2}:{oneEndTime.Minutes:D2}:{oneEndTime.Seconds:D2}.{oneEndTime.Milliseconds:D3} " +
|
||||
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
|
||||
Console.WriteLine($"Total tasks: {cliRunnerList.Sum(runner => runner.TaskPool.Count)}");
|
||||
|
||||
|
||||
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
|
||||
{
|
||||
string results = $"iCliRunner: {iCliRunner}";
|
||||
foreach (Task<JsonDataFromPoseidon> task in cliRunnerList[iCliRunner].TaskPool)
|
||||
|
||||
foreach (CliTaskInfo taskInfo in cliRunnerList[iCliRunner].TaskPool)
|
||||
{
|
||||
if (task != null)
|
||||
Assert.IsNotNull(taskInfo);
|
||||
Assert.IsNotNull(taskInfo.Task);
|
||||
|
||||
if (taskInfo.UseResult)
|
||||
{
|
||||
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
|
||||
Assert.IsNotNull(task, "Expected Task<JsonDataFromPoseidon>.");
|
||||
|
||||
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
|
||||
results += ($" ID: {jsonDataFromPoseidon.DeviceId}");
|
||||
results += $" ID: {jsonDataFromPoseidon?.DeviceId}";
|
||||
Assert.IsNotNull(jsonDataFromPoseidon);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail(
|
||||
$"Task did not complete successfully. Runner={iCliRunner}, State={taskInfo.State}, Status={taskInfo.Task.Status}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(results);
|
||||
}
|
||||
|
||||
// Check that the total time is greater than the sum of the individual times
|
||||
Assert.IsTrue((cliRunnerList.Count*OneEndTime.Ticks) > delta.Ticks);
|
||||
Assert.IsTrue((cliRunnerList.Count * oneEndTime.Ticks) > delta.Ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
[TestClass]
|
||||
[TestSubject(typeof(CliRunner))]
|
||||
public class CliRunnerTimeoutTest
|
||||
{
|
||||
private static string GetCmdSleepTestPath()
|
||||
{
|
||||
var serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
|
||||
return serialPort.SerialPortCmdClientPath;
|
||||
}
|
||||
|
||||
private static void EnsureExeExists(string exePath)
|
||||
{
|
||||
if (!File.Exists(exePath))
|
||||
{
|
||||
Assert.Inconclusive(
|
||||
$"Test executable '{exePath}' not found. " +
|
||||
"Please ensure cmdSleepTest.exe exists in the test directory.");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Timeout_ShouldBeDetected_ForLongRunningTask()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
||||
|
||||
await Task.Delay(200);
|
||||
|
||||
bool timedOut = cliRunner.TimeOutReceived(100);
|
||||
|
||||
Assert.IsTrue(timedOut, "Timeout should have been detected.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task CancelUndoneTasksAsTimedOut_ShouldMarkRunningTaskAsTimedOut()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
||||
|
||||
await Task.Delay(150);
|
||||
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.AreEqual(1, cliRunner.TaskPool.Count);
|
||||
|
||||
var taskInfo = cliRunner.TaskPool.Single();
|
||||
|
||||
Assert.IsNotNull(taskInfo);
|
||||
Assert.AreEqual(CliTaskState.TimedOut, taskInfo.State);
|
||||
Assert.IsFalse(taskInfo.UseResult, "Timed out task must not be used.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CancelUndoneTasksAsTimedOut_ShouldKeepCompletedTaskCompleted()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50");
|
||||
|
||||
try
|
||||
{
|
||||
cliRunner.WaitAll();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// let assertions inspect states
|
||||
}
|
||||
|
||||
cliRunner.RefreshTaskStates();
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.AreEqual(1, cliRunner.TaskPool.Count);
|
||||
|
||||
var taskInfo = cliRunner.TaskPool.Single();
|
||||
|
||||
Assert.IsNotNull(taskInfo);
|
||||
Assert.AreEqual(CliTaskState.Completed, taskInfo.State);
|
||||
Assert.IsTrue(taskInfo.UseResult, "Completed task should remain usable.");
|
||||
|
||||
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
|
||||
Assert.IsNotNull(task);
|
||||
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
|
||||
Assert.IsNotNull(task.Result);
|
||||
Assert.IsFalse(string.IsNullOrEmpty(task.Result.DeviceId));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task CancelUndoneTasksAsTimedOut_ShouldKeepDoneTask_AndMarkUndoneTask()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50");
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
||||
|
||||
await Task.Delay(250);
|
||||
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.AreEqual(2, cliRunner.TaskPool.Count);
|
||||
Assert.AreEqual(1, cliRunner.TaskPool.Count(t => t.State == CliTaskState.Completed),
|
||||
"Exactly one fast task should be completed before timeout handling.");
|
||||
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
var doneTask = cliRunner.TaskPool.Single(t => t.State == CliTaskState.Completed);
|
||||
var timedOutTask = cliRunner.TaskPool.Single(t => t.State == CliTaskState.TimedOut);
|
||||
|
||||
Assert.IsTrue(doneTask.UseResult);
|
||||
Assert.IsFalse(timedOutTask.UseResult);
|
||||
|
||||
var completed = doneTask.Task as Task<JsonDataFromPoseidon>;
|
||||
Assert.IsNotNull(completed);
|
||||
Assert.AreEqual(TaskStatus.RanToCompletion, completed.Status);
|
||||
Assert.IsNotNull(completed.Result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task AreTasksDone_ShouldReturnTrue_AfterTimeoutCancellation()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
||||
|
||||
await Task.Delay(150);
|
||||
|
||||
Assert.IsFalse(cliRunner.AreTasksDone(), "Task should still be running before timeout cancellation.");
|
||||
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.IsTrue(cliRunner.AreTasksDone(),
|
||||
"After timed out tasks are marked, runner should report no running tasks.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task TimedOutTask_ShouldNotHaveUseResult()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
||||
|
||||
await Task.Delay(150);
|
||||
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
var taskInfo = cliRunner.TaskPool.Single();
|
||||
|
||||
Assert.AreEqual(CliTaskState.TimedOut, taskInfo.State);
|
||||
Assert.IsFalse(taskInfo.UseResult);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task MultipleSlowTasks_ShouldAllBeMarkedTimedOut()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
||||
}
|
||||
|
||||
await Task.Delay(200);
|
||||
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.AreEqual(5, cliRunner.TaskPool.Count);
|
||||
Assert.AreEqual(5, cliRunner.TaskPool.Count(t => t.State == CliTaskState.TimedOut));
|
||||
Assert.AreEqual(0, cliRunner.TaskPool.Count(t => t.UseResult));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void FastTask_WithInvalidJson_ShouldFinishButNotProduceUsefulResult()
|
||||
{
|
||||
string exePath = GetCmdSleepTestPath();
|
||||
EnsureExeExists(exePath);
|
||||
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50 invalidjson=true");
|
||||
|
||||
try
|
||||
{
|
||||
cliRunner.WaitAll();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.AreEqual(1, cliRunner.TaskPool.Count);
|
||||
|
||||
var taskInfo = cliRunner.TaskPool.Single();
|
||||
Assert.AreEqual(CliTaskState.Completed, taskInfo.State);
|
||||
|
||||
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
|
||||
Assert.IsNotNull(task);
|
||||
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
|
||||
|
||||
// depending on your TryJsonStringDeserialize fallback,
|
||||
// result may be null or an empty/default object
|
||||
// so avoid asserting UseResult=false here
|
||||
// instead assert no valid device id
|
||||
if (task.Result != null)
|
||||
{
|
||||
Assert.IsTrue(string.IsNullOrEmpty(task.Result.DeviceId),
|
||||
"Invalid JSON should not produce a valid DeviceId.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
[TestClass]
|
||||
[TestSubject(typeof(CliRunner))]
|
||||
public class CliRunnerTimeoutUnitTest
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task CancelUndoneTasksAsTimedOut_ShouldMarkOnlyRunningTasks()
|
||||
{
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
var completedTask = Task.FromResult("done");
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var runningTask = Task.Delay(TimeSpan.FromSeconds(30), cts.Token);
|
||||
|
||||
cliRunner.AddTaskForTest(completedTask, "completed");
|
||||
cliRunner.AddTaskForTest(runningTask, "running", cts);
|
||||
|
||||
await Task.Delay(50);
|
||||
|
||||
cliRunner.RefreshTaskStates();
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.AreEqual(2, cliRunner.TaskPool.Count);
|
||||
|
||||
var completed = cliRunner.TaskPool.First(t => t.Name == "completed");
|
||||
var timedOut = cliRunner.TaskPool.First(t => t.Name == "running");
|
||||
|
||||
Assert.AreEqual(CliTaskState.Completed, completed.State);
|
||||
Assert.IsTrue(completed.UseResult);
|
||||
|
||||
Assert.AreEqual(CliTaskState.TimedOut, timedOut.State);
|
||||
Assert.IsFalse(timedOut.UseResult);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TimeOutReceived_ShouldReturnTrue_WhenElapsedExceedsTimeout()
|
||||
{
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
Thread.Sleep(30);
|
||||
|
||||
Assert.IsTrue(cliRunner.TimeOutReceived(1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task AreTasksDone_ShouldReturnTrue_WhenTimedOutTasksAreMarked()
|
||||
{
|
||||
var cliRunner = new CliRunner(false);
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var runningTask = Task.Delay(TimeSpan.FromSeconds(30), cts.Token);
|
||||
|
||||
cliRunner.AddTaskForTest(runningTask, "running", cts);
|
||||
|
||||
await Task.Delay(50);
|
||||
|
||||
Assert.IsFalse(cliRunner.AreTasksDone());
|
||||
|
||||
cliRunner.CancelUndoneTasksAsTimedOut();
|
||||
cliRunner.RefreshTaskStates();
|
||||
|
||||
Assert.IsTrue(cliRunner.AreTasksDone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,8 +111,10 @@
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisReaderTests.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReaderChannelAveragingTests.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReaderChannelTests.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReaderStopTests.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReaderTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReaderThreadedReadTests.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReader_Q3Test.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\diagnosticLed\DiagnosticLedParserTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\hexLogger\HexFormatterTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\IperlHatProtocol\IperlHatFrameBuilderTests.cs" />
|
||||
@ -123,6 +125,8 @@
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadBaudRateDetectionTests.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadFrameBuilderTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutUnitTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
||||
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user