Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
842f009b42 | ||
|
|
7f30ca0cd1 | ||
|
|
93e207c211 | ||
|
|
64cafc088a | ||
|
|
8a0da27a07 | ||
|
|
5a8478e782 | ||
|
|
368cd95114 | ||
|
|
33ef914984 | ||
|
|
3eb0b87f0d | ||
|
|
711dfc03ef | ||
|
|
93459ccfab | ||
|
|
009aefb7c9 | ||
|
|
d2e18d615d | ||
|
|
69b475eb77 | ||
|
|
2210bb8240 | ||
|
|
3376ac41b4 | ||
|
|
f9181fee74 | ||
|
|
65ab19290f | ||
|
|
94c7279da1 | ||
|
|
2136695b80 | ||
|
|
c0f9b0ffa0 | ||
|
|
c4ef22436f | ||
|
|
0b73871518 | ||
|
|
f7dc6fee5e | ||
|
|
ba848a167d | ||
|
|
dcb0bf9a88 | ||
|
|
f6433134c1 | ||
|
|
7e3df77b5b | ||
|
|
ff5954d85b | ||
|
|
08dff1272b | ||
|
|
c09e266b2c | ||
|
|
d5c8fd1c8f | ||
|
|
a34740e838 | ||
|
|
836ba5a41f | ||
|
|
23c83ab452 | ||
|
|
bc9e583c29 |
@@ -19,6 +19,9 @@ using System.Runtime.InteropServices;
|
|||||||
// COM, set the ComVisible attribute to true on that type.
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
[assembly: ComVisible(false)]
|
[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
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
[assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")]
|
[assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")]
|
||||||
|
|
||||||
@@ -29,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||||||
// Build Number
|
// Build Number
|
||||||
// Revision
|
// Revision
|
||||||
//
|
//
|
||||||
[assembly: AssemblyVersion("3.9.3013.1")]
|
[assembly: AssemblyVersion("3.9.3058.1")]
|
||||||
[assembly: AssemblyFileVersion("3.9.3013.1")]
|
[assembly: AssemblyFileVersion("3.9.3058.1")]
|
||||||
|
|||||||
Generated
+9
-1
@@ -1,7 +1,6 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// 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>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Test in progress.
|
/// Looks up a localized string similar to Test in progress.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Generated
+5012
File diff suppressed because it is too large
Load Diff
@@ -1764,4 +1764,7 @@
|
|||||||
<data name="Units" xml:space="preserve">
|
<data name="Units" xml:space="preserve">
|
||||||
<value />
|
<value />
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Test_in_calculation" xml:space="preserve">
|
||||||
|
<value>Probíhá výpočet</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -2482,4 +2482,7 @@
|
|||||||
<data name="Units" xml:space="preserve">
|
<data name="Units" xml:space="preserve">
|
||||||
<value>Units</value>
|
<value>Units</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Test_in_calculation" xml:space="preserve">
|
||||||
|
<value>Test in calculation</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -259,4 +259,7 @@
|
|||||||
<data name="Units" xml:space="preserve">
|
<data name="Units" xml:space="preserve">
|
||||||
<value />
|
<value />
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Test_in_calculation" xml:space="preserve">
|
||||||
|
<value>Prebieha výpočet</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -111,6 +111,7 @@ namespace TBF.Rig.BuiltIn.PumpTandem
|
|||||||
|
|
||||||
public void TurnOff()
|
public void TurnOff()
|
||||||
{
|
{
|
||||||
|
log.DebugFormat("{0}.TurnOff()", Name);
|
||||||
if ((pumpFm1 != null) && (pumpFm2 != null))
|
if ((pumpFm1 != null) && (pumpFm2 != null))
|
||||||
{
|
{
|
||||||
pumpFm1.TurnOff();
|
pumpFm1.TurnOff();
|
||||||
@@ -120,6 +121,7 @@ namespace TBF.Rig.BuiltIn.PumpTandem
|
|||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
log.DebugFormat("DONE {0}.TurnOff()", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -175,8 +175,8 @@ namespace TBF.Rig.ControlBoard.Uni
|
|||||||
double reqFlowLo = (0.7 * qFrom) + (0.3 * reqFlowAve); /// Move the lower limit 15% of the range up
|
double reqFlowLo = (0.7 * qFrom) + (0.3 * reqFlowAve); /// Move the lower limit 15% of the range up
|
||||||
double reqFlowHi = (0.7 * qTo) + (0.3 * reqFlowAve); /// Move the upper limit 15% of the range down
|
double reqFlowHi = (0.7 * qTo) + (0.3 * reqFlowAve); /// Move the upper limit 15% of the range down
|
||||||
///
|
///
|
||||||
uniCB.SetFlow(false, regV.Idx1, 2000.0 * reqFlowLo / flowMeter.NominalFlow,
|
uniCB.SetFlow(false, regV.Idx1, flowMeter.NominalFreq * reqFlowLo / flowMeter.NominalFlow,
|
||||||
2000.0 * reqFlowHi / flowMeter.NominalFlow);
|
flowMeter.NominalFreq * reqFlowHi / flowMeter.NominalFlow);
|
||||||
if (readDivTransition)
|
if (readDivTransition)
|
||||||
{
|
{
|
||||||
/// Schedule reading diverter transition data
|
/// Schedule reading diverter transition data
|
||||||
|
|||||||
@@ -803,12 +803,60 @@ namespace TBF.Rig.ControlBoard.Uni
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetFlow(bool isFromUI, int regVId, double freqLo, double freqHi, int regulationMinStep = 0)
|
public void SetFlow(bool isFromUI, int regVId, double freqLo, double freqHi, int regulationMinStep = 0)
|
||||||
{
|
{
|
||||||
if (IsUIBlocked && isFromUI) return;
|
LiveLogDiag.Log1("----------------------------------------");
|
||||||
|
LiveLogDiag.Log1(
|
||||||
|
"SetFlow() >> ENTER isFromUI={0} regVId={1} freqLo={2} freqHi={3} regulationMinStep={4} IsUIBlocked={5}",
|
||||||
|
isFromUI, regVId, freqLo, freqHi, regulationMinStep, IsUIBlocked);
|
||||||
|
|
||||||
actionQueue.Enqueue(Action.SetFlow(isFromUI, regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)), 200, regulationMinStep));
|
if (IsUIBlocked && isFromUI)
|
||||||
log.InfoFormat("Enqueue( SetFlow(rv={0}, fLo={1}, fHi={2}, pid={3}) )", regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)));
|
{
|
||||||
|
LiveLogDiag.Log1(
|
||||||
|
"SetFlow() >> EXIT (UI BLOCKED) isFromUI={0}",
|
||||||
|
isFromUI);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var a in actionQueue) log.DebugFormat(" {0}", a);
|
int pid = Convert.ToInt32(Math.Round(Devices.PidCoef));
|
||||||
|
int fixedParam = 200;
|
||||||
|
|
||||||
|
LiveLogDiag.Log1(
|
||||||
|
"SetFlow() >> PREPARE pid={0} fixedParam={1} regulationMinStep={2}",
|
||||||
|
pid, fixedParam, regulationMinStep);
|
||||||
|
|
||||||
|
var action = Action.SetFlow(
|
||||||
|
isFromUI,
|
||||||
|
regVId,
|
||||||
|
freqLo,
|
||||||
|
freqHi,
|
||||||
|
pid,
|
||||||
|
fixedParam,
|
||||||
|
regulationMinStep);
|
||||||
|
|
||||||
|
LiveLogDiag.Log1(
|
||||||
|
"SetFlow() >> ACTION CREATED: rv={0} fLo={1} fHi={2} pid={3} p6={4} minStep={5}",
|
||||||
|
regVId, freqLo, freqHi, pid, fixedParam, regulationMinStep);
|
||||||
|
|
||||||
|
actionQueue.Enqueue(action);
|
||||||
|
|
||||||
|
LiveLogDiag.Log1(
|
||||||
|
"SetFlow() >> ENQUEUED actionQueue.Count={0}",
|
||||||
|
actionQueue.Count);
|
||||||
|
|
||||||
|
log.InfoFormat(
|
||||||
|
"Enqueue( SetFlow(rv={0}, fLo={1}, fHi={2}, pid={3}) )",
|
||||||
|
regVId, freqLo, freqHi, pid);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var a in actionQueue)
|
||||||
|
{
|
||||||
|
LiveLogDiag.Log1(
|
||||||
|
"SetFlow() >> QUEUE[{0}] = {1}",
|
||||||
|
i++, a);
|
||||||
|
log.DebugFormat(" {0}", a);
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveLogDiag.Log1("SetFlow() >> EXIT");
|
||||||
|
LiveLogDiag.Log1("----------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartTest(bool isFromUI, int flowMId, int divId, int divThreshold,
|
public void StartTest(bool isFromUI, int flowMId, int divId, int divThreshold,
|
||||||
@@ -981,5 +1029,18 @@ namespace TBF.Rig.ControlBoard.Uni
|
|||||||
{
|
{
|
||||||
/// TODO
|
/// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logging
|
||||||
|
/// For activation use compilation condition: LIVELOGDIAG_FlowMeter_cs
|
||||||
|
/// </summary>
|
||||||
|
static class LiveLogDiag
|
||||||
|
{
|
||||||
|
[Conditional("LIVELOGDIAG_UniCB_cs")]
|
||||||
|
public static void Log1(string format, params object[] args)
|
||||||
|
{
|
||||||
|
LiveLogCache.Instance.AddLog("UniCB.cs LOG>> " + string.Format(format, args));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,6 +332,8 @@ namespace TBF.Rig.Danfoss.VLT2800
|
|||||||
Telegram.UpdateTelegramChecksum(msg);
|
Telegram.UpdateTelegramChecksum(msg);
|
||||||
}
|
}
|
||||||
SendData(msg);
|
SendData(msg);
|
||||||
|
|
||||||
|
log.DebugFormat("DONE {0}.TurnOff()", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,8 @@ namespace TBF.Rig.Modbus.PumpFM.DanfossVLT
|
|||||||
|
|
||||||
modbus.SendMessage(msg, Name);
|
modbus.SendMessage(msg, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.DebugFormat("DONE {0}.TurnOff()", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -416,6 +416,8 @@ namespace TBF.Rig.Modbus.PumpFM.Grundfoss
|
|||||||
// --- DIAGNOSTIKA ---
|
// --- DIAGNOSTIKA ---
|
||||||
LiveLogDiag.Log1("GF TurnOff msg = " + BitConverter.ToString(msg));
|
LiveLogDiag.Log1("GF TurnOff msg = " + BitConverter.ToString(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.DebugFormat("DONE {0}.TurnOff()", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
{
|
{
|
||||||
return new GenesisCfgCtrl();
|
return new GenesisCfgCtrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Serialized parameters
|
/// 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 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 int Group; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
|
||||||
public CommunicationInterface CommunicationInterface; /// Communication Interface: RFID or NFC
|
public CommunicationInterface CommunicationInterface; /// Communication Interface: RFID or NFC
|
||||||
///
|
public bool EnableShowChanels;
|
||||||
|
public int IBeginDataFlush;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Procedure parameters </summary>
|
/// <summary> Procedure parameters </summary>
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
@@ -56,6 +56,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
ProcParams = CreateProcParamsProvider() as ProcParams;
|
ProcParams = CreateProcParamsProvider() as ProcParams;
|
||||||
CommunicationInterface = CommunicationInterface.RFID;
|
CommunicationInterface = CommunicationInterface.RFID;
|
||||||
HeadCommunicationComPortNr = 0;
|
HeadCommunicationComPortNr = 0;
|
||||||
|
EnableShowChanels = false;
|
||||||
|
IBeginDataFlush = 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenesisCfg(IComponentFactory factory)
|
public GenesisCfg(IComponentFactory factory)
|
||||||
@@ -67,7 +69,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
|
|
||||||
public string ToString(int i)
|
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();
|
muxBoardNrTextBox.Text = config.MuxBoardNr.ToString();
|
||||||
groupTextBox.Text = config.Group.ToString();
|
groupTextBox.Text = config.Group.ToString();
|
||||||
comboBoxCommunicationInterface.SelectedItem = config.CommunicationInterface.ToString();
|
comboBoxCommunicationInterface.SelectedItem = config.CommunicationInterface.ToString();
|
||||||
|
tBBeginDataFlush.Text = config.IBeginDataFlush.ToString();
|
||||||
|
checkBox_EnableShowChanels.Checked = config.EnableShowChanels;
|
||||||
|
|
||||||
tabPage2.Controls.Add(new GenesisHeadTestCtrl(config));
|
tabPage2.Controls.Add(new GenesisHeadTestCtrl(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +77,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
muxBoardNrTextBox.Enabled = true;
|
muxBoardNrTextBox.Enabled = true;
|
||||||
groupTextBox.Enabled = true;
|
groupTextBox.Enabled = true;
|
||||||
comboBoxCommunicationInterface.Enabled = true;
|
comboBoxCommunicationInterface.Enabled = true;
|
||||||
|
tBBeginDataFlush.Enabled = true;
|
||||||
|
checkBox_EnableShowChanels.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||||
@@ -129,6 +134,12 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
flags |= CfgUpdateFlags.Error;
|
flags |= CfgUpdateFlags.Error;
|
||||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, groupLabel.Text);
|
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;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -158,6 +169,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
config.Group = int.Parse(groupTextBox.Text);
|
config.Group = int.Parse(groupTextBox.Text);
|
||||||
config.CommunicationInterface = (CommunicationInterface)comboBoxCommunicationInterface.SelectedIndex;
|
config.CommunicationInterface = (CommunicationInterface)comboBoxCommunicationInterface.SelectedIndex;
|
||||||
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
|
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
|
||||||
|
config.IBeginDataFlush = int.Parse(tBBeginDataFlush.Text);
|
||||||
|
config.EnableShowChanels = checkBox_EnableShowChanels.Checked;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|||||||
+421
-376
@@ -25,388 +25,433 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
|
|||||||
|
|
||||||
#region Component Designer generated code
|
#region Component Designer generated code
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required method for Designer support - do not modify
|
/// Required method for Designer support - do not modify
|
||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||||
this.label4 = new System.Windows.Forms.Label();
|
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||||
this.label3 = new System.Windows.Forms.Label();
|
this.headPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
this.label1 = new System.Windows.Forms.Label();
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
|
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
|
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
|
||||||
this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
this.tcpipPortLabel = new System.Windows.Forms.Label();
|
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.tcpipPortTextBox = new System.Windows.Forms.TextBox();
|
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
|
||||||
this.ipAddressLabel = new System.Windows.Forms.Label();
|
this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
|
||||||
this.ipAddressTextBox = new System.Windows.Forms.TextBox();
|
this.checkBox_EnableShowChanels = new System.Windows.Forms.CheckBox();
|
||||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
this.tBBeginDataFlush = new System.Windows.Forms.TextBox();
|
||||||
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
this.labelFlush = new System.Windows.Forms.Label();
|
||||||
this.optoSerialPortLabel = new System.Windows.Forms.Label();
|
this.tcpipPortLabel = new System.Windows.Forms.Label();
|
||||||
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
|
this.tcpipPortTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.groupTextBox = new System.Windows.Forms.TextBox();
|
this.ipAddressLabel = new System.Windows.Forms.Label();
|
||||||
this.groupLabel = new System.Windows.Forms.Label();
|
this.ipAddressTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.muxBoardNrTextBox = new System.Windows.Forms.TextBox();
|
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
||||||
this.muxBoardNrLabel = new System.Windows.Forms.Label();
|
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
||||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
this.optoSerialPortLabel = new System.Windows.Forms.Label();
|
||||||
this.nameLabel = new System.Windows.Forms.Label();
|
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.classNameLabel = new System.Windows.Forms.Label();
|
this.groupTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
this.groupLabel = new System.Windows.Forms.Label();
|
||||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
this.muxBoardNrTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.label2 = new System.Windows.Forms.Label();
|
this.muxBoardNrLabel = new System.Windows.Forms.Label();
|
||||||
this.headPortNrTextBox = new System.Windows.Forms.TextBox();
|
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.tabControl1.SuspendLayout();
|
this.nameLabel = new System.Windows.Forms.Label();
|
||||||
this.tabPage1.SuspendLayout();
|
this.classNameLabel = new System.Windows.Forms.Label();
|
||||||
this.groupBox1.SuspendLayout();
|
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||||
this.optoDataGroupBox.SuspendLayout();
|
this.tabControl1.SuspendLayout();
|
||||||
this.groupBox2.SuspendLayout();
|
this.tabPage1.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.groupBox2.SuspendLayout();
|
||||||
//
|
this.groupBox1.SuspendLayout();
|
||||||
// tabControl1
|
this.optoDataGroupBox.SuspendLayout();
|
||||||
//
|
this.SuspendLayout();
|
||||||
this.tabControl1.Controls.Add(this.tabPage1);
|
//
|
||||||
this.tabControl1.Controls.Add(this.tabPage2);
|
// tabControl1
|
||||||
this.tabControl1.Location = new System.Drawing.Point(3, 3);
|
//
|
||||||
this.tabControl1.Name = "tabControl1";
|
this.tabControl1.Controls.Add(this.tabPage1);
|
||||||
this.tabControl1.SelectedIndex = 0;
|
this.tabControl1.Controls.Add(this.tabPage2);
|
||||||
this.tabControl1.Size = new System.Drawing.Size(611, 432);
|
this.tabControl1.Location = new System.Drawing.Point(3, 4);
|
||||||
this.tabControl1.TabIndex = 0;
|
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
//
|
this.tabControl1.Name = "tabControl1";
|
||||||
// tabPage1
|
this.tabControl1.SelectedIndex = 0;
|
||||||
//
|
this.tabControl1.Size = new System.Drawing.Size(687, 540);
|
||||||
this.tabPage1.Controls.Add(this.groupBox2);
|
this.tabControl1.TabIndex = 0;
|
||||||
this.tabPage1.Controls.Add(this.label4);
|
//
|
||||||
this.tabPage1.Controls.Add(this.label3);
|
// tabPage1
|
||||||
this.tabPage1.Controls.Add(this.groupBox1);
|
//
|
||||||
this.tabPage1.Controls.Add(this.optoDataGroupBox);
|
this.tabPage1.Controls.Add(this.groupBox2);
|
||||||
this.tabPage1.Controls.Add(this.groupTextBox);
|
this.tabPage1.Controls.Add(this.label4);
|
||||||
this.tabPage1.Controls.Add(this.groupLabel);
|
this.tabPage1.Controls.Add(this.label3);
|
||||||
this.tabPage1.Controls.Add(this.muxBoardNrTextBox);
|
this.tabPage1.Controls.Add(this.groupBox1);
|
||||||
this.tabPage1.Controls.Add(this.muxBoardNrLabel);
|
this.tabPage1.Controls.Add(this.optoDataGroupBox);
|
||||||
this.tabPage1.Controls.Add(this.nameTextBox);
|
this.tabPage1.Controls.Add(this.groupTextBox);
|
||||||
this.tabPage1.Controls.Add(this.nameLabel);
|
this.tabPage1.Controls.Add(this.groupLabel);
|
||||||
this.tabPage1.Controls.Add(this.classNameLabel);
|
this.tabPage1.Controls.Add(this.muxBoardNrTextBox);
|
||||||
this.tabPage1.Location = new System.Drawing.Point(4, 25);
|
this.tabPage1.Controls.Add(this.muxBoardNrLabel);
|
||||||
this.tabPage1.Name = "tabPage1";
|
this.tabPage1.Controls.Add(this.nameTextBox);
|
||||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage1.Controls.Add(this.nameLabel);
|
||||||
this.tabPage1.Size = new System.Drawing.Size(603, 403);
|
this.tabPage1.Controls.Add(this.classNameLabel);
|
||||||
this.tabPage1.TabIndex = 0;
|
this.tabPage1.Location = new System.Drawing.Point(4, 29);
|
||||||
this.tabPage1.Text = "Config";
|
this.tabPage1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
this.tabPage1.UseVisualStyleBackColor = true;
|
this.tabPage1.Name = "tabPage1";
|
||||||
//
|
this.tabPage1.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
// label4
|
this.tabPage1.Size = new System.Drawing.Size(679, 507);
|
||||||
//
|
this.tabPage1.TabIndex = 0;
|
||||||
this.label4.AutoSize = true;
|
this.tabPage1.Text = "Config";
|
||||||
this.label4.Location = new System.Drawing.Point(208, 101);
|
this.tabPage1.UseVisualStyleBackColor = true;
|
||||||
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
//
|
||||||
this.label4.Name = "label4";
|
// groupBox2
|
||||||
this.label4.Size = new System.Drawing.Size(40, 16);
|
//
|
||||||
this.label4.TabIndex = 25;
|
this.groupBox2.Controls.Add(this.headPortNrTextBox);
|
||||||
this.label4.Text = "1 .. 10";
|
this.groupBox2.Controls.Add(this.label2);
|
||||||
//
|
this.groupBox2.Location = new System.Drawing.Point(11, 450);
|
||||||
// label3
|
this.groupBox2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
//
|
this.groupBox2.Name = "groupBox2";
|
||||||
this.label3.AutoSize = true;
|
this.groupBox2.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
this.label3.Location = new System.Drawing.Point(208, 72);
|
this.groupBox2.Size = new System.Drawing.Size(621, 52);
|
||||||
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.groupBox2.TabIndex = 26;
|
||||||
this.label3.Name = "label3";
|
this.groupBox2.TabStop = false;
|
||||||
this.label3.Size = new System.Drawing.Size(33, 16);
|
this.groupBox2.Text = "Head Communication";
|
||||||
this.label3.TabIndex = 24;
|
//
|
||||||
this.label3.Text = "1 .. 4";
|
// headPortNrTextBox
|
||||||
//
|
//
|
||||||
// groupBox1
|
this.headPortNrTextBox.Enabled = false;
|
||||||
//
|
this.headPortNrTextBox.Location = new System.Drawing.Point(494, 19);
|
||||||
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
|
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.groupBox1.Controls.Add(this.label1);
|
this.headPortNrTextBox.Name = "headPortNrTextBox";
|
||||||
this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
|
this.headPortNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||||
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
|
this.headPortNrTextBox.TabIndex = 8;
|
||||||
this.groupBox1.Location = new System.Drawing.Point(10, 259);
|
//
|
||||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4);
|
// label2
|
||||||
this.groupBox1.Name = "groupBox1";
|
//
|
||||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4);
|
this.label2.AutoSize = true;
|
||||||
this.groupBox1.Size = new System.Drawing.Size(552, 68);
|
this.label2.Location = new System.Drawing.Point(361, 22);
|
||||||
this.groupBox1.TabIndex = 23;
|
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.groupBox1.TabStop = false;
|
this.label2.Name = "label2";
|
||||||
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
|
this.label2.Size = new System.Drawing.Size(107, 20);
|
||||||
//
|
this.label2.TabIndex = 7;
|
||||||
// comboBoxCommunicationInterface
|
this.label2.Text = "Serial port nr.:";
|
||||||
//
|
//
|
||||||
this.comboBoxCommunicationInterface.Enabled = false;
|
// label4
|
||||||
this.comboBoxCommunicationInterface.FormattingEnabled = true;
|
//
|
||||||
this.comboBoxCommunicationInterface.Items.AddRange(new object[] {
|
this.label4.AutoSize = true;
|
||||||
"RFID",
|
this.label4.Location = new System.Drawing.Point(234, 126);
|
||||||
"NFC"});
|
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(201, 27);
|
this.label4.Name = "label4";
|
||||||
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
|
this.label4.Size = new System.Drawing.Size(52, 20);
|
||||||
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(71, 24);
|
this.label4.TabIndex = 25;
|
||||||
this.comboBoxCommunicationInterface.TabIndex = 9;
|
this.label4.Text = "1 .. 10";
|
||||||
//
|
//
|
||||||
// label1
|
// label3
|
||||||
//
|
//
|
||||||
this.label1.AutoSize = true;
|
this.label3.AutoSize = true;
|
||||||
this.label1.Location = new System.Drawing.Point(41, 30);
|
this.label3.Location = new System.Drawing.Point(234, 90);
|
||||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.label1.Name = "label1";
|
this.label3.Name = "label3";
|
||||||
this.label1.Size = new System.Drawing.Size(153, 16);
|
this.label3.Size = new System.Drawing.Size(43, 20);
|
||||||
this.label1.TabIndex = 8;
|
this.label3.TabIndex = 24;
|
||||||
this.label1.Text = "Communication Interface";
|
this.label3.Text = "1 .. 4";
|
||||||
//
|
//
|
||||||
// rfidPortNrTextBox
|
// groupBox1
|
||||||
//
|
//
|
||||||
this.rfidPortNrTextBox.Enabled = false;
|
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
|
||||||
this.rfidPortNrTextBox.Location = new System.Drawing.Point(439, 26);
|
this.groupBox1.Controls.Add(this.label1);
|
||||||
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
|
||||||
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
|
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
|
||||||
this.rfidPortNrTextBox.Size = new System.Drawing.Size(44, 22);
|
this.groupBox1.Location = new System.Drawing.Point(11, 363);
|
||||||
this.rfidPortNrTextBox.TabIndex = 7;
|
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
//
|
this.groupBox1.Name = "groupBox1";
|
||||||
// rfidSerialPortNrLabel
|
this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
//
|
this.groupBox1.Size = new System.Drawing.Size(621, 85);
|
||||||
this.rfidSerialPortNrLabel.AutoSize = true;
|
this.groupBox1.TabIndex = 23;
|
||||||
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(321, 30);
|
this.groupBox1.TabStop = false;
|
||||||
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
|
||||||
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
|
//
|
||||||
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(88, 16);
|
// comboBoxCommunicationInterface
|
||||||
this.rfidSerialPortNrLabel.TabIndex = 6;
|
//
|
||||||
this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
|
this.comboBoxCommunicationInterface.Enabled = false;
|
||||||
//
|
this.comboBoxCommunicationInterface.FormattingEnabled = true;
|
||||||
// optoDataGroupBox
|
this.comboBoxCommunicationInterface.Items.AddRange(new object[] { "RFID", "NFC" });
|
||||||
//
|
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(226, 34);
|
||||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel);
|
this.comboBoxCommunicationInterface.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox);
|
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
|
||||||
this.optoDataGroupBox.Controls.Add(this.ipAddressLabel);
|
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(79, 28);
|
||||||
this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox);
|
this.comboBoxCommunicationInterface.TabIndex = 9;
|
||||||
this.optoDataGroupBox.Controls.Add(this.radioButton1);
|
//
|
||||||
this.optoDataGroupBox.Controls.Add(this.radioButton2);
|
// label1
|
||||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
|
//
|
||||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
|
this.label1.AutoSize = true;
|
||||||
this.optoDataGroupBox.Location = new System.Drawing.Point(10, 131);
|
this.label1.Location = new System.Drawing.Point(46, 38);
|
||||||
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4);
|
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.optoDataGroupBox.Name = "optoDataGroupBox";
|
this.label1.Name = "label1";
|
||||||
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4);
|
this.label1.Size = new System.Drawing.Size(187, 20);
|
||||||
this.optoDataGroupBox.Size = new System.Drawing.Size(552, 119);
|
this.label1.TabIndex = 8;
|
||||||
this.optoDataGroupBox.TabIndex = 18;
|
this.label1.Text = "Communication Interface";
|
||||||
this.optoDataGroupBox.TabStop = false;
|
//
|
||||||
this.optoDataGroupBox.Text = "Opto-data";
|
// rfidPortNrTextBox
|
||||||
//
|
//
|
||||||
// tcpipPortLabel
|
this.rfidPortNrTextBox.Enabled = false;
|
||||||
//
|
this.rfidPortNrTextBox.Location = new System.Drawing.Point(494, 32);
|
||||||
this.tcpipPortLabel.AutoSize = true;
|
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.tcpipPortLabel.Location = new System.Drawing.Point(41, 87);
|
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
|
||||||
this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.rfidPortNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||||
this.tcpipPortLabel.Name = "tcpipPortLabel";
|
this.rfidPortNrTextBox.TabIndex = 7;
|
||||||
this.tcpipPortLabel.Size = new System.Drawing.Size(54, 16);
|
//
|
||||||
this.tcpipPortLabel.TabIndex = 4;
|
// rfidSerialPortNrLabel
|
||||||
this.tcpipPortLabel.Text = "Port nr..:";
|
//
|
||||||
//
|
this.rfidSerialPortNrLabel.AutoSize = true;
|
||||||
// tcpipPortTextBox
|
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(361, 38);
|
||||||
//
|
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.tcpipPortTextBox.Enabled = false;
|
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
|
||||||
this.tcpipPortTextBox.Location = new System.Drawing.Point(143, 84);
|
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(107, 20);
|
||||||
this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.rfidSerialPortNrLabel.TabIndex = 6;
|
||||||
this.tcpipPortTextBox.Name = "tcpipPortTextBox";
|
this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
|
||||||
this.tcpipPortTextBox.Size = new System.Drawing.Size(51, 22);
|
//
|
||||||
this.tcpipPortTextBox.TabIndex = 5;
|
// optoDataGroupBox
|
||||||
//
|
//
|
||||||
// ipAddressLabel
|
this.optoDataGroupBox.Controls.Add(this.checkBox_EnableShowChanels);
|
||||||
//
|
this.optoDataGroupBox.Controls.Add(this.tBBeginDataFlush);
|
||||||
this.ipAddressLabel.AutoSize = true;
|
this.optoDataGroupBox.Controls.Add(this.labelFlush);
|
||||||
this.ipAddressLabel.Location = new System.Drawing.Point(41, 59);
|
this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel);
|
||||||
this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox);
|
||||||
this.ipAddressLabel.Name = "ipAddressLabel";
|
this.optoDataGroupBox.Controls.Add(this.ipAddressLabel);
|
||||||
this.ipAddressLabel.Size = new System.Drawing.Size(78, 16);
|
this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox);
|
||||||
this.ipAddressLabel.TabIndex = 2;
|
this.optoDataGroupBox.Controls.Add(this.radioButton1);
|
||||||
this.ipAddressLabel.Text = "IP address.:";
|
this.optoDataGroupBox.Controls.Add(this.radioButton2);
|
||||||
//
|
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
|
||||||
// ipAddressTextBox
|
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
|
||||||
//
|
this.optoDataGroupBox.Location = new System.Drawing.Point(11, 164);
|
||||||
this.ipAddressTextBox.Enabled = false;
|
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.ipAddressTextBox.Location = new System.Drawing.Point(143, 55);
|
this.optoDataGroupBox.Name = "optoDataGroupBox";
|
||||||
this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.ipAddressTextBox.Name = "ipAddressTextBox";
|
this.optoDataGroupBox.Size = new System.Drawing.Size(621, 189);
|
||||||
this.ipAddressTextBox.Size = new System.Drawing.Size(129, 22);
|
this.optoDataGroupBox.TabIndex = 18;
|
||||||
this.ipAddressTextBox.TabIndex = 3;
|
this.optoDataGroupBox.TabStop = false;
|
||||||
//
|
this.optoDataGroupBox.Text = "Opto-data";
|
||||||
// radioButton1
|
//
|
||||||
//
|
// checkBox_EnableShowChanels
|
||||||
this.radioButton1.AutoSize = true;
|
//
|
||||||
this.radioButton1.Checked = true;
|
this.checkBox_EnableShowChanels.Checked = true;
|
||||||
this.radioButton1.Enabled = false;
|
this.checkBox_EnableShowChanels.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
this.radioButton1.Location = new System.Drawing.Point(29, 23);
|
this.checkBox_EnableShowChanels.Enabled = false;
|
||||||
this.radioButton1.Margin = new System.Windows.Forms.Padding(4);
|
this.checkBox_EnableShowChanels.Location = new System.Drawing.Point(351, 147);
|
||||||
this.radioButton1.Name = "radioButton1";
|
this.checkBox_EnableShowChanels.Name = "checkBox_EnableShowChanels";
|
||||||
this.radioButton1.Size = new System.Drawing.Size(99, 20);
|
this.checkBox_EnableShowChanels.Size = new System.Drawing.Size(238, 24);
|
||||||
this.radioButton1.TabIndex = 0;
|
this.checkBox_EnableShowChanels.TabIndex = 10;
|
||||||
this.radioButton1.TabStop = true;
|
this.checkBox_EnableShowChanels.Text = "Enable Show Channels";
|
||||||
this.radioButton1.Text = "Use TCP/IP";
|
this.checkBox_EnableShowChanels.UseVisualStyleBackColor = true;
|
||||||
this.radioButton1.UseVisualStyleBackColor = true;
|
//
|
||||||
//
|
// tBBeginDataFlush
|
||||||
// radioButton2
|
//
|
||||||
//
|
this.tBBeginDataFlush.Enabled = false;
|
||||||
this.radioButton2.AutoSize = true;
|
this.tBBeginDataFlush.Location = new System.Drawing.Point(474, 105);
|
||||||
this.radioButton2.Enabled = false;
|
this.tBBeginDataFlush.MaxLength = 8;
|
||||||
this.radioButton2.Location = new System.Drawing.Point(312, 23);
|
this.tBBeginDataFlush.Name = "tBBeginDataFlush";
|
||||||
this.radioButton2.Margin = new System.Windows.Forms.Padding(4);
|
this.tBBeginDataFlush.Size = new System.Drawing.Size(69, 26);
|
||||||
this.radioButton2.Name = "radioButton2";
|
this.tBBeginDataFlush.TabIndex = 9;
|
||||||
this.radioButton2.Size = new System.Drawing.Size(115, 20);
|
this.tBBeginDataFlush.Text = "2000";
|
||||||
this.radioButton2.TabIndex = 1;
|
this.tBBeginDataFlush.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||||
this.radioButton2.Text = "Use serial port";
|
//
|
||||||
this.radioButton2.UseVisualStyleBackColor = true;
|
// labelFlush
|
||||||
//
|
//
|
||||||
// optoSerialPortLabel
|
this.labelFlush.Location = new System.Drawing.Point(328, 109);
|
||||||
//
|
this.labelFlush.Name = "labelFlush";
|
||||||
this.optoSerialPortLabel.AutoSize = true;
|
this.labelFlush.Size = new System.Drawing.Size(140, 22);
|
||||||
this.optoSerialPortLabel.Location = new System.Drawing.Point(321, 55);
|
this.labelFlush.TabIndex = 8;
|
||||||
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.labelFlush.Text = "Begin Data Flush:";
|
||||||
this.optoSerialPortLabel.Name = "optoSerialPortLabel";
|
//
|
||||||
this.optoSerialPortLabel.Size = new System.Drawing.Size(88, 16);
|
// tcpipPortLabel
|
||||||
this.optoSerialPortLabel.TabIndex = 6;
|
//
|
||||||
this.optoSerialPortLabel.Text = "Serial port nr.:";
|
this.tcpipPortLabel.AutoSize = true;
|
||||||
//
|
this.tcpipPortLabel.Location = new System.Drawing.Point(46, 109);
|
||||||
// optoSerialPortTextBox
|
this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
//
|
this.tcpipPortLabel.Name = "tcpipPortLabel";
|
||||||
this.optoSerialPortTextBox.Enabled = false;
|
this.tcpipPortLabel.Size = new System.Drawing.Size(68, 20);
|
||||||
this.optoSerialPortTextBox.Location = new System.Drawing.Point(439, 52);
|
this.tcpipPortLabel.TabIndex = 4;
|
||||||
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.tcpipPortLabel.Text = "Port nr..:";
|
||||||
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
|
//
|
||||||
this.optoSerialPortTextBox.Size = new System.Drawing.Size(44, 22);
|
// tcpipPortTextBox
|
||||||
this.optoSerialPortTextBox.TabIndex = 7;
|
//
|
||||||
//
|
this.tcpipPortTextBox.Enabled = false;
|
||||||
// groupTextBox
|
this.tcpipPortTextBox.Location = new System.Drawing.Point(161, 105);
|
||||||
//
|
this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.groupTextBox.Enabled = false;
|
this.tcpipPortTextBox.Name = "tcpipPortTextBox";
|
||||||
this.groupTextBox.Location = new System.Drawing.Point(153, 97);
|
this.tcpipPortTextBox.Size = new System.Drawing.Size(57, 26);
|
||||||
this.groupTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.tcpipPortTextBox.TabIndex = 5;
|
||||||
this.groupTextBox.Name = "groupTextBox";
|
//
|
||||||
this.groupTextBox.Size = new System.Drawing.Size(44, 22);
|
// ipAddressLabel
|
||||||
this.groupTextBox.TabIndex = 22;
|
//
|
||||||
//
|
this.ipAddressLabel.AutoSize = true;
|
||||||
// groupLabel
|
this.ipAddressLabel.Location = new System.Drawing.Point(46, 74);
|
||||||
//
|
this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.groupLabel.AutoSize = true;
|
this.ipAddressLabel.Name = "ipAddressLabel";
|
||||||
this.groupLabel.Location = new System.Drawing.Point(6, 101);
|
this.ipAddressLabel.Size = new System.Drawing.Size(93, 20);
|
||||||
this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.ipAddressLabel.TabIndex = 2;
|
||||||
this.groupLabel.Name = "groupLabel";
|
this.ipAddressLabel.Text = "IP address.:";
|
||||||
this.groupLabel.Size = new System.Drawing.Size(54, 16);
|
//
|
||||||
this.groupLabel.TabIndex = 21;
|
// ipAddressTextBox
|
||||||
this.groupLabel.Text = "Group 2";
|
//
|
||||||
//
|
this.ipAddressTextBox.Enabled = false;
|
||||||
// muxBoardNrTextBox
|
this.ipAddressTextBox.Location = new System.Drawing.Point(161, 69);
|
||||||
//
|
this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.muxBoardNrTextBox.Enabled = false;
|
this.ipAddressTextBox.Name = "ipAddressTextBox";
|
||||||
this.muxBoardNrTextBox.Location = new System.Drawing.Point(153, 69);
|
this.ipAddressTextBox.Size = new System.Drawing.Size(145, 26);
|
||||||
this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.ipAddressTextBox.TabIndex = 3;
|
||||||
this.muxBoardNrTextBox.Name = "muxBoardNrTextBox";
|
//
|
||||||
this.muxBoardNrTextBox.Size = new System.Drawing.Size(44, 22);
|
// radioButton1
|
||||||
this.muxBoardNrTextBox.TabIndex = 20;
|
//
|
||||||
//
|
this.radioButton1.AutoSize = true;
|
||||||
// muxBoardNrLabel
|
this.radioButton1.Checked = true;
|
||||||
//
|
this.radioButton1.Enabled = false;
|
||||||
this.muxBoardNrLabel.AutoSize = true;
|
this.radioButton1.Location = new System.Drawing.Point(33, 29);
|
||||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(6, 72);
|
this.radioButton1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.radioButton1.Name = "radioButton1";
|
||||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
this.radioButton1.Size = new System.Drawing.Size(109, 24);
|
||||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(131, 16);
|
this.radioButton1.TabIndex = 0;
|
||||||
this.muxBoardNrLabel.TabIndex = 19;
|
this.radioButton1.TabStop = true;
|
||||||
this.muxBoardNrLabel.Text = "Group 1 (mux. board)";
|
this.radioButton1.Text = "Use TCP/IP";
|
||||||
//
|
this.radioButton1.UseVisualStyleBackColor = true;
|
||||||
// nameTextBox
|
//
|
||||||
//
|
// radioButton2
|
||||||
this.nameTextBox.Enabled = false;
|
//
|
||||||
this.nameTextBox.Location = new System.Drawing.Point(153, 40);
|
this.radioButton2.AutoSize = true;
|
||||||
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.radioButton2.Enabled = false;
|
||||||
this.nameTextBox.Name = "nameTextBox";
|
this.radioButton2.Location = new System.Drawing.Point(351, 29);
|
||||||
this.nameTextBox.Size = new System.Drawing.Size(160, 22);
|
this.radioButton2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.nameTextBox.TabIndex = 17;
|
this.radioButton2.Name = "radioButton2";
|
||||||
//
|
this.radioButton2.Size = new System.Drawing.Size(129, 24);
|
||||||
// nameLabel
|
this.radioButton2.TabIndex = 1;
|
||||||
//
|
this.radioButton2.Text = "Use serial port";
|
||||||
this.nameLabel.AutoSize = true;
|
this.radioButton2.UseVisualStyleBackColor = true;
|
||||||
this.nameLabel.Location = new System.Drawing.Point(6, 44);
|
//
|
||||||
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
// optoSerialPortLabel
|
||||||
this.nameLabel.Name = "nameLabel";
|
//
|
||||||
this.nameLabel.Size = new System.Drawing.Size(44, 16);
|
this.optoSerialPortLabel.AutoSize = true;
|
||||||
this.nameLabel.TabIndex = 16;
|
this.optoSerialPortLabel.Location = new System.Drawing.Point(361, 69);
|
||||||
this.nameLabel.Text = "Name";
|
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
//
|
this.optoSerialPortLabel.Name = "optoSerialPortLabel";
|
||||||
// classNameLabel
|
this.optoSerialPortLabel.Size = new System.Drawing.Size(107, 20);
|
||||||
//
|
this.optoSerialPortLabel.TabIndex = 6;
|
||||||
this.classNameLabel.AutoSize = true;
|
this.optoSerialPortLabel.Text = "Serial port nr.:";
|
||||||
this.classNameLabel.Location = new System.Drawing.Point(149, 11);
|
//
|
||||||
this.classNameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
// optoSerialPortTextBox
|
||||||
this.classNameLabel.Name = "classNameLabel";
|
//
|
||||||
this.classNameLabel.Size = new System.Drawing.Size(78, 16);
|
this.optoSerialPortTextBox.Enabled = false;
|
||||||
this.classNameLabel.TabIndex = 15;
|
this.optoSerialPortTextBox.Location = new System.Drawing.Point(494, 65);
|
||||||
this.classNameLabel.Text = "ClassName";
|
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
//
|
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
|
||||||
// tabPage2
|
this.optoSerialPortTextBox.Size = new System.Drawing.Size(49, 26);
|
||||||
//
|
this.optoSerialPortTextBox.TabIndex = 7;
|
||||||
this.tabPage2.Location = new System.Drawing.Point(4, 25);
|
//
|
||||||
this.tabPage2.Name = "tabPage2";
|
// groupTextBox
|
||||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
//
|
||||||
this.tabPage2.Size = new System.Drawing.Size(603, 403);
|
this.groupTextBox.Enabled = false;
|
||||||
this.tabPage2.TabIndex = 1;
|
this.groupTextBox.Location = new System.Drawing.Point(172, 121);
|
||||||
this.tabPage2.Text = "Test";
|
this.groupTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.tabPage2.UseVisualStyleBackColor = true;
|
this.groupTextBox.Name = "groupTextBox";
|
||||||
//
|
this.groupTextBox.Size = new System.Drawing.Size(49, 26);
|
||||||
// groupBox2
|
this.groupTextBox.TabIndex = 22;
|
||||||
//
|
//
|
||||||
this.groupBox2.Controls.Add(this.headPortNrTextBox);
|
// groupLabel
|
||||||
this.groupBox2.Controls.Add(this.label2);
|
//
|
||||||
this.groupBox2.Location = new System.Drawing.Point(10, 335);
|
this.groupLabel.AutoSize = true;
|
||||||
this.groupBox2.Name = "groupBox2";
|
this.groupLabel.Location = new System.Drawing.Point(7, 126);
|
||||||
this.groupBox2.Size = new System.Drawing.Size(552, 50);
|
this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.groupBox2.TabIndex = 26;
|
this.groupLabel.Name = "groupLabel";
|
||||||
this.groupBox2.TabStop = false;
|
this.groupLabel.Size = new System.Drawing.Size(67, 20);
|
||||||
this.groupBox2.Text = "Head Communication";
|
this.groupLabel.TabIndex = 21;
|
||||||
//
|
this.groupLabel.Text = "Group 2";
|
||||||
// label2
|
//
|
||||||
//
|
// muxBoardNrTextBox
|
||||||
this.label2.AutoSize = true;
|
//
|
||||||
this.label2.Location = new System.Drawing.Point(321, 18);
|
this.muxBoardNrTextBox.Enabled = false;
|
||||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
this.muxBoardNrTextBox.Location = new System.Drawing.Point(172, 86);
|
||||||
this.label2.Name = "label2";
|
this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.label2.Size = new System.Drawing.Size(88, 16);
|
this.muxBoardNrTextBox.Name = "muxBoardNrTextBox";
|
||||||
this.label2.TabIndex = 7;
|
this.muxBoardNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||||
this.label2.Text = "Serial port nr.:";
|
this.muxBoardNrTextBox.TabIndex = 20;
|
||||||
//
|
//
|
||||||
// headPortNrTextBox
|
// muxBoardNrLabel
|
||||||
//
|
//
|
||||||
this.headPortNrTextBox.Enabled = false;
|
this.muxBoardNrLabel.AutoSize = true;
|
||||||
this.headPortNrTextBox.Location = new System.Drawing.Point(439, 15);
|
this.muxBoardNrLabel.Location = new System.Drawing.Point(7, 90);
|
||||||
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.headPortNrTextBox.Name = "headPortNrTextBox";
|
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||||
this.headPortNrTextBox.Size = new System.Drawing.Size(44, 22);
|
this.muxBoardNrLabel.Size = new System.Drawing.Size(159, 20);
|
||||||
this.headPortNrTextBox.TabIndex = 8;
|
this.muxBoardNrLabel.TabIndex = 19;
|
||||||
//
|
this.muxBoardNrLabel.Text = "Group 1 (mux. board)";
|
||||||
// IperlHeadCfgCtrl
|
//
|
||||||
//
|
// nameTextBox
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
//
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.nameTextBox.Enabled = false;
|
||||||
this.Controls.Add(this.tabControl1);
|
this.nameTextBox.Location = new System.Drawing.Point(172, 50);
|
||||||
this.Margin = new System.Windows.Forms.Padding(4);
|
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||||
this.Name = "GenesisCfgCtrl";
|
this.nameTextBox.Name = "nameTextBox";
|
||||||
this.Size = new System.Drawing.Size(617, 438);
|
this.nameTextBox.Size = new System.Drawing.Size(180, 26);
|
||||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
this.nameTextBox.TabIndex = 17;
|
||||||
this.tabControl1.ResumeLayout(false);
|
//
|
||||||
this.tabPage1.ResumeLayout(false);
|
// nameLabel
|
||||||
this.tabPage1.PerformLayout();
|
//
|
||||||
this.groupBox1.ResumeLayout(false);
|
this.nameLabel.AutoSize = true;
|
||||||
this.groupBox1.PerformLayout();
|
this.nameLabel.Location = new System.Drawing.Point(7, 55);
|
||||||
this.optoDataGroupBox.ResumeLayout(false);
|
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
this.optoDataGroupBox.PerformLayout();
|
this.nameLabel.Name = "nameLabel";
|
||||||
this.groupBox2.ResumeLayout(false);
|
this.nameLabel.Size = new System.Drawing.Size(51, 20);
|
||||||
this.groupBox2.PerformLayout();
|
this.nameLabel.TabIndex = 16;
|
||||||
this.ResumeLayout(false);
|
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.TabControl tabControl1;
|
||||||
private System.Windows.Forms.TabPage tabPage1;
|
private System.Windows.Forms.TabPage tabPage1;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using System;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.DataPackages.MeasurementRecords;
|
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.DataPackages.MeasurementRecords;
|
||||||
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Protocols.StreamingProtocol;
|
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Protocols.StreamingProtocol;
|
||||||
|
using Xylem.Common.Metrology.Measurements;
|
||||||
|
|
||||||
|
|
||||||
namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
||||||
@@ -25,6 +25,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
public static readonly int Length = 42;
|
public static readonly int Length = 42;
|
||||||
private static CultureInfo culture;
|
private static CultureInfo culture;
|
||||||
|
|
||||||
|
public MeasurementRecord data;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Strobed value
|
/// Strobed value
|
||||||
@@ -124,11 +125,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------- TIMESTAMP (seconds) --------
|
|
||||||
private const double TS_RANGE = StreamingDecoder.CpuTimeOverflowS;
|
|
||||||
|
|
||||||
// -------- VOLUME (liters) --------
|
|
||||||
private const double VOL_RANGE = StreamingDecoder.DefaultAccuDutOverflowVolumeCm * 1000;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// update data by CalibrationRecord
|
/// update data by CalibrationRecord
|
||||||
@@ -149,7 +146,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
if (data == null)
|
if (data == null)
|
||||||
throw new ArgumentNullException(nameof(data));
|
throw new ArgumentNullException(nameof(data));
|
||||||
|
|
||||||
UpdateData( data.Channel, data.VolumeCm, data.TimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
|
this.data = data;
|
||||||
|
UpdateData( data.Channel, data.VolumeCm, data.OverflowVolumeCm, data.TimeS, data.OverflowTimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -170,8 +168,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
throw new ArgumentNullException(nameof(data));
|
throw new ArgumentNullException(nameof(data));
|
||||||
|
this.data = data;
|
||||||
UpdateData( data.Channel, data.VolumeCm, data.TimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
|
UpdateData( data.Channel, data.VolumeCm, data.OverflowVolumeCm, data.TimeS, data.OverflowTimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -187,7 +185,9 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
private void UpdateData(
|
private void UpdateData(
|
||||||
int channel,
|
int channel,
|
||||||
double volumeCm,
|
double volumeCm,
|
||||||
|
double OverflowVolumeCm,
|
||||||
double timeS,
|
double timeS,
|
||||||
|
double OverflowTimeS,
|
||||||
int counter,
|
int counter,
|
||||||
float refFlow,
|
float refFlow,
|
||||||
ref double volumeRawExtLast,
|
ref double volumeRawExtLast,
|
||||||
@@ -200,29 +200,30 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
Flags = OptoTelegramFlags.OK;
|
Flags = OptoTelegramFlags.OK;
|
||||||
|
|
||||||
FlowRaw = 0;
|
FlowRaw = 0;
|
||||||
VolumeRaw = volumeCm * 1000.0; // liters
|
double nV = NormalizeByOverflow(volumeCm, OverflowVolumeCm);
|
||||||
|
VolumeRaw = nV * 1000.0; // liters
|
||||||
CheckSum = 0;
|
CheckSum = 0;
|
||||||
Impedance = 0;
|
Impedance = 0;
|
||||||
EmfRaw = 0;
|
EmfRaw = 0;
|
||||||
MagneticFieldRaw = 0;
|
MagneticFieldRaw = 0;
|
||||||
|
|
||||||
double ts = NormalizeTimestamp(timeS);
|
double ts = NormalizeByOverflow(timeS, OverflowTimeS);
|
||||||
Timestamp = ts;
|
Timestamp = ts;
|
||||||
|
|
||||||
VolumeRawExt = UnwrapVolume(VolumeRaw, ref volumeRawExtLast);
|
VolumeRawExt = UnwrapVolume(VolumeRaw,OverflowVolumeCm * 1000, ref volumeRawExtLast);
|
||||||
TimestampExt = UnwrapTimestamp(ts, ref timestampExtLast);
|
TimestampExt = UnwrapTimestamp(ts,OverflowTimeS, ref timestampExtLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double NormalizeTimestamp(double timeS)
|
private static double NormalizeByOverflow(double value, double overfValue = 0)
|
||||||
{
|
{
|
||||||
double ts = timeS % TS_RANGE;
|
double nValue = value % overfValue;
|
||||||
if (ts < 0)
|
if (nValue < 0)
|
||||||
ts += TS_RANGE;
|
nValue += overfValue;
|
||||||
|
|
||||||
return ts;
|
return nValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double UnwrapVolume(double currentVolume, ref double volumeRawExtLast)
|
private static double UnwrapVolume(double currentVolume, double overfValue, ref double volumeRawExtLast)
|
||||||
{
|
{
|
||||||
double result;
|
double result;
|
||||||
|
|
||||||
@@ -232,16 +233,25 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = currentVolume < volumeRawExtLast
|
double lastMod = volumeRawExtLast % overfValue;
|
||||||
? currentVolume + VOL_RANGE
|
if (lastMod < 0)
|
||||||
: currentVolume;
|
lastMod += overfValue;
|
||||||
|
|
||||||
|
double delta = currentVolume - lastMod;
|
||||||
|
|
||||||
|
if (delta < -overfValue / 2.0)
|
||||||
|
delta += overfValue;
|
||||||
|
else if (delta > overfValue / 2.0)
|
||||||
|
delta -= overfValue;
|
||||||
|
|
||||||
|
result = volumeRawExtLast + delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeRawExtLast = result;
|
volumeRawExtLast = result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double UnwrapTimestamp(double currentTimestamp, ref double timestampExtLast)
|
private static double UnwrapTimestamp(double currentTimestamp,double overfValue, ref double timestampExtLast)
|
||||||
{
|
{
|
||||||
double result;
|
double result;
|
||||||
|
|
||||||
@@ -251,16 +261,16 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double lastMod = timestampExtLast % TS_RANGE;
|
double lastMod = timestampExtLast % overfValue;
|
||||||
if (lastMod < 0)
|
if (lastMod < 0)
|
||||||
lastMod += TS_RANGE;
|
lastMod += overfValue;
|
||||||
|
|
||||||
double delta = currentTimestamp - lastMod;
|
double delta = currentTimestamp - lastMod;
|
||||||
|
|
||||||
if (delta < -TS_RANGE / 2.0)
|
if (delta < -overfValue / 2.0)
|
||||||
delta += TS_RANGE;
|
delta += overfValue;
|
||||||
else if (delta > TS_RANGE / 2.0)
|
else if (delta > overfValue / 2.0)
|
||||||
delta -= TS_RANGE;
|
delta -= overfValue;
|
||||||
|
|
||||||
result = timestampExtLast + delta;
|
result = timestampExtLast + delta;
|
||||||
}
|
}
|
||||||
@@ -349,5 +359,33 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
Label());
|
Label());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Copy(OptoTelegramRaw optoTelegramRaw)
|
||||||
|
{
|
||||||
|
this.Flags = optoTelegramRaw.Flags;
|
||||||
|
this.DateTime = optoTelegramRaw.DateTime;
|
||||||
|
this.RefFlow = optoTelegramRaw.RefFlow;
|
||||||
|
this.Counter = optoTelegramRaw.Counter;
|
||||||
|
this.EmfRaw = optoTelegramRaw.EmfRaw;
|
||||||
|
this.MagneticFieldRaw = optoTelegramRaw.MagneticFieldRaw;
|
||||||
|
this.FlowRaw = optoTelegramRaw.FlowRaw;
|
||||||
|
this.VolumeRaw = optoTelegramRaw.VolumeRaw;
|
||||||
|
this.VolumeRawExt = optoTelegramRaw.VolumeRawExt;
|
||||||
|
this.Impedance = optoTelegramRaw.Impedance;
|
||||||
|
this.Timestamp = optoTelegramRaw.Timestamp;
|
||||||
|
this.TimestampExt = optoTelegramRaw.TimestampExt;
|
||||||
|
this.CheckSum = optoTelegramRaw.CheckSum;
|
||||||
|
this.iChannel = optoTelegramRaw.iChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string rawDataToString()
|
||||||
|
{
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
return string.Format("Channel: {0}, VolumeCm:{1}, OverflowVolumeCm:{2}, TimeS: {3}, OverflowTimeS:{4} ",
|
||||||
|
data.Channel, data.VolumeCm, data.OverflowVolumeCm, data.TimeS, data.OverflowTimeS);
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,6 +227,20 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
|||||||
return _serialPort.ReadExisting();
|
return _serialPort.ReadExisting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ResetInputBuffer()
|
||||||
|
{
|
||||||
|
if (!IsOpen)
|
||||||
|
throw new InvalidOperationException("Serial port not open");
|
||||||
|
_serialPort.DiscardInBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetOutputBuffer()
|
||||||
|
{
|
||||||
|
if (!IsOpen)
|
||||||
|
throw new InvalidOperationException("Serial port not open");
|
||||||
|
_serialPort.DiscardOutBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
public Encoding Encoding => _serialPort?.Encoding ?? _encoding;
|
public Encoding Encoding => _serialPort?.Encoding ?? _encoding;
|
||||||
|
|
||||||
public int BytesToRead => (_serialPort != null && _serialPort.IsOpen) ? _serialPort.BytesToRead : 0;
|
public int BytesToRead => (_serialPort != null && _serialPort.IsOpen) ? _serialPort.BytesToRead : 0;
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
{
|
{
|
||||||
Flush = 0,
|
Flush = 0,
|
||||||
ProcessAndSave,
|
ProcessAndSave,
|
||||||
|
CalculateStoredData,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CommunicationInterface
|
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
|
public class CliRunner
|
||||||
{
|
{
|
||||||
//static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
|
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
private List<Task> taskPool = new List<Task>();
|
private readonly List<CliTaskInfo> taskPool = new List<CliTaskInfo>();
|
||||||
private long startTime;
|
private long startTimeMs;
|
||||||
private long incommingTime;
|
private long incommingTimeMs;
|
||||||
|
|
||||||
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 => { }); }
|
|
||||||
|
|
||||||
public void StartAll()
|
public List<CliTaskInfo> TaskPool
|
||||||
{
|
{
|
||||||
taskPool.ForEach(t => t.Start());
|
get { return taskPool; }
|
||||||
}
|
|
||||||
|
|
||||||
public bool AreTasksDone()
|
|
||||||
{
|
|
||||||
return taskPool.All(task => task.IsCompleted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long StartTime
|
public long StartTime
|
||||||
{
|
{
|
||||||
get => startTime;
|
get { return startTimeMs; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public long IncommingTime
|
public long IncommingTime
|
||||||
{
|
{
|
||||||
get => incommingTime;
|
get { return incommingTimeMs; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TimeOutReceived(long timeout)
|
|
||||||
{
|
|
||||||
return (DateTime.Now.Ticks - startTime) > timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CliRunner(bool isCliLogging)
|
public CliRunner(bool isCliLogging)
|
||||||
{
|
{
|
||||||
startTime = DateTime.Now.Ticks;
|
ResetStartTime();
|
||||||
|
|
||||||
if (isCliLogging)
|
if (isCliLogging)
|
||||||
{
|
{
|
||||||
@@ -60,88 +43,180 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
{
|
{
|
||||||
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||||
@"C:\TBF\Logs\CliRunner.txt",
|
@"C:\TBF\Logs\CliRunner.txt",
|
||||||
10, // maxFileSizeMB
|
10,
|
||||||
7, // maxBackups
|
7,
|
||||||
log4net.Core.Level.Debug,
|
log4net.Core.Level.Debug,
|
||||||
true, // zipRolledFiles
|
true,
|
||||||
true, // singleZipPerDay
|
true,
|
||||||
TimeSpan.FromMinutes(2) // zipScanInterval
|
TimeSpan.FromMinutes(2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Fallback to console or handle gracefully
|
|
||||||
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
|
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public void ResetStartTime()
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
|
||||||
{
|
{
|
||||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
startTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
taskPool.Add(task);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 };
|
public void Clear()
|
||||||
process.Start();
|
{
|
||||||
|
foreach (var item in taskPool)
|
||||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
|
||||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
try
|
||||||
}
|
{
|
||||||
catch (OperationCanceledException)
|
item?.Cts?.Dispose();
|
||||||
{
|
}
|
||||||
if (!process.HasExited)
|
catch
|
||||||
{
|
{
|
||||||
process.Kill();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw;
|
try
|
||||||
|
{
|
||||||
|
if (item?.Process != null)
|
||||||
|
{
|
||||||
|
item.Process.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//comming answer from serial port - good place for time stamp
|
taskPool.Clear();
|
||||||
incommingTime = DateTime.Now.Ticks;
|
|
||||||
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
|
|
||||||
log?.Debug(allOutput);
|
|
||||||
return allOutput;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WaitAll()
|
||||||
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
|
||||||
{
|
{
|
||||||
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
var tasks = taskPool
|
||||||
taskPool.Add(task);
|
.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
|
var psi = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
@@ -153,80 +228,210 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
CreateNoWindow = true
|
CreateNoWindow = true
|
||||||
};
|
};
|
||||||
|
|
||||||
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||||
process.Start();
|
{
|
||||||
|
info.Process = process;
|
||||||
|
|
||||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
try
|
||||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
{
|
||||||
|
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 ?? "");
|
try
|
||||||
log?.Debug(allOutput);
|
{
|
||||||
|
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
if (info.State != CliTaskState.TimedOut)
|
||||||
|
info.State = CliTaskState.Canceled;
|
||||||
|
|
||||||
string json = ExtractJson(allOutput);
|
if (!process.HasExited)
|
||||||
if (TryJsonStringDeserialize(json, out T result)) return result;
|
{
|
||||||
return default;
|
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)
|
if (json != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
|
value = JsonConvert.DeserializeObject<T>(json);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.Debug(ex.Message);
|
log?.Debug(ex.Message);
|
||||||
runAndCaptureJsonAsync = TryConvert<T>(json);
|
value = TryConvert<T>(json);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runAndCaptureJsonAsync = default;
|
value = default(T);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static T TryConvert<T>(string json) where T : new()
|
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;
|
try
|
||||||
|
{
|
||||||
JToken token;
|
object value = token.ToObject(prop.PropertyType);
|
||||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
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)
|
}
|
||||||
{
|
catch (Exception ex)
|
||||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
{
|
||||||
}
|
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ExtractJson(string text)
|
public string ExtractJson(string text)
|
||||||
@@ -241,6 +446,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
return null;
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
/// for debug purposes what time will consume answer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private long startTimeInMilis = -1, fullTimeInMilis = -1;
|
private long startTimeInMilis = -1, fullTimeInMilis = -1;
|
||||||
|
/// 30 seconds
|
||||||
private static long SafetyTimeOut = 30 * 1000;
|
private static long SafetyTimeOut = 30 * 1000;
|
||||||
private long incommingTime = -1;
|
private long incommingTime = -1;
|
||||||
|
private bool _lastOpTimedOut;
|
||||||
|
|
||||||
|
|
||||||
/// 30 seconds
|
|
||||||
|
|
||||||
public long DeltaTime { get{return fullTimeInMilis;}}
|
public long DeltaTime { get{return fullTimeInMilis;}}
|
||||||
public long IncommingTime { get{return incommingTime;}}
|
public long IncommingTime { get{return incommingTime;}}
|
||||||
@@ -356,108 +358,146 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
|
|
||||||
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
|
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
|
||||||
{
|
{
|
||||||
|
CliRunner.Clear();
|
||||||
|
_lastOpTimedOut = false;
|
||||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
|
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||||
return Event.Busy;
|
_currentOp = CurrentPoseidonOp.SendStartDataStream_Runing;
|
||||||
|
return Event.Busy;
|
||||||
}
|
}
|
||||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
|
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
|
||||||
{
|
{
|
||||||
if (CliRunner.AreTasksDone()
|
if (CliRunner.AreTasksDone())
|
||||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
|
||||||
{
|
{
|
||||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
_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)
|
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 (firstTaskInfo != null)
|
||||||
if (firstTask != null && firstTask is Task<string>)
|
|
||||||
{
|
{
|
||||||
string data = null;
|
var task = (Task<string>)firstTaskInfo.Task;
|
||||||
data = (firstTask as Task<string>).Result;
|
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;
|
return Event.Done;
|
||||||
}
|
}
|
||||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||||
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
||||||
{
|
{
|
||||||
startTimeInMilis = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
|
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
incommingTime = -1;
|
incommingTime = -1;
|
||||||
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
|
_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;
|
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
|
||||||
return Event.Busy;
|
return Event.Busy;
|
||||||
}else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
}
|
||||||
|
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||||
{
|
{
|
||||||
if (CliRunner.AreTasksDone()
|
if (CliRunner.AreTasksDone())
|
||||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
|
||||||
{
|
{
|
||||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||||
//set time stamp - end of reading
|
|
||||||
incommingTime = CliRunner.IncommingTime;
|
incommingTime = CliRunner.IncommingTime;
|
||||||
}
|
}
|
||||||
|
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||||
|
{
|
||||||
|
_lastOpTimedOut = true;
|
||||||
|
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||||
|
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||||
|
incommingTime = CliRunner.IncommingTime;
|
||||||
|
}
|
||||||
|
|
||||||
return Event.Busy;
|
return Event.Busy;
|
||||||
}
|
}
|
||||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
|
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
|
||||||
{
|
{
|
||||||
fullTimeInMilis = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - startTimeInMilis;
|
fullTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTimeInMilis;
|
||||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis} ");
|
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;
|
|
||||||
|
|
||||||
//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))
|
if (string.IsNullOrEmpty(wmSerialNr))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wmSerialNr = data?.DeviceId ?? wmSerialNr;
|
wmSerialNr = data.DeviceId ?? wmSerialNr;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
log.Error("Serial Nr - parse error!");
|
log.Error("Serial Nr - parse error!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//GET volume
|
double volume;
|
||||||
if (data != null && Double.TryParse(data.Reading, out double Volume))
|
if (Double.TryParse(data.Reading, out volume))
|
||||||
{
|
{
|
||||||
double VolumeLi = Units.ConvertFrom(Unit.USgal, Volume);
|
double volumeLi = Units.ConvertFrom(Unit.USgal, volume);
|
||||||
//double VolumeM3 = Units.ConvertTo(Unit.m3, VolumeLi);
|
|
||||||
if (_isReadingStart)
|
|
||||||
{
|
|
||||||
//volume
|
|
||||||
beginWMState = VolumeLi;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//volume
|
|
||||||
endWMState = VolumeLi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (_isReadingStart)
|
||||||
|
beginWMState = volumeLi;
|
||||||
|
else
|
||||||
|
endWMState = volumeLi;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Finish reading and loop
|
CliRunner.Clear();
|
||||||
_currentOp = CurrentPoseidonOp.Done;
|
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||||
return Event.Done;
|
return Event.Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Event.None;
|
||||||
|
|
||||||
return Event.None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Stop this operation</summary>
|
/// <summary>Stop this operation</summary>
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -678,7 +678,8 @@ namespace TBF.Rig.Sequences
|
|||||||
/// On error or when STOP pressed
|
/// On error or when STOP pressed
|
||||||
///
|
///
|
||||||
foreach (var fmPump in PumpsWithFM) fmPump.TurnOff();
|
foreach (var fmPump in PumpsWithFM) fmPump.TurnOff();
|
||||||
|
log.Debug("STOP or ERROR: Pumps with FM stopped!");
|
||||||
|
|
||||||
if (inPath != null)
|
if (inPath != null)
|
||||||
{
|
{
|
||||||
///
|
///
|
||||||
@@ -1275,22 +1276,49 @@ namespace TBF.Rig.Sequences
|
|||||||
|
|
||||||
var smryItems = DEItem.GetSummaryColumns();
|
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.Count > i &&
|
||||||
BatchRslts.Batch.WaterMeters[i] != null &&
|
BatchRslts.Batch.WaterMeters[i] != null)
|
||||||
!BatchRslts.Batch.WaterMeters[i].Disabled)
|
|
||||||
{
|
{
|
||||||
|
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];
|
var wm = BatchRslts.Batch.WaterMeters[i];
|
||||||
|
|
||||||
if (!wm.Compound() && !wm.HeatMeter())
|
if (!wm.Compound() && !wm.HeatMeter())
|
||||||
{
|
{
|
||||||
/// If this is a single meter
|
/// If this is a single meter
|
||||||
|
Results.Entities.MeterTestRslt mtrRslt = null;
|
||||||
Results.Entities.MeterTestRslt mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.Single);
|
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);
|
bool isCamera = (mtrRslt.RegReaderType == (int)RegisterReaderType.Camera);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using TBF.Rig.GenericDevices;
|
|||||||
using TBF.Boxes;
|
using TBF.Boxes;
|
||||||
using TBF.Resources;
|
using TBF.Resources;
|
||||||
using TBF.Rig.TestMethods.GenesisCommunication.GenesisHead;
|
using TBF.Rig.TestMethods.GenesisCommunication.GenesisHead;
|
||||||
|
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||||
using TBF.UiBridge;
|
using TBF.UiBridge;
|
||||||
|
|
||||||
namespace TBF.Rig.TestMethods.FlyingStart
|
namespace TBF.Rig.TestMethods.FlyingStart
|
||||||
@@ -329,6 +330,9 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
|||||||
|
|
||||||
temperature_set:
|
temperature_set:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//TODO genesis - check with genesis switch
|
//TODO genesis - check with genesis switch
|
||||||
if (atleastOneGenesis)
|
if (atleastOneGenesis)
|
||||||
{
|
{
|
||||||
@@ -379,18 +383,26 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
|||||||
IList<IOperation> cameraMeasurementOps = new List<IOperation>();
|
IList<IOperation> cameraMeasurementOps = new List<IOperation>();
|
||||||
foreach (var camera in cameras) cameraMeasurementOps.Add(camera.MeasurementOp());
|
foreach (var camera in cameras) cameraMeasurementOps.Add(camera.MeasurementOp());
|
||||||
|
|
||||||
foreach (var rr in sensPath.RegisterReaders)
|
/// Prepare datastream read operations
|
||||||
{
|
IList<IOperation> readDatastreamOps = new List<IOperation>();
|
||||||
if (rr is IRegReaderDatastream)
|
if (sensPath != null && sensPath.RegisterReaders != null)
|
||||||
(rr as IRegReaderDatastream).TestIsGoingToStartSoon(test, repetitionNr);
|
{
|
||||||
|
foreach (var rr in sensPath.RegisterReaders)
|
||||||
if (rr is GenesisHead) // Genesis - CORDONEL head
|
{
|
||||||
(rr as GenesisHead).StartRead(test.Name, BatchRslts.Batch.BatchNr, repetitionNr);
|
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);
|
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))
|
State.Create(string.Format("{0}({1}) : FlyingStartStopTestOp is running", test.Method, test.Name))
|
||||||
.AddOperation(checkUiOp)
|
.AddOperation(checkUiOp)
|
||||||
.AddOperations(readTempPressOps)
|
.AddOperations(readTempPressOps)
|
||||||
|
.AddOperations(readDatastreamOps)
|
||||||
.AddOperations(cameraMeasurementOps)
|
.AddOperations(cameraMeasurementOps)
|
||||||
.AddOperation(cBrd.FlyingStartStopTestOp(test, test.QfromM3ph(), test.QtoM3ph(), totalPulses))
|
.AddOperation(cBrd.FlyingStartStopTestOp(test, test.QfromM3ph(), test.QtoM3ph(), totalPulses))
|
||||||
.AddOperation(processDataLoggingOp)
|
.AddOperation(processDataLoggingOp)
|
||||||
@@ -454,6 +467,21 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
|||||||
|
|
||||||
/// Measurement loop end
|
/// Measurement loop end
|
||||||
StopRecordingStatistics();
|
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
|
//TODO genesis - check with genesis switch
|
||||||
if (atleastOneGenesis)
|
if (atleastOneGenesis)
|
||||||
|
|||||||
@@ -8,11 +8,14 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
using Results.Entities;
|
||||||
using TBF.Boxes;
|
using TBF.Boxes;
|
||||||
using TBF.Resources;
|
using TBF.Resources;
|
||||||
using TBF.Rig;
|
using TBF.Rig;
|
||||||
using TBF.Rig.GenericDevices;
|
using TBF.Rig.GenericDevices;
|
||||||
|
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||||
using TBF.Rig.RegisterReaders.PoseidonReader;
|
using TBF.Rig.RegisterReaders.PoseidonReader;
|
||||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||||
@@ -170,8 +173,8 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
string testName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
string testName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
||||||
TestStartTime = DateTime.Now;
|
TestStartTime = DateTime.Now;
|
||||||
|
|
||||||
bool atleastOneGenesis = false;
|
// bool atleastOneGenesis = false;
|
||||||
atleastOneGenesis = GenesisHeadBatch.Start(sensPath.RegisterReaders, Program.LocalSettings.LastSNTexts);
|
// atleastOneGenesis = GenesisHeadBatch.Start(sensPath.RegisterReaders, Program.LocalSettings.LastSNTexts);
|
||||||
|
|
||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
Bridge.OnActivity(this, Strings.Checking_tank_capacity);
|
Bridge.OnActivity(this, Strings.Checking_tank_capacity);
|
||||||
@@ -452,23 +455,23 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atleastOneGenesis)
|
// if (atleastOneGenesis)
|
||||||
{
|
// {
|
||||||
log.Info($"Genesis - Starting... Test Name:{test.Name.ToLower()}.");
|
// log.Info($"Genesis - Starting... Test Name:{test.Name.ToLower()}.");
|
||||||
if (test.Name.ToLower().Contains("calib"))
|
// if (test.Name.ToLower().Contains("calib"))
|
||||||
{
|
// {
|
||||||
log.Info("Genesis - Calibration starting.");
|
// log.Info("Genesis - Calibration starting.");
|
||||||
GenesisHeadBatch.BatchHolder.Value.MetersLogin();
|
// GenesisHeadBatch.BatchHolder.Value.MetersLogin();
|
||||||
GenesisHeadBatch.BatchHolder.Value.MetersInitCalibration();
|
// GenesisHeadBatch.BatchHolder.Value.MetersInitCalibration();
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
if (test.Name.ToLower().Contains("init"))
|
// if (test.Name.ToLower().Contains("init"))
|
||||||
{
|
// {
|
||||||
log.Info("Genesis - init starting.");
|
// log.Info("Genesis - init starting.");
|
||||||
GenesisHeadBatch.BatchHolder.Value.MetersLogin();
|
// GenesisHeadBatch.BatchHolder.Value.MetersLogin();
|
||||||
GenesisHeadBatch.BatchHolder.Value.MetersInitMeasurement();
|
// GenesisHeadBatch.BatchHolder.Value.MetersInitMeasurement();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (drainTheTank)
|
if (drainTheTank)
|
||||||
{
|
{
|
||||||
@@ -607,22 +610,40 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
}
|
}
|
||||||
while (!e.Contains(Event.TestCompleted) && !e.Contains(Event.Next)); /// 'Next' button is enabled in Debug version only
|
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
|
/// Measurement loop end
|
||||||
StopRecordingStatistics();
|
StopRecordingStatistics();
|
||||||
|
|
||||||
if (atleastOneGenesis)
|
|
||||||
{
|
|
||||||
if (test.Name.ToLower().Contains("calib"))
|
if (sensPath != null && sensPath.RegisterReaders != null)
|
||||||
{
|
{
|
||||||
log.Info("Genesis - Calibration stopped.");
|
foreach (var rr in sensPath.RegisterReaders)
|
||||||
GenesisHeadBatch.BatchHolder.Value.MetersStopCalibration();
|
{
|
||||||
}
|
var datastreamRR = rr as ISmartReader;
|
||||||
else
|
if (datastreamRR != null)
|
||||||
{
|
{
|
||||||
log.Info("Genesis - Init measurement stopped.");
|
datastreamRR.StopDataStreamProcessing();
|
||||||
GenesisHeadBatch.BatchHolder.Value.MetersStopMeasurement();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if (atleastOneGenesis)
|
||||||
|
// {
|
||||||
|
// if (test.Name.ToLower().Contains("calib"))
|
||||||
|
// {
|
||||||
|
// log.Info("Genesis - Calibration stopped.");
|
||||||
|
// GenesisHeadBatch.BatchHolder.Value.MetersStopCalibration();
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// log.Info("Genesis - Init measurement stopped.");
|
||||||
|
// GenesisHeadBatch.BatchHolder.Value.MetersStopMeasurement();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// (Berlin:) Water is stopped immediately after the test and before the 2nd mass measurement in case:
|
/// (Berlin:) Water is stopped immediately after the test and before the 2nd mass measurement in case:
|
||||||
@@ -955,6 +976,7 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
bool bUpgradeCountOfMeters = false;
|
||||||
///
|
///
|
||||||
/// Single meters
|
/// Single meters
|
||||||
///
|
///
|
||||||
@@ -969,6 +991,7 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = regReader as TestMethods.iPerlCommunication.iPerlHead.IperlHead;
|
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = regReader as TestMethods.iPerlCommunication.iPerlHead.IperlHead;
|
||||||
GenericDevices.IRegReaderLiveCamera cameraRoi = regReader as GenericDevices.IRegReaderLiveCamera;
|
GenericDevices.IRegReaderLiveCamera cameraRoi = regReader as GenericDevices.IRegReaderLiveCamera;
|
||||||
TestMethods.GenesisCommunication.GenesisHead.GenesisHead Genesis = regReader as TestMethods.GenesisCommunication.GenesisHead.GenesisHead;
|
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)
|
if (meterRslt != null && regReader != null)
|
||||||
{
|
{
|
||||||
@@ -1057,6 +1080,23 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
var calError = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, meterRslt.VolumeRef);
|
var calError = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, meterRslt.VolumeRef);
|
||||||
Genesis.Log(" MeterError = " + calError.ToString() + " %");
|
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)
|
else if (dstrReader != null)
|
||||||
{
|
{
|
||||||
@@ -1241,7 +1281,15 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bUpgradeCountOfMeters)
|
||||||
|
{
|
||||||
|
//TODO remove test!!
|
||||||
|
//BatchRslts.WMPositionsCount = BatchRslts.WMPositionsCount + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tstRslt.Components = Results.Entities.Components.UpdateList(BatchRslts.ComponentsList,
|
tstRslt.Components = Results.Entities.Components.UpdateList(BatchRslts.ComponentsList,
|
||||||
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
|
||||||
@@ -1300,6 +1348,98 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
|||||||
return new List<Event> { retVal };
|
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,
|
IList<Event> Simulate1(Config.Entities.Test test, int repetitionNr, bool isLastRepetition,
|
||||||
Compound.CombinedTestParams compoundTestParams,
|
Compound.CombinedTestParams compoundTestParams,
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ using Xylem.Common.Metrology.Measurements;
|
|||||||
using Xylem.Common.Metrology.Measurements.Consts;
|
using Xylem.Common.Metrology.Measurements.Consts;
|
||||||
using Common;
|
using Common;
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
using GenesisMeter = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter;
|
|
||||||
using MeterBatch = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.MeterBatch;
|
|
||||||
|
|
||||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,20 +6,21 @@ using TBF.Rig.Generic;
|
|||||||
|
|
||||||
namespace TBF.Rig.Uni.FlowMetersInParallel
|
namespace TBF.Rig.Uni.FlowMetersInParallel
|
||||||
{
|
{
|
||||||
public class Factory : IComponentFactory
|
public class Factory : IComponentFactory
|
||||||
{
|
{
|
||||||
public string ClassName { get { return GetType().Namespace.Substring(12); } }
|
public string ClassName { get { return GetType().Namespace.Substring(12); } }
|
||||||
public override string ToString() { return ClassName; }
|
public override string ToString() { return ClassName; }
|
||||||
|
|
||||||
public IComponent DummyComponent() { return new FlowMeter(); }
|
public IComponent DummyComponent() { return new FlowMeter(); }
|
||||||
|
|
||||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new FlowMeter(cfg, components); }
|
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new FlowMeter(cfg, components); }
|
||||||
|
|
||||||
public IComponentCfg DefaultConfig() { return new FlowMeterCfg(this, "I11+I12"); }
|
public IComponentCfg DefaultConfig() { return new FlowMeterCfg(this, "I11+I12"); }
|
||||||
|
|
||||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||||
{
|
{
|
||||||
return ComponentCfgBase.CreateFromDbEntity(FlowMeterCfg.Serializer, component, this);
|
return ComponentCfgBase.CreateFromDbEntity(FlowMeterCfg.Serializer, component, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using log4net;
|
using log4net;
|
||||||
using SchematicDrawing;
|
using SchematicDrawing;
|
||||||
|
using SharedComponents;
|
||||||
using TBF.Boxes;
|
using TBF.Boxes;
|
||||||
using TBF.Rig.ControlBoard.Uni;
|
using TBF.Rig.ControlBoard.Uni;
|
||||||
using TBF.Rig.GenericDevices;
|
using TBF.Rig.GenericDevices;
|
||||||
@@ -12,17 +13,16 @@ using TBF.Rig.GenericDevices;
|
|||||||
namespace TBF.Rig.Uni.FlowMetersInParallel
|
namespace TBF.Rig.Uni.FlowMetersInParallel
|
||||||
{
|
{
|
||||||
public class FlowMeter : ComponentBase, IFlowMeter, IDrawingItCmpntWithMeasuredVal
|
public class FlowMeter : ComponentBase, IFlowMeter, IDrawingItCmpntWithMeasuredVal
|
||||||
{
|
{
|
||||||
private static readonly ILog log = LogManager.GetLogger(typeof(FlowMeter));
|
private static readonly ILog log = LogManager.GetLogger(typeof(FlowMeter));
|
||||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||||
|
|
||||||
readonly FlowMeterCfg myCfg;
|
readonly FlowMeterCfg flowMeterCfg;
|
||||||
|
|
||||||
UniCB uniCB;
|
UniCB uniCB;
|
||||||
IFlowMeterSingle flowMtr1;
|
IFlowMeterSingle flowMtr1;
|
||||||
IFlowMeterSingle flowMtr2;
|
IFlowMeterSingle flowMtr2;
|
||||||
IFlowMeterSingle flowMtr3;
|
IFlowMeterSingle flowMtr3;
|
||||||
IFlowMeterSingle inactiveFlowMtr;
|
|
||||||
double nominalFlow;
|
double nominalFlow;
|
||||||
double nominalFreq;
|
double nominalFreq;
|
||||||
double ltrPerPulse;
|
double ltrPerPulse;
|
||||||
@@ -34,22 +34,20 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
public double NominalFreq { get { return nominalFreq; } }
|
public double NominalFreq { get { return nominalFreq; } }
|
||||||
public double LtrPerPulse { get { return ltrPerPulse; } }
|
public double LtrPerPulse { get { return ltrPerPulse; } }
|
||||||
|
|
||||||
public SchematicDrawing.IDrawingItem DrawingItem { get { return myCfg as SchematicDrawing.IDrawingItem; } }
|
public SchematicDrawing.IDrawingItem DrawingItem { get { return flowMeterCfg as SchematicDrawing.IDrawingItem; } }
|
||||||
public string MsrdFormat { get { return myCfg.MsrdFormat; } }
|
public string MsrdFormat { get { return flowMeterCfg.MsrdFormat; } }
|
||||||
public Common.Unit MsrdUnit { get { return myCfg.MsrdUnit; } }
|
public Common.Unit MsrdUnit { get { return flowMeterCfg.MsrdUnit; } }
|
||||||
public double MsrdValLimLo { get { return myCfg.MsrdValLimLo; } set { myCfg.MsrdValLimLo = value; } }
|
public double MsrdValLimLo { get { return flowMeterCfg.MsrdValLimLo; } set { flowMeterCfg.MsrdValLimLo = value; } }
|
||||||
public double MsrdValLimHi { get { return myCfg.MsrdValLimHi; } set { myCfg.MsrdValLimHi = value; } }
|
public double MsrdValLimHi { get { return flowMeterCfg.MsrdValLimHi; } set { flowMeterCfg.MsrdValLimHi = value; } }
|
||||||
|
|
||||||
|
|
||||||
public bool MsrmntAvailable
|
public bool MsrmntAvailable
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (flowMtr1 != null) result = (result && flowMtr1.MsrmntAvailable);
|
if (flowMtr1 != null) result = result && flowMtr1.MsrmntAvailable;
|
||||||
if (flowMtr2 != null) result = (result && flowMtr2.MsrmntAvailable);
|
if (flowMtr2 != null) result = result && flowMtr2.MsrmntAvailable;
|
||||||
if (flowMtr3 != null) result = (result && flowMtr3.MsrmntAvailable);
|
if (flowMtr3 != null) result = result && flowMtr3.MsrmntAvailable;
|
||||||
if (inactiveFlowMtr != null) result = (result && !inactiveFlowMtr.MsrmntAvailable);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,24 +59,22 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
|
|
||||||
public string AltString { get { return "Invalid format"; } }
|
public string AltString { get { return "Invalid format"; } }
|
||||||
|
|
||||||
|
public FlowMeter() { }
|
||||||
|
|
||||||
public FlowMeter() { }
|
public FlowMeter(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
|
||||||
|
: base(cfg)
|
||||||
public FlowMeter(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
|
{
|
||||||
: base(cfg)
|
flowMeterCfg = cfg as FlowMeterCfg;
|
||||||
{
|
}
|
||||||
myCfg = cfg as FlowMeterCfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
uniCB = TbfComponents.FindComponent(myCfg.ParentName) as UniCB;
|
uniCB = TbfComponents.FindComponent(flowMeterCfg.ParentName) as UniCB;
|
||||||
if (uniCB == null) throw new Exception("Cannot find " + Name + " parent");
|
if (uniCB == null) throw new Exception("Cannot find " + Name + " parent");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(myCfg.Flowmeter1)) flowMtr1 = TbfComponents.FindComponent(myCfg.Flowmeter1) as IFlowMeterSingle;
|
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter1)) flowMtr1 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter1) as IFlowMeterSingle;
|
||||||
if (!string.IsNullOrEmpty(myCfg.Flowmeter2)) flowMtr2 = TbfComponents.FindComponent(myCfg.Flowmeter2) as IFlowMeterSingle;
|
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter2)) flowMtr2 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter2) as IFlowMeterSingle;
|
||||||
if (!string.IsNullOrEmpty(myCfg.Flowmeter3)) flowMtr3 = TbfComponents.FindComponent(myCfg.Flowmeter3) as IFlowMeterSingle;
|
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter3)) flowMtr3 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter3) as IFlowMeterSingle;
|
||||||
if (!string.IsNullOrEmpty(myCfg.InactiveFlowmtr)) inactiveFlowMtr = TbfComponents.FindComponent(myCfg.InactiveFlowmtr) as IFlowMeterSingle;
|
|
||||||
|
|
||||||
nominalFlow = 0;
|
nominalFlow = 0;
|
||||||
flowMetersCount = 0;
|
flowMetersCount = 0;
|
||||||
@@ -91,8 +87,8 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
flowMetersBitfield |= (4 << flowMtr1.Idx1);
|
flowMetersBitfield |= (4 << flowMtr1.Idx1);
|
||||||
flowMetersCount++;
|
flowMetersCount++;
|
||||||
}
|
}
|
||||||
if (flowMtr2 != null)
|
if (flowMtr2 != null)
|
||||||
{
|
{
|
||||||
nominalFlow += flowMtr2.NominalFlow;
|
nominalFlow += flowMtr2.NominalFlow;
|
||||||
nominalFreq += flowMtr2.NominalFreq;
|
nominalFreq += flowMtr2.NominalFreq;
|
||||||
flowMetersBitfield |= (4 << flowMtr2.Idx1);
|
flowMetersBitfield |= (4 << flowMtr2.Idx1);
|
||||||
@@ -109,15 +105,31 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
|
|
||||||
MsrdValLimHi = nominalFlow;
|
MsrdValLimHi = nominalFlow;
|
||||||
|
|
||||||
|
nominalFreq = nominalFreq / flowMetersCount;
|
||||||
|
|
||||||
ltrPerPulse = nominalFlow / (3.6 * nominalFreq); /// Nominal freq. is sum of particular nominal frquencies
|
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}",
|
log.FatalFormat("{0} initialized: {1} nom.flow={2} m3/h nom.freq={3} Hz bitfield=0x{4:X2}",
|
||||||
Name, this, nominalFlow, nominalFreq, flowMetersBitfield);
|
Name, true, nominalFlow, nominalFreq, flowMetersBitfield);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double ReadFlow()
|
public double ReadFlow()
|
||||||
{
|
{
|
||||||
return ReadFrequency() * nominalFlow / nominalFreq;
|
double flowByNewFormulaSum = 0;
|
||||||
|
|
||||||
|
if (flowMtr1 != null)
|
||||||
|
{
|
||||||
|
flowByNewFormulaSum += flowMtr1.NominalFlow * uniCB.Data.ReferenceFreq[1] / flowMtr1.NominalFreq;
|
||||||
|
}
|
||||||
|
if (flowMtr2 != null)
|
||||||
|
{
|
||||||
|
flowByNewFormulaSum += flowMtr2.NominalFlow * uniCB.Data.ReferenceFreq[2] / flowMtr2.NominalFreq;
|
||||||
|
}
|
||||||
|
if (flowMtr3 != null)
|
||||||
|
{
|
||||||
|
flowByNewFormulaSum += flowMtr3.NominalFlow * uniCB.Data.ReferenceFreq[3] / flowMtr3.NominalFreq;
|
||||||
|
}
|
||||||
|
return flowByNewFormulaSum/*ReadFrequency() * nominalFlow / nominalFreq*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double ReadFrequency()
|
public double ReadFrequency()
|
||||||
@@ -125,27 +137,26 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
return uniCB.RefFrequency;
|
return uniCB.RefFrequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Events: FlowDone, Error
|
/// Events: FlowDone, Error
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flow">Reference to a variable for the flow in Bar</param>
|
/// <param name="flow">Reference to a variable for the flow in Bar</param>
|
||||||
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
|
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
|
||||||
public IOperation ReadFlowOp(ref DoubleBox flow)
|
public IOperation ReadFlowOp(ref DoubleBox flow)
|
||||||
{
|
{
|
||||||
return new ReadFlowOp(this, ref flow);
|
return new ReadFlowOp(this, ref flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Events: flowDone, Error
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="flow">Reference to a variable for the flow in Bar</param>
|
|
||||||
/// <param name="flowDone">Event returned when measurement done</param>
|
|
||||||
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
|
|
||||||
public IOperation ReadFlowOp(ref DoubleBox flow, Event flowDone)
|
|
||||||
{
|
|
||||||
return new ReadFlowOp(this, ref flow, flowDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Events: flowDone, Error
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flow">Reference to a variable for the flow in Bar</param>
|
||||||
|
/// <param name="flowDone">Event returned when measurement done</param>
|
||||||
|
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
|
||||||
|
public IOperation ReadFlowOp(ref DoubleBox flow, Event flowDone)
|
||||||
|
{
|
||||||
|
return new ReadFlowOp(this, ref flow, flowDone);
|
||||||
|
}
|
||||||
|
|
||||||
double flowRawSum;
|
double flowRawSum;
|
||||||
double flowSum;
|
double flowSum;
|
||||||
@@ -197,7 +208,7 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
public double LtrPerPulseCorrected(double flow, float temperature)
|
public double LtrPerPulseCorrected(double flow, float temperature)
|
||||||
{
|
{
|
||||||
double ltrPerPulseCorrected = (flowRawSum == 0) ? LtrPerPulse : LtrPerPulse * flowSum / flowRawSum;
|
double ltrPerPulseCorrected = (flowRawSum == 0) ? LtrPerPulse : LtrPerPulse * flowSum / flowRawSum;
|
||||||
log.WarnFormat("LtrPerPulseCorrected() flow = {0:F3} m3/h flowRawSum = {1:F3} m3/h flowSum = {2:F3} m3/h temperature = {3:F1} C ltrPerPulseCorrected = {4}", flow, flowRawSum, flowSum, temperature, ltrPerPulseCorrected);
|
log.WarnFormat("LtrPerPulseCorrected() flow = {0} m3/h flowRawSum = {1} m3/h flowSum = {2} m3/h temperature = {3} C ltrPerPulseCorrected = {4}", flow, flowRawSum, flowSum, temperature, ltrPerPulseCorrected);
|
||||||
return ltrPerPulseCorrected;
|
return ltrPerPulseCorrected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ using TBF.Rig.Generic;
|
|||||||
namespace TBF.Rig.Uni.FlowMetersInParallel
|
namespace TBF.Rig.Uni.FlowMetersInParallel
|
||||||
{
|
{
|
||||||
public class FlowMeterCfg : ComponentCfgBase, IChildComponentCfg, IParamsProvider, IDrawingItemWithMeasuredVal
|
public class FlowMeterCfg : ComponentCfgBase, IChildComponentCfg, IParamsProvider, IDrawingItemWithMeasuredVal
|
||||||
{
|
{
|
||||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlowMeterCfg) })[0];
|
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlowMeterCfg) })[0];
|
||||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||||
|
|
||||||
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
|
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
|
||||||
{
|
{
|
||||||
@@ -24,15 +24,14 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
return new Configs.ParamsProvider.ComponentCfgCtrl(this, parents);
|
return new Configs.ParamsProvider.ComponentCfgCtrl(this, parents);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Serialized parameters
|
/// Serialized parameters
|
||||||
///
|
///
|
||||||
public string Flowmeter1; /// 0 Flowmeter component name or string.Empty
|
public string Flowmeter1; /// 0 Flowmeter component name or string.Empty
|
||||||
public string Flowmeter2; /// 1 - ' ' -
|
public string Flowmeter2; /// 1 - ' ' -
|
||||||
public string Flowmeter3; /// 2 - ' ' -
|
public string Flowmeter3; /// 2 - ' ' -
|
||||||
public string InactiveFlowmtr; /// 3 Inactive flowmeter component name or string.Empty
|
public string MsrdFormat { get; set; } /// 3
|
||||||
public string MsrdFormat { get; set; } /// 4
|
public Unit MsrdUnit { get; set; } /// 4
|
||||||
public Unit MsrdUnit { get; set; } /// 5
|
|
||||||
|
|
||||||
/// Schematic drawing info
|
/// Schematic drawing info
|
||||||
public Shape Shape { get; set; }
|
public Shape Shape { get; set; }
|
||||||
@@ -58,9 +57,6 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
|
|
||||||
private IEnumerable<Config.Entities.Component> flowMeters;
|
private IEnumerable<Config.Entities.Component> flowMeters;
|
||||||
|
|
||||||
[XmlIgnore]
|
|
||||||
public bool IsOffline { get; set; }
|
|
||||||
|
|
||||||
/// Private parameterless constructor invoked by all other (public) constructors
|
/// Private parameterless constructor invoked by all other (public) constructors
|
||||||
FlowMeterCfg()
|
FlowMeterCfg()
|
||||||
{
|
{
|
||||||
@@ -82,12 +78,13 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
|
|
||||||
public string ComponentName { get { return Name; } }
|
public string ComponentName { get { return Name; } }
|
||||||
|
|
||||||
|
public bool IsOffline { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
public void InitializeAll()
|
public void InitializeAll()
|
||||||
{
|
{
|
||||||
Flowmeter1 = "I11";
|
Flowmeter1 = "I11";
|
||||||
Flowmeter2 = "I12";
|
Flowmeter2 = "I12";
|
||||||
Flowmeter3 = string.Empty;
|
Flowmeter3 = string.Empty;
|
||||||
InactiveFlowmtr = "I13";
|
|
||||||
MsrdFormat = "{0:F3} m3/h";
|
MsrdFormat = "{0:F3} m3/h";
|
||||||
MsrdUnit = Unit.m3ph;
|
MsrdUnit = Unit.m3ph;
|
||||||
}
|
}
|
||||||
@@ -97,9 +94,8 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
"Flow meter 1", /// 0
|
"Flow meter 1", /// 0
|
||||||
"Flow meter 2", /// 1
|
"Flow meter 2", /// 1
|
||||||
"Flow meter 3", /// 2
|
"Flow meter 3", /// 2
|
||||||
"Inactive flow meter", /// 3
|
"Display format", /// 3
|
||||||
"Display format", /// 4
|
"Unit of flow on a display", /// 4
|
||||||
"Unit of flow on a display", /// 5
|
|
||||||
};
|
};
|
||||||
public string ParamName(int i) { return paramNames[i]; }
|
public string ParamName(int i) { return paramNames[i]; }
|
||||||
public int ParamsCount() { return paramNames.Length; }
|
public int ParamsCount() { return paramNames.Length; }
|
||||||
@@ -111,48 +107,44 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
|
||||||
if (flowMeters == null) return null;
|
if (flowMeters == null) return null;
|
||||||
var fmtrs = new List<string>();
|
var fmtrs = new List<string>();
|
||||||
foreach (var fmtr in flowMeters) fmtrs.Add(fmtr.Name);
|
foreach (var fmtr in flowMeters) fmtrs.Add(fmtr.Name);
|
||||||
fmtrs.Add("---");
|
fmtrs.Add("---");
|
||||||
return fmtrs;
|
return fmtrs;
|
||||||
case 5:
|
case 4:
|
||||||
return new string[] { "m3/h", "l/h", "gal/m" };
|
return new string[] { "m3/h", "l/h" };
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToString(int i)
|
public string ToString(int i)
|
||||||
{
|
{
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case 0: return string.IsNullOrEmpty(Flowmeter1) ? "---" : Flowmeter1;
|
case 0: return string.IsNullOrEmpty(Flowmeter1) ? "---" : Flowmeter1;
|
||||||
case 1: return string.IsNullOrEmpty(Flowmeter2) ? "---" : Flowmeter2;
|
case 1: return string.IsNullOrEmpty(Flowmeter2) ? "---" : Flowmeter2;
|
||||||
case 2: return string.IsNullOrEmpty(Flowmeter3) ? "---" : Flowmeter3;
|
case 2: return string.IsNullOrEmpty(Flowmeter3) ? "---" : Flowmeter3;
|
||||||
case 3: return string.IsNullOrEmpty(InactiveFlowmtr) ? "---" : InactiveFlowmtr;
|
case 3: return MsrdFormat;
|
||||||
case 4: return MsrdFormat;
|
case 4: return MsrdUnit.ToDescription();
|
||||||
case 5: return MsrdUnit.ToDescription();
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return string.Format("Name={0} {1} {2} {3} ~{4} fmt={5} unit={6} Lo={7} Hi={8}",
|
return string.Format("Name={0} {1} {2} {3} fmt={4} unit={5} Lo={6} Hi={7}",
|
||||||
Name, Flowmeter1, Flowmeter2, Flowmeter3, InactiveFlowmtr,
|
Name, Flowmeter1, Flowmeter2, Flowmeter3,
|
||||||
MsrdFormat, MsrdUnit.ToDescription(), MsrdValLimLo, MsrdValLimHi);
|
MsrdFormat, MsrdUnit.ToDescription(), MsrdValLimLo, MsrdValLimHi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CfgUpdateFlags UpdateParam(int i, string str)
|
public CfgUpdateFlags UpdateParam(int i, string str)
|
||||||
{
|
{
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case 0: Flowmeter1 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
case 0: Flowmeter1 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
||||||
case 1: Flowmeter2 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
case 1: Flowmeter2 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
||||||
case 2: Flowmeter3 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
case 2: Flowmeter3 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
||||||
case 3: InactiveFlowmtr = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
|
case 3: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd;
|
||||||
case 4: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd;
|
case 4: MsrdUnit = (str == "l/h") ? Unit.lph : Unit.m3ph; return CfgUpdateFlags.RestartRqrd;
|
||||||
//case 5: MsrdUnit = (str == "l/h") ? Unit.lph : Unit.m3ph; return CfgUpdateFlags.RestartRqrd;
|
|
||||||
case 5: MsrdUnit = ParseFlowUnit(str); return CfgUpdateFlags.RestartRqrd;
|
|
||||||
default:
|
default:
|
||||||
return CfgUpdateFlags.None;
|
return CfgUpdateFlags.None;
|
||||||
}
|
}
|
||||||
@@ -167,11 +159,10 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 4:
|
||||||
case 5:
|
|
||||||
if (ParamValues(i).Contains(str)) return true;
|
if (ParamValues(i).Contains(str)) return true;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 3:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
message = "Invalid index";
|
message = "Invalid index";
|
||||||
@@ -187,7 +178,6 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
prms.Flowmeter1 = this.Flowmeter1;
|
prms.Flowmeter1 = this.Flowmeter1;
|
||||||
prms.Flowmeter2 = this.Flowmeter2;
|
prms.Flowmeter2 = this.Flowmeter2;
|
||||||
prms.Flowmeter3 = this.Flowmeter3;
|
prms.Flowmeter3 = this.Flowmeter3;
|
||||||
prms.InactiveFlowmtr = this.InactiveFlowmtr;
|
|
||||||
prms.MsrdFormat = this.MsrdFormat;
|
prms.MsrdFormat = this.MsrdFormat;
|
||||||
prms.MsrdUnit = this.MsrdUnit;
|
prms.MsrdUnit = this.MsrdUnit;
|
||||||
}
|
}
|
||||||
@@ -203,19 +193,5 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
|
|||||||
{
|
{
|
||||||
return true; /// =OK, do nothing
|
return true; /// =OK, do nothing
|
||||||
}
|
}
|
||||||
public static Unit ParseFlowUnit(string str)
|
|
||||||
{
|
|
||||||
//Check if the string is a valid unit description
|
|
||||||
Unit fromDescription = Units.FromDescription(str);
|
|
||||||
if (fromDescription != Unit.None) return fromDescription;
|
|
||||||
//check if the string is a valid unit name
|
|
||||||
switch (str)
|
|
||||||
{
|
|
||||||
case "l/h": return Unit.lph;
|
|
||||||
case "gal/m": return Unit.USgalpm;
|
|
||||||
case "m3/h":
|
|
||||||
default: return Unit.m3ph;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,57 +8,57 @@ using TBF.Rig.GenericDevices;
|
|||||||
|
|
||||||
namespace TBF.Rig.Uni.FlowMetersInParallel
|
namespace TBF.Rig.Uni.FlowMetersInParallel
|
||||||
{
|
{
|
||||||
public class ReadFlowOp : IOperation
|
public class ReadFlowOp : IOperation
|
||||||
{
|
{
|
||||||
private static readonly ILog log = LogManager.GetLogger(typeof(ReadFlowOp));
|
private static readonly ILog log = LogManager.GetLogger(typeof(ReadFlowOp));
|
||||||
public override string ToString() { return string.Format("ReadFlowOp({0},.,.,{1})", flowMeter.Idx1, eventDone); }
|
public override string ToString() { return string.Format("ReadFlowOp({0},.,.,{1})", flowMeter.Idx1, eventDone); }
|
||||||
|
|
||||||
/// Set by the constructor
|
/// Set by the constructor
|
||||||
readonly IFlowMeter flowMeter;
|
readonly IFlowMeter flowMeter;
|
||||||
readonly DoubleBox flowBox;
|
readonly DoubleBox flowBox;
|
||||||
readonly Event eventDone;
|
readonly Event eventDone;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Events: FlowInDone, FlowOutDone or Error
|
/// Events: FlowInDone, FlowOutDone or Error
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flowMeter">Flow meter reference</param>
|
/// <param name="flowMeter">Flow meter reference</param>
|
||||||
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
|
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
|
||||||
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
|
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
|
||||||
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox, Event eventDone)
|
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox, Event eventDone)
|
||||||
{
|
{
|
||||||
if (flowMeter == null) throw new ArgumentNullException();
|
if (flowMeter == null) throw new ArgumentNullException();
|
||||||
|
|
||||||
this.flowMeter = flowMeter;
|
this.flowMeter = flowMeter;
|
||||||
this.eventDone = eventDone;
|
this.eventDone = eventDone;
|
||||||
this.flowBox = flowBox;
|
this.flowBox = flowBox;
|
||||||
|
|
||||||
log.Debug(this.ToString());
|
log.Debug(this.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox)
|
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox)
|
||||||
: this(flowMeter, ref flowBox, Event.FlowMeasurementDone)
|
: this(flowMeter, ref flowBox, Event.FlowMeasurementDone)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Start this operation</summary>
|
/// <summary>Start this operation</summary>
|
||||||
public void Start() { }
|
public void Start() { }
|
||||||
|
|
||||||
/// <summary>Run this operation</summary>
|
/// <summary>Run this operation</summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Event.FlowInDone or Event.FlowOutDone
|
/// Event.FlowInDone or Event.FlowOutDone
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public Event Run()
|
public Event Run()
|
||||||
{
|
{
|
||||||
if (flowMeter.MsrmntAvailable)
|
if (flowMeter.MsrmntAvailable)
|
||||||
{
|
{
|
||||||
if (flowBox != null) flowBox.Val = flowMeter.ReadFlow();
|
if (flowBox != null) flowBox.Val = flowMeter.ReadFlow();
|
||||||
return eventDone;
|
return eventDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Event.Error;
|
return Event.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Stop this operation</summary>
|
/// <summary>Stop this operation</summary>
|
||||||
public void Stop() { }
|
public void Stop() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
///
|
///
|
||||||
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
|
/// Copyright (c) 2021 Sensus Metering Systems
|
||||||
///
|
///
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using log4net;
|
using log4net;
|
||||||
using TBF.Rig.ControlBoard.Uni;
|
|
||||||
using TBF.Rig.GenericDevices;
|
using TBF.Rig.GenericDevices;
|
||||||
|
|
||||||
namespace TBF.Rig.Uni.RegValve
|
namespace TBF.Rig.Uni.RegValve
|
||||||
@@ -14,12 +13,12 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
private static readonly ILog log = LogManager.GetLogger(typeof(ChangeRegValvePositionOp));
|
private static readonly ILog log = LogManager.GetLogger(typeof(ChangeRegValvePositionOp));
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regV.Name, timePulseSec.ToString("F2"));
|
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regulValve.Name, timePulseSec.ToString("F2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set by the constructor
|
/// Set by the constructor
|
||||||
readonly UniCB uniCB;
|
readonly TBF.Rig.ControlBoard.Uni.UniCB controlBoard;
|
||||||
readonly RegValve regV;
|
readonly RegValve regulValve;
|
||||||
readonly int regulValveNr;
|
readonly int regulValveNr;
|
||||||
readonly double timePulseSec;
|
readonly double timePulseSec;
|
||||||
|
|
||||||
@@ -33,14 +32,14 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
|
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
|
||||||
/// <param name="timeout">Timeout in sec. for setting the flow</param>
|
/// <param name="timeout">Timeout in sec. for setting the flow</param>
|
||||||
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
|
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
|
||||||
public ChangeRegValvePositionOp(UniCB uniCB, RegValve regV, double timePulseSec)
|
public ChangeRegValvePositionOp(TBF.Rig.ControlBoard.IControlBoard cb, RegValve rv, double timePulseSec)
|
||||||
{
|
{
|
||||||
this.uniCB = uniCB;
|
controlBoard = cb as TBF.Rig.ControlBoard.Uni.UniCB;
|
||||||
if (this.uniCB == null) throw new ArgumentNullException("ctrlBoard");
|
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
|
||||||
|
|
||||||
this.regV = regV as RegValve;
|
regulValve = rv as RegValve;
|
||||||
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
|
if (regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
|
||||||
regulValveNr = this.regV.Idx1;
|
regulValveNr = this.regulValve.Idx1;
|
||||||
|
|
||||||
this.timePulseSec = timePulseSec;
|
this.timePulseSec = timePulseSec;
|
||||||
|
|
||||||
@@ -50,7 +49,13 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
/// <summary>Start this operation</summary>
|
/// <summary>Start this operation</summary>
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
uniCB.RegVlvIncrMove(false, regulValveNr, timePulseSec);
|
//double positionPct = controlBoard.RValvePosition(regulValveNr);
|
||||||
|
//log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
|
||||||
|
|
||||||
|
//controlBoard.ValveMove(regulValveNr,
|
||||||
|
// TBF.Rig.ControlBoard.Legacy.RegulValveMode.PulseWidth,
|
||||||
|
// new double[2] { timePulseSec, timePulseSec },
|
||||||
|
// regulValve.StableTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Run this operation</summary>
|
/// <summary>Run this operation</summary>
|
||||||
@@ -59,6 +64,9 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
/// </returns>
|
/// </returns>
|
||||||
public Event Run()
|
public Event Run()
|
||||||
{
|
{
|
||||||
|
//float positionPct = controlBoard.RValvePosition(regulValveNr);
|
||||||
|
//log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
|
||||||
|
|
||||||
return Event.PositionReached;
|
return Event.PositionReached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
///
|
///
|
||||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
/// Copyright (c) 2021 Sensus Metering Systems
|
||||||
///
|
///
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using TBF.Rig.Generic;
|
using TBF.Rig.Generic;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
///
|
///
|
||||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
/// Copyright (c) 2021 Sensus Metering Systems
|
||||||
///
|
///
|
||||||
using System;
|
using System;
|
||||||
using log4net;
|
using log4net;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
///
|
///
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Common;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Config.Entities;
|
using Config.Entities;
|
||||||
using TBF.Rig.ControlBoard.Uni;
|
using TBF.Rig.ControlBoard.Uni;
|
||||||
@@ -19,10 +20,11 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regV.Name, shrinkedTgtFlowLo, shrinkedTgtFlowHi);
|
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regV.Name, shrinkedTgtFlowLo, shrinkedTgtFlowHi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public const double RqrdFlowRangeRatio = 0.5;
|
public const double RqrdFlowRangeRatio = 0.5;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set by the constructor
|
/// Set by the constructor
|
||||||
///
|
///
|
||||||
readonly UniCB uniCB;
|
readonly UniCB uniCB;
|
||||||
readonly RegValve regV;
|
readonly RegValve regV;
|
||||||
@@ -35,8 +37,8 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
readonly bool leaveFlowControlRunning;
|
readonly bool leaveFlowControlRunning;
|
||||||
|
|
||||||
readonly double maximalFlow;
|
readonly double maximalFlow;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Internal state of this operation
|
/// Internal state of this operation
|
||||||
///
|
///
|
||||||
enum OpState
|
enum OpState
|
||||||
@@ -55,12 +57,13 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
|
|
||||||
double currentReqFlowLo;
|
double currentReqFlowLo;
|
||||||
double currentReqFlowHi;
|
double currentReqFlowHi;
|
||||||
double targetPositionLo;
|
double targetPositionLo;
|
||||||
double targetPositionHi;
|
double targetPositionHi;
|
||||||
|
|
||||||
|
int startTime;
|
||||||
int setFlowTime;
|
int setFlowTime;
|
||||||
int expireTime;
|
int expireTime;
|
||||||
DoubleBox msrdFlow;
|
DoubleBox flowBox;
|
||||||
int isFlowOkDuration;
|
int isFlowOkDuration;
|
||||||
|
|
||||||
|
|
||||||
@@ -69,23 +72,23 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
/// Events: FlowSet, FlowTimeOut
|
/// Events: FlowSet, FlowTimeOut
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uniCB">Control board device</param>
|
/// <param name="uniCB">Control board device</param>
|
||||||
/// <param name="regValve">Regulation valve component</param>
|
/// <param name="regulValve">Regulation valve component</param>
|
||||||
/// <param name="flowMeter">Flowmeter component</param>
|
/// <param name="flowMeter">Flowmeter component</param>
|
||||||
/// <param name="qFrom">Lower limit of the flow to be achieved in [m3/h]</param>
|
/// <param name="qFrom">Lower limit of the flow to be achieved in [m3/h]</param>
|
||||||
/// <param name="qTo">Upper limit of the flow to be achieved in [m3/h]</param>
|
/// <param name="qTo">Upper limit of the flow to be achieved in [m3/h]</param>
|
||||||
/// <param name="msrdFlow">DoubleBox for measured flow</param>
|
/// <param name="pidCoef">PID coefficient (float)</param>
|
||||||
/// <param name="timeout">Timeout for the flow setting in [s]</param>
|
/// <param name="timeout">Timeout for the flow setting in [s]</param>
|
||||||
/// <param name="delay">Flow setting starts after this delay in [s]</param>
|
/// <param name="delay">Flow setting starts after this delay [s]</param>
|
||||||
/// <param name="leaveFlowControlRunning">true = Leave the measurement running after op. stop</param>
|
/// <param name="leaveFlowControlRunning">true = Leave the measurement running after op. stop</param>
|
||||||
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
|
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
|
||||||
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox msrdFlow,
|
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox flowBox,
|
||||||
int timeout, int delay, bool leaveFlowControlRunning)
|
int timeout, int delay, bool leaveFlowControlRunning)
|
||||||
{
|
{
|
||||||
this.uniCB = uniCB;
|
this.uniCB = uniCB;
|
||||||
if (this.uniCB == null) throw new ArgumentNullException("Control board is null or not Uni");
|
if (this.uniCB == null) throw new ArgumentNullException("cBoard is null or not Uni");
|
||||||
|
|
||||||
this.regV = regValve as RegValve;
|
this.regV = regValve as RegValve;
|
||||||
if (this.regV == null) throw new ArgumentNullException(string.Format("{0} is not Uni.RegValve", regValve.Name));
|
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
|
||||||
|
|
||||||
this.flowMeter = flowMeter;
|
this.flowMeter = flowMeter;
|
||||||
if (this.flowMeter == null) throw new ArgumentNullException("flowMeter");
|
if (this.flowMeter == null) throw new ArgumentNullException("flowMeter");
|
||||||
@@ -95,14 +98,15 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
double rqrdFlowLoBeforeCorr = qFrom - MeasurementCorrection.GetCorrection(qFrom, flowMeter.Corrections);
|
double rqrdFlowLoBeforeCorr = qFrom - MeasurementCorrection.GetCorrection(qFrom, flowMeter.Corrections);
|
||||||
double rqrdFlowHiBeforeCorr = qTo - MeasurementCorrection.GetCorrection(qTo, flowMeter.Corrections);
|
double rqrdFlowHiBeforeCorr = qTo - MeasurementCorrection.GetCorrection(qTo, flowMeter.Corrections);
|
||||||
targetFlowAve = (rqrdFlowLoBeforeCorr + rqrdFlowHiBeforeCorr) / 2;
|
targetFlowAve = (rqrdFlowLoBeforeCorr + rqrdFlowHiBeforeCorr) / 2;
|
||||||
shrinkedTgtFlowLo = (RqrdFlowRangeRatio * rqrdFlowLoBeforeCorr)
|
shrinkedTgtFlowLo = (RqrdFlowRangeRatio * rqrdFlowLoBeforeCorr) + ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the lower limit 15% of the range up
|
||||||
+ ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the lower limit 15% of the range up
|
shrinkedTgtFlowHi = (RqrdFlowRangeRatio * rqrdFlowHiBeforeCorr) + ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the upper limit 15% of the range down
|
||||||
shrinkedTgtFlowHi = (RqrdFlowRangeRatio * rqrdFlowHiBeforeCorr)
|
|
||||||
+ ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the upper limit 15% of the range down
|
this.flowBox = flowBox;
|
||||||
|
if (this.flowBox == null) throw new ArgumentNullException("flowBox");
|
||||||
|
|
||||||
this.msrdFlow = msrdFlow;
|
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.delay = delay;
|
this.delay = delay;
|
||||||
|
|
||||||
this.leaveFlowControlRunning = leaveFlowControlRunning;
|
this.leaveFlowControlRunning = leaveFlowControlRunning;
|
||||||
|
|
||||||
log.Debug(this.ToString());
|
log.Debug(this.ToString());
|
||||||
@@ -168,13 +172,16 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Start this operation</summary>
|
/// <summary>
|
||||||
|
/// Start this operation
|
||||||
|
/// </summary>
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
|
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
|
||||||
regV.Idx1, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
|
regV.Idx1, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
|
||||||
|
|
||||||
/// Store the current time, etc.
|
/// Store the current time, etc.
|
||||||
|
startTime = StateMachine.Time;
|
||||||
setFlowTime = StateMachine.Time + delay;
|
setFlowTime = StateMachine.Time + delay;
|
||||||
expireTime = StateMachine.Time + timeout;
|
expireTime = StateMachine.Time + timeout;
|
||||||
if (expireTime < 0) expireTime = int.MaxValue;
|
if (expireTime < 0) expireTime = int.MaxValue;
|
||||||
@@ -200,6 +207,11 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
public Event Run()
|
public Event Run()
|
||||||
{
|
{
|
||||||
log.DebugFormat("Op.Run() opState={0}", opState);
|
log.DebugFormat("Op.Run() opState={0}", opState);
|
||||||
|
|
||||||
|
if (this.uniCB?.DebugLevel == DebugMode.Simulate)
|
||||||
|
{
|
||||||
|
return Event.FlowReached;
|
||||||
|
}
|
||||||
|
|
||||||
if (StateMachine.Time > expireTime) return Event.RegulValveTimeOut;
|
if (StateMachine.Time > expireTime) return Event.RegulValveTimeOut;
|
||||||
|
|
||||||
@@ -267,16 +279,17 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
///
|
///
|
||||||
double frequency = flowMeter.ReadFrequency();
|
double frequency = flowMeter.ReadFrequency();
|
||||||
double flow = flowMeter.ReadFlow();
|
double flow = flowMeter.ReadFlow();
|
||||||
if (msrdFlow != null && flow != 0) msrdFlow.Val = flow;
|
if (flow != 0) flowBox.Val = flow;
|
||||||
|
|
||||||
if (currentReqFlowLo <= flow && flow <= currentReqFlowHi)
|
if ((currentReqFlowLo <= flow) && (flow <= currentReqFlowHi))
|
||||||
{
|
{
|
||||||
isFlowOkDuration++; /// Increment the flow within range duration
|
/// Flow is within range
|
||||||
|
isFlowOkDuration++;
|
||||||
|
|
||||||
if (isFlowOkDuration >= regV.FlowStableSec)
|
if (isFlowOkDuration >= regV.FlowStableSec)
|
||||||
{
|
{
|
||||||
/// Flow is within range for sufficiently long time
|
/// Flow is within range for sufficiently long time
|
||||||
if (regV.StoredPositionReuse)
|
if (regV.regValveCfg.StoredPositionReuse)
|
||||||
{
|
{
|
||||||
double rvPosition = regV.Position; /// Read the current position
|
double rvPosition = regV.Position; /// Read the current position
|
||||||
double storedPosition;
|
double storedPosition;
|
||||||
@@ -323,12 +336,13 @@ namespace TBF.Rig.Uni.RegValve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Stop this operation</summary>
|
/// <summary>Start this operation</summary>
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
if (!leaveFlowControlRunning)
|
if (!leaveFlowControlRunning)
|
||||||
{
|
{
|
||||||
uniCB.StopFlowControl(false, regV.Idx1); /// Stop the flow measurement
|
/// Stop flow measurement
|
||||||
|
uniCB.StopFlowControl(false, regV.Idx1);
|
||||||
}
|
}
|
||||||
|
|
||||||
opState = OpState.Idle;
|
opState = OpState.Idle;
|
||||||
|
|||||||
+25
-8
@@ -71,7 +71,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
<OutputPath>bin\x86\Release\</OutputPath>
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
<DefineConstants>TRACE;CAMERA;LANG_PL;IPERL;</DefineConstants>
|
<DefineConstants>TRACE;CAMERA;LANG_PL;IPERL;LIVELOGDIAG_FlowMeter_cs;LIVELOGDIAG_RegValve_cs</DefineConstants>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -1049,7 +1049,9 @@
|
|||||||
<Compile Include="Rig\Operations\LargeMessageBoxOp.cs" />
|
<Compile Include="Rig\Operations\LargeMessageBoxOp.cs" />
|
||||||
<Compile Include="Rig\Operations\ReturnGivenEventOp.cs" />
|
<Compile Include="Rig\Operations\ReturnGivenEventOp.cs" />
|
||||||
<Compile Include="Rig\Output\DB\DatabaseWriter\Factory.cs" />
|
<Compile Include="Rig\Output\DB\DatabaseWriter\Factory.cs" />
|
||||||
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.cs" />
|
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.designer.cs" />
|
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.designer.cs" />
|
||||||
<Compile Include="Rig\Output\DB\DatabaseWriter\WriterCfg.cs" />
|
<Compile Include="Rig\Output\DB\DatabaseWriter\WriterCfg.cs" />
|
||||||
<Compile Include="Rig\Output\DB\DatabaseWriter\WritingToDB.cs" />
|
<Compile Include="Rig\Output\DB\DatabaseWriter\WritingToDB.cs" />
|
||||||
@@ -1293,6 +1295,7 @@
|
|||||||
<Compile Include="Rig\RegisterReaders\DataStream\Reader\ReaderCfg.cs" />
|
<Compile Include="Rig\RegisterReaders\DataStream\Reader\ReaderCfg.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\common\HexFormatter.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\common\HexFormatter.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\common\OptoTelegramRaw.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\common\OptoTelegramRaw.cs" />
|
||||||
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\ChannelAverages.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Genesis\Crc16Ccitt.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Genesis\Crc16Ccitt.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Genesis\DataPackages\EventArguments\BaseDataEventArgs.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Genesis\DataPackages\EventArguments\BaseDataEventArgs.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Genesis\DataPackages\EventArguments\BendDetectDataEventArgs.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Genesis\DataPackages\EventArguments\BendDetectDataEventArgs.cs" />
|
||||||
@@ -1385,12 +1388,16 @@
|
|||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Utils\SerialDriver.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Utils\SerialDriver.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Utils\SerialDriverBuilder.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Utils\SerialDriverBuilder.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\Factory.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\Factory.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.Designer.cs">
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.Designer.cs">
|
||||||
<DependentUpon>GenesisHeadTestCtrl.cs</DependentUpon>
|
<DependentUpon>GenesisHeadTestCtrl.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfg.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfg.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.designer.cs">
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.designer.cs">
|
||||||
<DependentUpon>GenesisCfgCtrl.cs</DependentUpon>
|
<DependentUpon>GenesisCfgCtrl.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -1409,9 +1416,13 @@
|
|||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\Factory.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\Factory.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\IPerlASICImplHeadTestCtrl.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\IPerlASICImplHeadTestCtrl.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\SmartReader.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\SmartReader.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.Designer.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.Designer.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.designer.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.designer.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlReaderUNI\common\IUniHeadTestCtrl.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlReaderUNI\common\IUniHeadTestCtrl.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlReaderUNI\Factory.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlReaderUNI\Factory.cs" />
|
||||||
@@ -1483,6 +1494,8 @@
|
|||||||
<DependentUpon>RRCfgCtrl.cs</DependentUpon>
|
<DependentUpon>RRCfgCtrl.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunner.cs" />
|
<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\Factory.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\JsonDataFromPoseidon.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\JsonDataFromPoseidon.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCfg.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCfg.cs" />
|
||||||
@@ -1714,7 +1727,9 @@
|
|||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\Factory.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\Factory.cs" />
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHead.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHead.cs" />
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfg.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfg.cs" />
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.designer.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.designer.cs" />
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\OptoReceivedEventArgs.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\OptoReceivedEventArgs.cs" />
|
||||||
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\OptoTelegramRaw.cs" />
|
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\OptoTelegramRaw.cs" />
|
||||||
@@ -1770,7 +1785,9 @@
|
|||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\ISerialDriver.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\ISerialDriver.cs" />
|
||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\SerialDriver.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\SerialDriver.cs" />
|
||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\SerialDriverBuilder.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\SerialDriverBuilder.cs" />
|
||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.designer.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.designer.cs" />
|
||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationParams.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationParams.cs" />
|
||||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationSeq.cs" />
|
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationSeq.cs" />
|
||||||
|
|||||||
@@ -189,8 +189,16 @@ namespace TBF.UI.Bench.Components
|
|||||||
int extraWidth = splitContainer.Panel2.Width + 40;
|
int extraWidth = splitContainer.Panel2.Width + 40;
|
||||||
int extraHeight = 80;
|
int extraHeight = 80;
|
||||||
|
|
||||||
this.Width = desired.Width + extraWidth;
|
if (!desired.IsEmpty)
|
||||||
this.Height = desired.Height + extraHeight;
|
{
|
||||||
|
this.Width = desired.Width + extraWidth;
|
||||||
|
this.Height = desired.Height + extraHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//this.Width += extraWidth;
|
||||||
|
//this.Height += extraHeight;
|
||||||
|
}
|
||||||
|
|
||||||
// Do not exceed screen working area
|
// Do not exceed screen working area
|
||||||
var screen = Screen.FromControl(this).WorkingArea;
|
var screen = Screen.FromControl(this).WorkingArea;
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ namespace TBF.UI.Bench.Components
|
|||||||
{
|
{
|
||||||
availCmpntsLstBox.SelectedIndex = selectedIndex;
|
availCmpntsLstBox.SelectedIndex = selectedIndex;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// SharedDlgSearchForListBox configuration
|
||||||
|
sharedSearchForListBox1.ListBoxEx = availCmpntsLstBox;
|
||||||
|
}
|
||||||
|
|
||||||
void Localize()
|
void Localize()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,13 +12,17 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
private static CalibrationRecord CreateCalibrationRecord(
|
private static CalibrationRecord CreateCalibrationRecord(
|
||||||
int channel = 1,
|
int channel = 1,
|
||||||
double volumeCm = 1.234,
|
double volumeCm = 1.234,
|
||||||
double timeS = 12.5)
|
double overflowVolumeCm = 8.38860799804687,
|
||||||
|
double timeS = 12.5,
|
||||||
|
double overflowTimeS = 65536.0)
|
||||||
{
|
{
|
||||||
return new CalibrationRecord
|
return new CalibrationRecord
|
||||||
{
|
{
|
||||||
Channel = channel,
|
Channel = channel,
|
||||||
VolumeCm = volumeCm,
|
VolumeCm = volumeCm,
|
||||||
TimeS = timeS
|
OverflowVolumeCm = overflowVolumeCm,
|
||||||
|
TimeS = timeS,
|
||||||
|
OverflowTimeS = overflowTimeS
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +30,12 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
public void UpdateFromSmart_FirstSample_ShouldInitializeFields()
|
public void UpdateFromSmart_FirstSample_ShouldInitializeFields()
|
||||||
{
|
{
|
||||||
var telegram = new OptoTelegramRaw();
|
var telegram = new OptoTelegramRaw();
|
||||||
var data = CreateCalibrationRecord(channel: 2, volumeCm: 2.5, timeS: 100.0);
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 2,
|
||||||
|
volumeCm: 2.5,
|
||||||
|
overflowVolumeCm: 8.38860799804687,
|
||||||
|
timeS: 100.0,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
double lastVolume = double.NaN;
|
double lastVolume = double.NaN;
|
||||||
double lastTimestamp = double.NaN;
|
double lastTimestamp = double.NaN;
|
||||||
@@ -54,32 +63,479 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.common
|
|||||||
Assert.AreEqual(0, telegram.MagneticFieldRaw);
|
Assert.AreEqual(0, telegram.MagneticFieldRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_RealGenesisDecodedSample_ShouldMapExpectedValues()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 2,
|
||||||
|
volumeCm: 0.48025591796875,
|
||||||
|
overflowVolumeCm: 8.38860799804687,
|
||||||
|
timeS: 62727.8408813477,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
double lastVolume = double.NaN;
|
||||||
|
double lastTimestamp = double.NaN;
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, counter: 1, refFlow: 0.0f, ref lastVolume, ref lastTimestamp);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, telegram.IChannel());
|
||||||
|
Assert.AreEqual(1, telegram.Counter);
|
||||||
|
Assert.AreEqual(0.0f, telegram.RefFlow);
|
||||||
|
Assert.AreEqual(OptoTelegramFlags.OK, telegram.Flags);
|
||||||
|
|
||||||
|
Assert.AreEqual(480.25591796875, telegram.VolumeRaw, 1e-9);
|
||||||
|
Assert.AreEqual(480.25591796875, telegram.VolumeRawExt, 1e-9);
|
||||||
|
Assert.AreEqual(480.25591796875, lastVolume, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(62727.8408813477, telegram.Timestamp, 1e-9);
|
||||||
|
Assert.AreEqual(62727.8408813477, telegram.TimestampExt, 1e-9);
|
||||||
|
Assert.AreEqual(62727.8408813477, lastTimestamp, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, telegram.FlowRaw);
|
||||||
|
Assert.AreEqual(0, telegram.CheckSum);
|
||||||
|
Assert.AreEqual(0, telegram.Impedance);
|
||||||
|
Assert.AreEqual(0, telegram.EmfRaw);
|
||||||
|
Assert.AreEqual(0, telegram.MagneticFieldRaw);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UpdateFromSmart_WhenVolumeDecreases_ShouldApplyVolumeRollover()
|
public void UpdateFromSmart_WhenVolumeDecreases_ShouldApplyVolumeRollover()
|
||||||
{
|
{
|
||||||
var telegram = new OptoTelegramRaw();
|
var telegram = new OptoTelegramRaw();
|
||||||
var data = CreateCalibrationRecord(channel: 1, volumeCm: 1.0, timeS: 10.0);
|
var overflowVolumeCm = 8.38860799804687;
|
||||||
|
var overflowRaw = overflowVolumeCm * 1000.0;
|
||||||
|
|
||||||
double previousExtendedVolume = 5000.0;
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: 1.0,
|
||||||
|
overflowVolumeCm: overflowVolumeCm,
|
||||||
|
timeS: 10.0,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
// Must be close enough to overflow so that current=1000 is interpreted as a wrap
|
||||||
|
double previousExtendedVolume = 8000.0;
|
||||||
double previousExtendedTimestamp = 10.0;
|
double previousExtendedTimestamp = 10.0;
|
||||||
|
|
||||||
telegram.UpdateFromSmart(data, counter: 1, refFlow: 0.5f, ref previousExtendedVolume, ref previousExtendedTimestamp);
|
telegram.UpdateFromSmart(
|
||||||
|
data,
|
||||||
|
counter: 1,
|
||||||
|
refFlow: 0.5f,
|
||||||
|
ref previousExtendedVolume,
|
||||||
|
ref previousExtendedTimestamp);
|
||||||
|
|
||||||
double expectedVolumeRaw = 1000.0;
|
double expectedVolumeRaw = 1000.0;
|
||||||
double expectedExtended = expectedVolumeRaw + StreamingDecoder.DefaultAccuDutOverflowVolumeCm * 1000.0;
|
double expectedExtended = expectedVolumeRaw + overflowRaw;
|
||||||
|
|
||||||
Assert.AreEqual(expectedVolumeRaw, telegram.VolumeRaw, 1e-9);
|
Assert.AreEqual(expectedVolumeRaw, telegram.VolumeRaw, 1e-9);
|
||||||
Assert.AreEqual(expectedExtended, telegram.VolumeRawExt, 1e-6);
|
Assert.AreEqual(expectedExtended, telegram.VolumeRawExt, 1e-6);
|
||||||
Assert.AreEqual(expectedExtended, previousExtendedVolume, 1e-6);
|
Assert.AreEqual(expectedExtended, previousExtendedVolume, 1e-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_MultipleVolumeRollover_ShouldKeepIncreasingExtendedVolume()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
double overflowVolumeCm = 8.38860799804687;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
// Safe sequence: small forward steps, natural wrap, small forward steps
|
||||||
|
double[] samples =
|
||||||
|
{
|
||||||
|
7.5,
|
||||||
|
8.0,
|
||||||
|
0.2,
|
||||||
|
1.0,
|
||||||
|
1.8,
|
||||||
|
2.6,
|
||||||
|
3.4,
|
||||||
|
4.2,
|
||||||
|
5.0,
|
||||||
|
5.8,
|
||||||
|
6.6,
|
||||||
|
7.4,
|
||||||
|
8.1,
|
||||||
|
0.3,
|
||||||
|
1.1
|
||||||
|
};
|
||||||
|
|
||||||
|
double previousExt = double.NaN;
|
||||||
|
|
||||||
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: samples[i],
|
||||||
|
overflowVolumeCm: overflowVolumeCm,
|
||||||
|
timeS: i,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
double expectedRaw = samples[i] * 1000.0;
|
||||||
|
Assert.AreEqual(expectedRaw, telegram.VolumeRaw, 1e-9, $"Raw mismatch at index {i}");
|
||||||
|
|
||||||
|
if (!double.IsNaN(previousExt))
|
||||||
|
{
|
||||||
|
Assert.IsTrue(
|
||||||
|
telegram.VolumeRawExt >= previousExt,
|
||||||
|
$"Volume should not decrease at index {i}. Prev={previousExt}, Current={telegram.VolumeRawExt}");
|
||||||
|
}
|
||||||
|
|
||||||
|
previousExt = telegram.VolumeRawExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_MultipleVolumeRollover_FirstToLastDeltaShouldBePositive()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
double overflowVolumeCm = 8.38860799804687;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
double[] samples =
|
||||||
|
{
|
||||||
|
7.5, 8.0, 0.2, 1.0, 1.8, 2.6, 3.4, 4.2, 5.0, 5.8, 6.6, 7.4, 8.1, 0.3, 1.1
|
||||||
|
};
|
||||||
|
|
||||||
|
double firstExt = double.NaN;
|
||||||
|
|
||||||
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: samples[i],
|
||||||
|
overflowVolumeCm: overflowVolumeCm,
|
||||||
|
timeS: i,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
firstExt = telegram.VolumeRawExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(lastVolumeExt > firstExt,
|
||||||
|
$"Volume should increase from first to last. First={firstExt}, Last={lastVolumeExt}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_MultipleVolumeRollover_ShouldMatchPhysicalDelta()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
double overflowVolumeCm = 8.38860799804687;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
double[] samples =
|
||||||
|
{
|
||||||
|
7.5,
|
||||||
|
8.0,
|
||||||
|
0.2,
|
||||||
|
1.0,
|
||||||
|
1.8,
|
||||||
|
2.6,
|
||||||
|
3.4,
|
||||||
|
4.2,
|
||||||
|
5.0,
|
||||||
|
5.8,
|
||||||
|
6.6,
|
||||||
|
7.4,
|
||||||
|
8.1,
|
||||||
|
0.3,
|
||||||
|
1.1
|
||||||
|
};
|
||||||
|
|
||||||
|
double firstExt = double.NaN;
|
||||||
|
double lastExt = double.NaN;
|
||||||
|
|
||||||
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: samples[i],
|
||||||
|
overflowVolumeCm: overflowVolumeCm,
|
||||||
|
timeS: i,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
firstExt = telegram.VolumeRawExt;
|
||||||
|
|
||||||
|
if (i == samples.Length - 1)
|
||||||
|
lastExt = telegram.VolumeRawExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
double start = samples[0];
|
||||||
|
double end = samples[samples.Length - 1];
|
||||||
|
|
||||||
|
int wraps = 0;
|
||||||
|
for (int i = 1; i < samples.Length; i++)
|
||||||
|
{
|
||||||
|
if (samples[i] < samples[i - 1])
|
||||||
|
wraps++;
|
||||||
|
}
|
||||||
|
|
||||||
|
double expectedDeltaCm = wraps * overflowVolumeCm + end - start;
|
||||||
|
double expectedDeltaRaw = expectedDeltaCm * 1000.0;
|
||||||
|
double actualDeltaRaw = lastExt - firstExt;
|
||||||
|
|
||||||
|
Assert.AreEqual(
|
||||||
|
expectedDeltaRaw,
|
||||||
|
actualDeltaRaw,
|
||||||
|
1e-6,
|
||||||
|
$"Delta mismatch. Wraps={wraps}, Expected={expectedDeltaRaw}, Actual={actualDeltaRaw}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_MultipleTimestampWrap_ShouldMatchPhysicalDelta()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
|
||||||
|
double overflowTimeS = 65536.0;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
// Safe sequence: small forward steps, natural wrap, small forward steps, second wrap
|
||||||
|
double[] times =
|
||||||
|
{
|
||||||
|
65530.0,
|
||||||
|
65535.0,
|
||||||
|
2.0, // wrap 1
|
||||||
|
10.0,
|
||||||
|
100.0,
|
||||||
|
1000.0,
|
||||||
|
10000.0,
|
||||||
|
30000.0,
|
||||||
|
50000.0,
|
||||||
|
65534.0,
|
||||||
|
3.0, // wrap 2
|
||||||
|
20.0
|
||||||
|
};
|
||||||
|
|
||||||
|
double firstExt = double.NaN;
|
||||||
|
double lastExt = double.NaN;
|
||||||
|
|
||||||
|
for (int i = 0; i < times.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: 1.0,
|
||||||
|
overflowVolumeCm: 8.38860799804687,
|
||||||
|
timeS: times[i],
|
||||||
|
overflowTimeS: overflowTimeS);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
firstExt = telegram.TimestampExt;
|
||||||
|
|
||||||
|
if (i == times.Length - 1)
|
||||||
|
lastExt = telegram.TimestampExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
double start = times[0];
|
||||||
|
double end = times[times.Length - 1];
|
||||||
|
|
||||||
|
int wraps = 0;
|
||||||
|
for (int i = 1; i < times.Length; i++)
|
||||||
|
{
|
||||||
|
if (times[i] < times[i - 1])
|
||||||
|
wraps++;
|
||||||
|
}
|
||||||
|
|
||||||
|
double expectedDelta = wraps * overflowTimeS + end - start;
|
||||||
|
double actualDelta = lastExt - firstExt;
|
||||||
|
|
||||||
|
Assert.AreEqual(
|
||||||
|
expectedDelta,
|
||||||
|
actualDelta,
|
||||||
|
1e-6,
|
||||||
|
$"Timestamp delta mismatch. Wraps={wraps}, Expected={expectedDelta}, Actual={actualDelta}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_MultipleTimestampWrap_ShouldKeepIncreasingExtendedTimestamp()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
|
||||||
|
double overflowTimeS = 65536.0;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
double[] times =
|
||||||
|
{
|
||||||
|
65530.0,
|
||||||
|
65535.0,
|
||||||
|
2.0,
|
||||||
|
10.0,
|
||||||
|
100.0,
|
||||||
|
1000.0,
|
||||||
|
10000.0,
|
||||||
|
30000.0,
|
||||||
|
50000.0,
|
||||||
|
65534.0,
|
||||||
|
3.0,
|
||||||
|
20.0
|
||||||
|
};
|
||||||
|
|
||||||
|
double previousExt = double.NaN;
|
||||||
|
|
||||||
|
for (int i = 0; i < times.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: 1.0,
|
||||||
|
overflowVolumeCm: 8.38860799804687,
|
||||||
|
timeS: times[i],
|
||||||
|
overflowTimeS: overflowTimeS);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
if (!double.IsNaN(previousExt))
|
||||||
|
{
|
||||||
|
Assert.IsTrue(
|
||||||
|
telegram.TimestampExt >= previousExt,
|
||||||
|
$"Timestamp should not decrease at index {i}. Prev={previousExt}, Current={telegram.TimestampExt}");
|
||||||
|
}
|
||||||
|
|
||||||
|
previousExt = telegram.TimestampExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_MultipleVolumeRollover_ShouldProduceExpectedExtendedValues()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
double overflowVolumeCm = 8.38860799804687;
|
||||||
|
double overflowRaw = overflowVolumeCm * 1000.0;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
double[] samples =
|
||||||
|
{
|
||||||
|
7.5,
|
||||||
|
8.0,
|
||||||
|
0.2,
|
||||||
|
0.8,
|
||||||
|
1.4
|
||||||
|
};
|
||||||
|
|
||||||
|
double[] expectedExt =
|
||||||
|
{
|
||||||
|
7500.0,
|
||||||
|
8000.0,
|
||||||
|
200.0 + overflowRaw,
|
||||||
|
800.0 + overflowRaw,
|
||||||
|
1400.0 + overflowRaw
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: samples[i],
|
||||||
|
overflowVolumeCm: overflowVolumeCm,
|
||||||
|
timeS: i,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
Assert.AreEqual(samples[i] * 1000.0, telegram.VolumeRaw, 1e-9, $"Raw mismatch at index {i}");
|
||||||
|
Assert.AreEqual(expectedExt[i], telegram.VolumeRawExt, 1e-6, $"Mismatch at index {i}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateFromSmart_TwoVolumeRollovers_ShouldKeepExtendedVolumeIncreasing()
|
||||||
|
{
|
||||||
|
var telegram = new OptoTelegramRaw();
|
||||||
|
double overflowVolumeCm = 8.38860799804687;
|
||||||
|
double overflowRaw = overflowVolumeCm * 1000.0;
|
||||||
|
|
||||||
|
double lastVolumeExt = double.NaN;
|
||||||
|
double lastTimestampExt = double.NaN;
|
||||||
|
|
||||||
|
double[] samples =
|
||||||
|
{
|
||||||
|
6.8,
|
||||||
|
8.1,
|
||||||
|
0.3,
|
||||||
|
1.2,
|
||||||
|
2.1,
|
||||||
|
3.0,
|
||||||
|
4.0,
|
||||||
|
7.5,
|
||||||
|
8.1,
|
||||||
|
0.4,
|
||||||
|
1.1
|
||||||
|
};
|
||||||
|
|
||||||
|
double[] expectedExt =
|
||||||
|
{
|
||||||
|
6800.0,
|
||||||
|
8100.0,
|
||||||
|
overflowRaw + 300.0,
|
||||||
|
overflowRaw + 1200.0,
|
||||||
|
overflowRaw + 2100.0,
|
||||||
|
overflowRaw + 3000.0,
|
||||||
|
overflowRaw + 4000.0,
|
||||||
|
overflowRaw + 7500.0,
|
||||||
|
overflowRaw + 8100.0,
|
||||||
|
2.0 * overflowRaw + 400.0,
|
||||||
|
2.0 * overflowRaw + 1100.0
|
||||||
|
};
|
||||||
|
|
||||||
|
double previous = double.NaN;
|
||||||
|
|
||||||
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
{
|
||||||
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: samples[i],
|
||||||
|
overflowVolumeCm: overflowVolumeCm,
|
||||||
|
timeS: i,
|
||||||
|
overflowTimeS: 65536.0);
|
||||||
|
|
||||||
|
telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt);
|
||||||
|
|
||||||
|
Assert.AreEqual(samples[i] * 1000.0, telegram.VolumeRaw, 1e-9, $"Raw mismatch at index {i}");
|
||||||
|
Assert.AreEqual(expectedExt[i], telegram.VolumeRawExt, 1e-6, $"Mismatch at index {i}");
|
||||||
|
|
||||||
|
if (!double.IsNaN(previous))
|
||||||
|
{
|
||||||
|
Assert.IsTrue(
|
||||||
|
telegram.VolumeRawExt > previous,
|
||||||
|
$"Extended volume did not increase at index {i}. Prev={previous}, Current={telegram.VolumeRawExt}");
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = telegram.VolumeRawExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void UpdateFromSmart_WhenTimestampWraps_ShouldUnwrapForward()
|
public void UpdateFromSmart_WhenTimestampWraps_ShouldUnwrapForward()
|
||||||
{
|
{
|
||||||
var telegram = new OptoTelegramRaw();
|
var telegram = new OptoTelegramRaw();
|
||||||
double tsRange = StreamingDecoder.CpuTimeOverflowS;
|
double tsRange = StreamingDecoder.CpuTimeOverflowS;
|
||||||
|
|
||||||
var data = CreateCalibrationRecord(channel: 1, volumeCm: 1.0, timeS: 1.0);
|
var data = CreateCalibrationRecord(
|
||||||
|
channel: 1,
|
||||||
|
volumeCm: 1.0,
|
||||||
|
overflowVolumeCm: 8.38860799804687,
|
||||||
|
timeS: 1.0,
|
||||||
|
overflowTimeS: tsRange);
|
||||||
|
|
||||||
double previousExtendedVolume = 1000.0;
|
double previousExtendedVolume = 1000.0;
|
||||||
double previousExtendedTimestamp = tsRange - 0.25;
|
double previousExtendedTimestamp = tsRange - 0.25;
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
public int CloseCalls { get; private set; }
|
public int CloseCalls { get; private set; }
|
||||||
public int DiscardInCalls { get; private set; }
|
public int DiscardInCalls { get; private set; }
|
||||||
public int DiscardOutCalls { get; private set; }
|
public int DiscardOutCalls { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public Encoding Encoding { get; set; } = Encoding.ASCII;
|
public Encoding Encoding { get; set; } = Encoding.ASCII;
|
||||||
|
|
||||||
public int BytesToRead => _lines.Count > 0 ? 1 : 0;
|
public int BytesToRead => _isOpen && _lines.Count > 0 ? 1 : 0;
|
||||||
public int BytesToWrite => 0;
|
public int BytesToWrite => 0;
|
||||||
|
|
||||||
public void EnqueueLine(string line) => _lines.Enqueue(line);
|
public void EnqueueLine(string line) => _lines.Enqueue(line);
|
||||||
|
|||||||
@@ -0,0 +1,318 @@
|
|||||||
|
using System;
|
||||||
|
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;
|
||||||
|
using TBF.Rig.Sequences;
|
||||||
|
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||||
|
|
||||||
|
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class GenesisReaderTests
|
||||||
|
{
|
||||||
|
|
||||||
|
private static GenesisCfg CreateCfg()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
Assert.IsTrue(realInputLines.Length > 0, "No test input lines were provided.");
|
||||||
|
|
||||||
|
int processedCount = 0;
|
||||||
|
int firstValidIx = -1;
|
||||||
|
int lastValidIx = -1;
|
||||||
|
|
||||||
|
Console.WriteLine("=== BEGIN INPUT PARSING ===");
|
||||||
|
|
||||||
|
for (int i = 0; i < realInputLines.Length; i++)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
firstValidIx = processedCount;
|
||||||
|
|
||||||
|
lastValidIx = optoDataCount - 1;
|
||||||
|
processedCount = optoDataCount;
|
||||||
|
|
||||||
|
Console.WriteLine(
|
||||||
|
$"[{i}] ACCEPTED -> processedCount={processedCount}, firstValidIx={firstValidIx}, lastValidIx={lastValidIx}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[{i}] NOT ACCEPTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("--------------------------------------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
InvokePrivate(reader, "AddTestStartEndMarksToData", new object[] { 0, 0 });
|
||||||
|
InvokePrivate(reader, "DataStreamPostProcessing");
|
||||||
|
InvokePrivate(reader, "PrepareCalculatedChannelData");
|
||||||
|
|
||||||
|
Assert.IsTrue(reader.NoSamples,
|
||||||
|
"With only one telegram per channel, recalculated start/end samples should still be unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RealInput_ShouldParseRolloverInputLines()
|
||||||
|
{
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg());
|
||||||
|
InitializeReaderForTest(reader);
|
||||||
|
|
||||||
|
string[] realInputLines = LoadRealInputLinesWithRollover();
|
||||||
|
Assert.IsTrue(realInputLines.Length > 0, "No rollover input lines were provided.");
|
||||||
|
|
||||||
|
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 finalOptoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
SetPrivateField(reader, "volumeRawExtLast", new double[channelCount]);
|
||||||
|
SetPrivateField(reader, "timestampExtLast", new double[channelCount]);
|
||||||
|
|
||||||
|
SetPrivateField(reader, "lastTimestamp", new double[channelCount]);
|
||||||
|
SetPrivateField(reader, "timestampSec", Enumerable.Repeat(double.NaN, channelCount).ToArray());
|
||||||
|
SetPrivateField(reader, "timestampSec0", Enumerable.Repeat(double.NaN, channelCount).ToArray());
|
||||||
|
|
||||||
|
SetPrivateField(reader, "lastVolumeRaw", new double[channelCount]);
|
||||||
|
SetPrivateField(reader, "volumeLtr", Enumerable.Repeat(double.NaN, channelCount).ToArray());
|
||||||
|
SetPrivateField(reader, "volumeLtr0", Enumerable.Repeat(double.NaN, channelCount).ToArray());
|
||||||
|
|
||||||
|
var optoData = new OptoTelegramRaw[GenesisSmartReader.OptoDataBufferSize];
|
||||||
|
for (int i = 0; i < optoData.Length; i++)
|
||||||
|
optoData[i] = new OptoTelegramRaw();
|
||||||
|
|
||||||
|
SetPrivateField(reader, "optoData", optoData);
|
||||||
|
SetPrivateField(reader, "optoDataCount", 0);
|
||||||
|
SetPrivateField(reader, "toBeFlushed", new OptoTelegramRaw());
|
||||||
|
|
||||||
|
SetPrivateField(reader, "flowDirectionDetection", new FlowDirectionDetection());
|
||||||
|
SetPrivateField(reader, "dataStreamState", DataStreamState.ProcessAndSave);
|
||||||
|
SetPrivateField(reader, "synchronized", false);
|
||||||
|
SetPrivateField(reader, "synchronized2", false);
|
||||||
|
SetPrivateField(reader, "partOfTelegram", string.Empty);
|
||||||
|
SetPrivateField(reader, "startDataProcessing", true);
|
||||||
|
|
||||||
|
reader.StopQueueData = false;
|
||||||
|
|
||||||
|
reader.TestStartTelegramIx = 0;
|
||||||
|
reader.TestEndTelegramIx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] LoadRealInputLines()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
// 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",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] LoadRealInputLinesWithRollover()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
// 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",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T GetPrivateField<T>(object target, string fieldName)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Type type = target.GetType();
|
||||||
|
|
||||||
|
while (type != null)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Fail($"Method '{methodName}' not found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+176
-53
@@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Common;
|
using Common;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using TBF.Rig.Generic;
|
|
||||||
using TBF.Rig.RegisterReaders.GenesisRegReader;
|
using TBF.Rig.RegisterReaders.GenesisRegReader;
|
||||||
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
|
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
|
||||||
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||||
@@ -14,6 +13,12 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
{
|
{
|
||||||
private const int ChannelCount = 3;
|
private const int ChannelCount = 3;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void TestInitialize()
|
||||||
|
{
|
||||||
|
SetPrivateStaticField(typeof(GenesisSmartReader), "chenelsSwichCount", ChannelCount);
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetPrivateField(object target, string fieldName, object value)
|
private static void SetPrivateField(object target, string fieldName, object value)
|
||||||
{
|
{
|
||||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
@@ -32,13 +37,25 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
return (T)field.GetValue(target);
|
return (T)field.GetValue(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InvokePrivateMethod(object target, string methodName)
|
private static void SetPrivateStaticField(Type type, string fieldName, object value)
|
||||||
{
|
{
|
||||||
var method = target.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
|
var field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
if (method == null)
|
if (field == null)
|
||||||
throw new MissingMethodException(target.GetType().FullName, methodName);
|
throw new MissingFieldException(type.FullName, fieldName);
|
||||||
|
|
||||||
method.Invoke(target, null);
|
field.SetValue(null, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InvokePrepareCalculatedChannelData(GenesisSmartReader reader)
|
||||||
|
{
|
||||||
|
var method = typeof(GenesisSmartReader).GetMethod(
|
||||||
|
"PrepareCalculatedChannelData",
|
||||||
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
if (method == null)
|
||||||
|
throw new MissingMethodException(typeof(GenesisSmartReader).FullName, "PrepareCalculatedChannelData");
|
||||||
|
|
||||||
|
method.Invoke(reader, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt, int counter)
|
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt, int counter)
|
||||||
@@ -53,8 +70,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
DateTime = DateTime.Now
|
DateTime = DateTime.Now
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static GenesisCfg CreateCfg()
|
private static GenesisCfg CreateCfg()
|
||||||
{
|
{
|
||||||
var cfg = new GenesisCfg(null);
|
var cfg = new GenesisCfg(null);
|
||||||
@@ -75,21 +91,27 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void SimulatedInterleaved20x3ChannelStream_ShouldComputeStartAndEndVolumeAndTimeCorrectly()
|
|
||||||
{
|
|
||||||
var fake = new FakeSerialDriver();
|
|
||||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
|
||||||
|
|
||||||
SetPrivateField(reader, "volumeRawExtLast", new double[3]);
|
private static GenesisSmartReader CreateReaderWithOptoBuffer()
|
||||||
SetPrivateField(reader, "timestampExtLast", new double[3]);
|
{
|
||||||
SetPrivateField(reader, "flowDirectionDetection", new FlowDirectionDetection());
|
var reader = new GenesisSmartReader(CreateCfg(), null);
|
||||||
|
|
||||||
SetPrivateField(reader, "optoData", new OptoTelegramRaw[GenesisSmartReader.OptoDataBufferSize]);
|
SetPrivateField(reader, "optoData", new OptoTelegramRaw[GenesisSmartReader.OptoDataBufferSize]);
|
||||||
|
|
||||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
for (int i = 0; i < optoData.Length; i++)
|
for (int i = 0; i < optoData.Length; i++)
|
||||||
|
{
|
||||||
optoData[i] = new OptoTelegramRaw();
|
optoData[i] = new OptoTelegramRaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SimulatedInterleaved20x3ChannelStream_ShouldComputeRecalculatedStartAndEndVolumeAndTimeCorrectly()
|
||||||
|
{
|
||||||
|
var reader = CreateReaderWithOptoBuffer();
|
||||||
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int g = 0; g < 20; g++)
|
for (int g = 0; g < 20; g++)
|
||||||
@@ -108,66 +130,78 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
reader.TestStartTelegramIx = 2;
|
reader.TestStartTelegramIx = 2;
|
||||||
reader.TestEndTelegramIx = index - 1;
|
reader.TestEndTelegramIx = index - 1;
|
||||||
|
|
||||||
Assert.AreEqual(200.0, reader.VolumeLtrStart, 1e-9);
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
Assert.AreEqual(217.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(1.0, reader.TimestampSecStart, 1e-9);
|
||||||
Assert.AreEqual(18.0, reader.TimestampSecEnd, 1e-9);
|
Assert.AreEqual(20.0, reader.TimestampSecEnd, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
|
||||||
|
Assert.AreEqual(219.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void VolumeLtrEnd_ShouldIgnoreInvalidTrailingRecords_AndUsePreviousValidPerChannelSamples()
|
public void VolumeLtrEnd_ShouldRecalculateShorterChannelToLongestChannelTimeSpan()
|
||||||
{
|
{
|
||||||
var reader = new GenesisSmartReader(CreateCfg(), null);
|
var reader = CreateReaderWithOptoBuffer();
|
||||||
|
|
||||||
SetPrivateField(reader, "optoData", new OptoTelegramRaw[GenesisSmartReader.OptoDataBufferSize]);
|
|
||||||
|
|
||||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
for (int i = 0; i < optoData.Length; i++)
|
|
||||||
optoData[i] = new OptoTelegramRaw();
|
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
// Build 10 groups of valid 3-channel data
|
|
||||||
for (int g = 0; g < 10; g++)
|
for (int g = 0; g < 10; g++)
|
||||||
{
|
{
|
||||||
optoData[index++] = CreateOptoRecord(0, 100 + g, 1 + g, index);
|
optoData[index] = CreateOptoRecord(0, 100 + g, 1 + g, index);
|
||||||
optoData[index++] = CreateOptoRecord(1, 200 + g, 1 + g, index);
|
index++;
|
||||||
optoData[index++] = CreateOptoRecord(2, 300 + g, 1 + g, index);
|
|
||||||
|
optoData[index] = CreateOptoRecord(1, 200 + g, 1 + g, index);
|
||||||
|
index++;
|
||||||
|
|
||||||
|
optoData[index] = CreateOptoRecord(2, 300 + g, 1 + g, index);
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Corrupt the last two channel-1 records
|
optoData[25].Flags = OptoTelegramFlags.InvalidTelegram;
|
||||||
optoData[25].Flags = OptoTelegramFlags.InvalidTelegram; // group 8, channel 1
|
optoData[28].Flags = OptoTelegramFlags.InvalidTelegram;
|
||||||
optoData[28].Flags = OptoTelegramFlags.InvalidTelegram; // group 9, channel 1
|
|
||||||
|
|
||||||
SetPrivateField(reader, "optoDataCount", index);
|
SetPrivateField(reader, "optoDataCount", index);
|
||||||
reader.TestStartTelegramIx = 2;
|
reader.TestStartTelegramIx = 2;
|
||||||
reader.TestEndTelegramIx = index - 1;
|
reader.TestEndTelegramIx = index - 1;
|
||||||
|
|
||||||
// Start still comes from first full valid 3-channel snapshot:
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
// (100 + 200 + 300) / 3 = 200
|
|
||||||
Assert.AreEqual(200.0, reader.VolumeLtrStart, 1e-9);
|
|
||||||
|
|
||||||
// End with last 5 valid per channel:
|
Assert.AreEqual(200.666666666667, reader.VolumeLtrStart, 1e-9);
|
||||||
// ch0 valid last 5: 105,106,107,108,109 => avg 107
|
Assert.AreEqual(209.666666666667, reader.VolumeLtrEnd, 1e-9);
|
||||||
// ch1 valid last 5: 203,204,205,206,207 => avg 205
|
Assert.AreEqual(209.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
|
||||||
// because 208 and 209 were invalid
|
|
||||||
// ch2 valid last 5: 305,306,307,308,309 => avg 307
|
Assert.AreEqual(101.0, reader.VolumeLtrStartCh1, 1e-9);
|
||||||
// total avg = (107 + 205 + 307) / 3 = 206.3333333333...
|
Assert.AreEqual(201.0, reader.VolumeLtrStartCh2, 1e-9);
|
||||||
Assert.AreEqual(206.33333333333334, reader.VolumeLtrEnd, 1e-9);
|
Assert.AreEqual(300.0, reader.VolumeLtrStartCh3, 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);
|
||||||
|
Assert.AreEqual(10.0, reader.TimestampSecEnd, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(1.0, reader.TimestampSecStartCh1, 1e-9);
|
||||||
|
Assert.AreEqual(1.0, reader.TimestampSecStartCh2, 1e-9);
|
||||||
|
Assert.AreEqual(1.0, reader.TimestampSecStartCh3, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(10.0, reader.TimestampSecEndCh1, 1e-9);
|
||||||
|
Assert.AreEqual(10.0, reader.TimestampSecEndCh2, 1e-9);
|
||||||
|
Assert.AreEqual(10.0, reader.TimestampSecEndCh3, 1e-9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void VolumeLtrStart_And_End_ShouldBeZero_WhenAllSamplesAreInvalid()
|
public void VolumeLtrStart_And_End_ShouldBeZero_WhenAllSamplesAreInvalid()
|
||||||
{
|
{
|
||||||
var reader = new GenesisSmartReader(CreateCfg(), null);
|
var reader = CreateReaderWithOptoBuffer();
|
||||||
|
|
||||||
SetPrivateField(reader, "optoData", new OptoTelegramRaw[GenesisSmartReader.OptoDataBufferSize]);
|
|
||||||
|
|
||||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
for (int i = 0; i < optoData.Length; i++)
|
|
||||||
optoData[i] = new OptoTelegramRaw();
|
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++)
|
for (int i = 0; i < 9; i++)
|
||||||
{
|
{
|
||||||
@@ -184,8 +218,97 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
reader.TestStartTelegramIx = 2;
|
reader.TestStartTelegramIx = 2;
|
||||||
reader.TestEndTelegramIx = 8;
|
reader.TestEndTelegramIx = 8;
|
||||||
|
|
||||||
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
|
|
||||||
Assert.AreEqual(0.0, reader.VolumeLtrStart, 1e-9);
|
Assert.AreEqual(0.0, reader.VolumeLtrStart, 1e-9);
|
||||||
Assert.AreEqual(0.0, reader.VolumeLtrEnd, 1e-9);
|
Assert.AreEqual(0.0, reader.VolumeLtrEnd, 1e-9);
|
||||||
|
Assert.AreEqual(0.0, reader.TimestampSecStart, 1e-9);
|
||||||
|
Assert.AreEqual(0.0, reader.TimestampSecEnd, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SimulatedInterleaved20x3ChannelStream_ShouldComputePerChannelStartAndEndValues()
|
||||||
|
{
|
||||||
|
var reader = CreateReaderWithOptoBuffer();
|
||||||
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (int g = 0; g < 20; g++)
|
||||||
|
{
|
||||||
|
optoData[index] = CreateOptoRecord(0, 100 + g, 1 + g, index);
|
||||||
|
index++;
|
||||||
|
|
||||||
|
optoData[index] = CreateOptoRecord(1, 200 + g, 1 + g, index);
|
||||||
|
index++;
|
||||||
|
|
||||||
|
optoData[index] = CreateOptoRecord(2, 300 + g, 1 + g, index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPrivateField(reader, "optoDataCount", index);
|
||||||
|
reader.TestStartTelegramIx = 2;
|
||||||
|
reader.TestEndTelegramIx = index - 1;
|
||||||
|
|
||||||
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
|
|
||||||
|
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(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);
|
||||||
|
Assert.AreEqual(1.0, reader.TimestampSecStartCh2, 1e-9);
|
||||||
|
Assert.AreEqual(1.0, reader.TimestampSecStartCh3, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(20.0, reader.TimestampSecEndCh1, 1e-9);
|
||||||
|
Assert.AreEqual(20.0, reader.TimestampSecEndCh2, 1e-9);
|
||||||
|
Assert.AreEqual(20.0, reader.TimestampSecEndCh3, 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.666666666667, reader.VolumeLtrStartAverage, 1e-9);
|
||||||
|
Assert.AreEqual(219.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VolumeLtrEnd_ShouldAverageOnlyAvailableChannels()
|
||||||
|
{
|
||||||
|
var reader = CreateReaderWithOptoBuffer();
|
||||||
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
optoData[idx++] = CreateOptoRecord(0, 10 + i, 100 + i, idx);
|
||||||
|
optoData[idx++] = CreateOptoRecord(1, 20 + i, 100 + i, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPrivateField(reader, "optoDataCount", idx);
|
||||||
|
reader.TestStartTelegramIx = 1;
|
||||||
|
reader.TestEndTelegramIx = idx - 1;
|
||||||
|
|
||||||
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
|
|
||||||
|
Assert.AreEqual(15.5, reader.VolumeLtrStart, 1e-9);
|
||||||
|
Assert.AreEqual(19.5, reader.VolumeLtrEnd, 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(15.0, reader.VolumeLtrEndCh1, 1e-9);
|
||||||
|
Assert.AreEqual(24.0, reader.VolumeLtrEndCh2, 1e-9);
|
||||||
|
Assert.AreEqual(0.0, reader.VolumeLtrEndCh3, 1e-9);
|
||||||
|
|
||||||
|
Assert.AreEqual(100.0, reader.TimestampSecStart, 1e-9);
|
||||||
|
Assert.AreEqual(104.0, reader.TimestampSecEnd, 1e-9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+511
@@ -0,0 +1,511 @@
|
|||||||
|
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 GenesisSmartReaderChannelTests
|
||||||
|
{
|
||||||
|
private GenesisSmartReader _reader;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_reader = new GenesisSmartReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OptoTelegramRaw Rec(
|
||||||
|
int channel,
|
||||||
|
double time,
|
||||||
|
double volume,
|
||||||
|
OptoTelegramFlags flags = OptoTelegramFlags.OK)
|
||||||
|
{
|
||||||
|
return new OptoTelegramRaw
|
||||||
|
{
|
||||||
|
iChannel = channel,
|
||||||
|
TimestampExt = time,
|
||||||
|
VolumeRawExt = volume,
|
||||||
|
Flags = flags
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private object InvokePrivate(string methodName, params object[] args)
|
||||||
|
{
|
||||||
|
var mi = typeof(GenesisSmartReader).GetMethod(
|
||||||
|
methodName,
|
||||||
|
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
Assert.IsNotNull(mi, $"Method '{methodName}' was not found.");
|
||||||
|
|
||||||
|
return mi.Invoke(_reader, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T GetPrivateField<T>(object instance, string fieldName)
|
||||||
|
{
|
||||||
|
var fi = instance.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
Assert.IsNotNull(fi, $"Field '{fieldName}' was not found.");
|
||||||
|
return (T)fi.GetValue(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetPrivateField(object instance, string fieldName, object value)
|
||||||
|
{
|
||||||
|
var fi = instance.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
Assert.IsNotNull(fi, $"Field '{fieldName}' was not found.");
|
||||||
|
fi.SetValue(instance, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GroupRecordsPerChannel_Groups_Valid_Records_By_Channel()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
Rec(0, 13, 110),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
Rec(2, 15, 330),
|
||||||
|
};
|
||||||
|
|
||||||
|
var grouped = (OptoTelegramRaw[][])InvokePrivate(
|
||||||
|
"GroupRecordsPerChannel",
|
||||||
|
(object)input, 0, input.Length - 1, input.Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(3, grouped.Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, grouped[0].Length);
|
||||||
|
Assert.AreEqual(2, grouped[1].Length);
|
||||||
|
Assert.AreEqual(2, grouped[2].Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(100, grouped[0][0].VolumeRawExt);
|
||||||
|
Assert.AreEqual(110, grouped[0][1].VolumeRawExt);
|
||||||
|
|
||||||
|
Assert.AreEqual(200, grouped[1][0].VolumeRawExt);
|
||||||
|
Assert.AreEqual(220, grouped[1][1].VolumeRawExt);
|
||||||
|
|
||||||
|
Assert.AreEqual(300, grouped[2][0].VolumeRawExt);
|
||||||
|
Assert.AreEqual(330, grouped[2][1].VolumeRawExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GroupRecordsPerChannel_Ignores_Invalid_Records()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100, OptoTelegramFlags.OK),
|
||||||
|
Rec(1, 11, 200, OptoTelegramFlags.InvalidTelegram),
|
||||||
|
Rec(2, 12, 300, OptoTelegramFlags.OK),
|
||||||
|
Rec(0, 13, 110, OptoTelegramFlags.SyncError),
|
||||||
|
Rec(1, 14, 220, OptoTelegramFlags.OK),
|
||||||
|
};
|
||||||
|
|
||||||
|
var grouped = (OptoTelegramRaw[][])InvokePrivate(
|
||||||
|
"GroupRecordsPerChannel",
|
||||||
|
(object)input, 0, input.Length - 1, input.Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, grouped[0].Length);
|
||||||
|
Assert.AreEqual(1, grouped[1].Length);
|
||||||
|
Assert.AreEqual(1, grouped[2].Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(100, grouped[0][0].VolumeRawExt);
|
||||||
|
Assert.AreEqual(220, grouped[1][0].VolumeRawExt);
|
||||||
|
Assert.AreEqual(300, grouped[2][0].VolumeRawExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GroupRecordsPerChannel_Swaps_Start_And_End_When_Reversed()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(0, 12, 120),
|
||||||
|
};
|
||||||
|
|
||||||
|
var grouped = (OptoTelegramRaw[][])InvokePrivate(
|
||||||
|
"GroupRecordsPerChannel",
|
||||||
|
(object)input, 2, 0, input.Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, grouped[0].Length);
|
||||||
|
Assert.AreEqual(1, grouped[1].Length);
|
||||||
|
Assert.AreEqual(0, grouped[2].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GroupRecordsPerChannel_Returns_Empty_For_Invalid_Range()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
};
|
||||||
|
|
||||||
|
var grouped = (OptoTelegramRaw[][])InvokePrivate(
|
||||||
|
"GroupRecordsPerChannel",
|
||||||
|
(object)input, -1, 1, input.Length);
|
||||||
|
|
||||||
|
Assert.AreEqual(3, grouped.Length);
|
||||||
|
Assert.IsTrue(grouped.All(x => x.Length == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TimeDeltaPerChannel_Computes_First_Last_Deltas()
|
||||||
|
{
|
||||||
|
var grouped = new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(0, 18, 170),
|
||||||
|
Rec(0, 15, 120)
|
||||||
|
},
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
Rec(1, 20, 500),
|
||||||
|
Rec(1, 23, 530)
|
||||||
|
},
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
Rec(2, 30, 900)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (ValueTuple<int, double?, double?>[])InvokePrivate(
|
||||||
|
"TimeDeltaPerChannel",
|
||||||
|
(object)grouped);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, result[0].Item1);
|
||||||
|
Assert.AreEqual(5, result[0].Item2);
|
||||||
|
Assert.AreEqual(20, result[0].Item3);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, result[1].Item1);
|
||||||
|
Assert.AreEqual(3, result[1].Item2);
|
||||||
|
Assert.AreEqual(30, result[1].Item3);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, result[2].Item1);
|
||||||
|
Assert.IsNull(result[2].Item2);
|
||||||
|
Assert.IsNull(result[2].Item3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VolumeStartPerChannel_Returns_Last_Seen_Value_Backward_From_Index()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(0, 12, 120),
|
||||||
|
Rec(2, 13, 300),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (double?[])InvokePrivate(
|
||||||
|
"VolumeStartPerChannel",
|
||||||
|
(object)input, input.Length, 4);
|
||||||
|
|
||||||
|
Assert.AreEqual(120, result[0]);
|
||||||
|
Assert.AreEqual(220, result[1]);
|
||||||
|
Assert.AreEqual(300, result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TimeStartPerChannel_Returns_Last_Seen_Time_Backward_From_Index()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(0, 12, 120),
|
||||||
|
Rec(2, 13, 300),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (double?[])InvokePrivate(
|
||||||
|
"TimeStartPerChannel",
|
||||||
|
(object)input, input.Length, 4);
|
||||||
|
|
||||||
|
Assert.AreEqual(12, result[0]);
|
||||||
|
Assert.AreEqual(14, result[1]);
|
||||||
|
Assert.AreEqual(13, result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VolumeEndPerChannel_Averages_Last_N_Samples_Per_Channel()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
Rec(0, 13, 120),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
Rec(2, 15, 330),
|
||||||
|
Rec(0, 16, 140),
|
||||||
|
Rec(1, 17, 240),
|
||||||
|
Rec(2, 18, 360),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (double?[])InvokePrivate(
|
||||||
|
"VolumeEndPerChannel",
|
||||||
|
(object)input, input.Length, 8, 2);
|
||||||
|
|
||||||
|
Assert.AreEqual((140 + 120) / 2.0, result[0]);
|
||||||
|
Assert.AreEqual((240 + 220) / 2.0, result[1]);
|
||||||
|
Assert.AreEqual((360 + 330) / 2.0, result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TimeEndPerChannel_Averages_Last_N_Samples_Per_Channel()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
Rec(0, 13, 120),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
Rec(2, 15, 330),
|
||||||
|
Rec(0, 16, 140),
|
||||||
|
Rec(1, 17, 240),
|
||||||
|
Rec(2, 18, 360),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (double?[])InvokePrivate(
|
||||||
|
"TimeEndPerChannel",
|
||||||
|
(object)input, input.Length, 8, 2);
|
||||||
|
|
||||||
|
Assert.AreEqual((16 + 13) / 2.0, result[0]);
|
||||||
|
Assert.AreEqual((17 + 14) / 2.0, result[1]);
|
||||||
|
Assert.AreEqual((18 + 15) / 2.0, result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void VolumeStartPerChannel_Returns_All_Nulls_For_OutOfRange_Index()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (double?[])InvokePrivate(
|
||||||
|
"VolumeStartPerChannel",
|
||||||
|
(object)input, input.Length, -1);
|
||||||
|
|
||||||
|
Assert.IsNull(result[0]);
|
||||||
|
Assert.IsNull(result[1]);
|
||||||
|
Assert.IsNull(result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TimeEndPerChannel_Uses_One_Sample_When_SamplesPerChannel_Is_Zero()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
Rec(0, 13, 120),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
Rec(2, 15, 330),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (double?[])InvokePrivate(
|
||||||
|
"TimeEndPerChannel",
|
||||||
|
(object)input, input.Length, 5, 0);
|
||||||
|
|
||||||
|
Assert.AreEqual(13, result[0]);
|
||||||
|
Assert.AreEqual(14, result[1]);
|
||||||
|
Assert.AreEqual(15, result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Precreated_OptoData_Private_Methods_Read_Correct_Values()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
Rec(0, 13, 120),
|
||||||
|
Rec(1, 14, 220),
|
||||||
|
Rec(2, 15, 330),
|
||||||
|
Rec(0, 16, 140),
|
||||||
|
Rec(1, 17, 240),
|
||||||
|
Rec(2, 18, 360),
|
||||||
|
};
|
||||||
|
|
||||||
|
SetPrivateField(_reader, "optoData", input);
|
||||||
|
SetPrivateField(_reader, "optoDataCount", input.Length);
|
||||||
|
|
||||||
|
_reader.TestStartTelegramIx = 5;
|
||||||
|
_reader.TestEndTelegramIx = 8;
|
||||||
|
|
||||||
|
Assert.AreEqual(input.Length, GetPrivateField<int>(_reader, "optoDataCount"));
|
||||||
|
|
||||||
|
var startVolumes = (double?[])InvokePrivate(
|
||||||
|
"VolumeStartPerChannel",
|
||||||
|
(object)input, input.Length, 5);
|
||||||
|
|
||||||
|
var endVolumes = (double?[])InvokePrivate(
|
||||||
|
"VolumeEndPerChannel",
|
||||||
|
(object)input, input.Length, 8, 2 * GenesisSmartReader.StartEndFilterSamplesCount2 + 1);
|
||||||
|
|
||||||
|
var startTimes = (double?[])InvokePrivate(
|
||||||
|
"TimeStartPerChannel",
|
||||||
|
(object)input, input.Length, 5);
|
||||||
|
|
||||||
|
var endTimes = (double?[])InvokePrivate(
|
||||||
|
"TimeEndPerChannel",
|
||||||
|
(object)input, input.Length, 8, 2 * GenesisSmartReader.StartEndFilterSamplesCount2 + 1);
|
||||||
|
|
||||||
|
Assert.AreEqual(120, startVolumes[0]);
|
||||||
|
Assert.AreEqual(220, startVolumes[1]);
|
||||||
|
Assert.AreEqual(330, startVolumes[2]);
|
||||||
|
|
||||||
|
Assert.AreEqual(13, startTimes[0]);
|
||||||
|
Assert.AreEqual(14, startTimes[1]);
|
||||||
|
Assert.AreEqual(15, startTimes[2]);
|
||||||
|
|
||||||
|
Assert.AreEqual((140 + 120 + 100) / 3.0, endVolumes[0]);
|
||||||
|
Assert.AreEqual((240 + 220 + 200) / 3.0, endVolumes[1]);
|
||||||
|
Assert.AreEqual((360 + 330 + 300) / 3.0, endVolumes[2]);
|
||||||
|
|
||||||
|
Assert.AreEqual((16 + 13 + 10) / 3.0, endTimes[0]);
|
||||||
|
Assert.AreEqual((17 + 14 + 11) / 3.0, endTimes[1]);
|
||||||
|
Assert.AreEqual((18 + 15 + 12) / 3.0, endTimes[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Public_Channel_Properties_Default_To_Zero_When_NoSamples_Is_True()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 11, 200),
|
||||||
|
Rec(2, 12, 300),
|
||||||
|
};
|
||||||
|
|
||||||
|
SetPrivateField(_reader, "optoData", input);
|
||||||
|
SetPrivateField(_reader, "optoDataCount", input.Length);
|
||||||
|
|
||||||
|
_reader.TestStartTelegramIx = 5;
|
||||||
|
_reader.TestEndTelegramIx = 8;
|
||||||
|
|
||||||
|
Assert.IsTrue(_reader.NoSamples);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, _reader.VolumeLtrStartCh1);
|
||||||
|
Assert.AreEqual(0, _reader.VolumeLtrStartCh2);
|
||||||
|
Assert.AreEqual(0, _reader.VolumeLtrStartCh3);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, _reader.VolumeLtrEndCh1);
|
||||||
|
Assert.AreEqual(0, _reader.VolumeLtrEndCh2);
|
||||||
|
Assert.AreEqual(0, _reader.VolumeLtrEndCh3);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, _reader.TimestampSecStartCh1);
|
||||||
|
Assert.AreEqual(0, _reader.TimestampSecStartCh2);
|
||||||
|
Assert.AreEqual(0, _reader.TimestampSecStartCh3);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, _reader.TimestampSecEndCh1);
|
||||||
|
Assert.AreEqual(0, _reader.TimestampSecEndCh2);
|
||||||
|
Assert.AreEqual(0, _reader.TimestampSecEndCh3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Copy_Should_Copy_From_Source_Record()
|
||||||
|
{
|
||||||
|
var source = Rec(2, 123.5, 456.7, OptoTelegramFlags.OK_TestEnd);
|
||||||
|
source.Counter = 77;
|
||||||
|
source.RefFlow = 9.5f;
|
||||||
|
source.FlowRaw = 111;
|
||||||
|
source.VolumeRaw = 222;
|
||||||
|
source.Impedance = 333;
|
||||||
|
source.CheckSum = 44;
|
||||||
|
|
||||||
|
var target = new OptoTelegramRaw();
|
||||||
|
target.Copy(source);
|
||||||
|
|
||||||
|
Assert.AreEqual(source.iChannel, target.iChannel);
|
||||||
|
Assert.AreEqual(source.TimestampExt, target.TimestampExt);
|
||||||
|
Assert.AreEqual(source.VolumeRawExt, target.VolumeRawExt);
|
||||||
|
Assert.AreEqual(source.Flags, target.Flags);
|
||||||
|
Assert.AreEqual(source.Counter, target.Counter);
|
||||||
|
Assert.AreEqual(source.RefFlow, target.RefFlow);
|
||||||
|
Assert.AreEqual(source.FlowRaw, target.FlowRaw);
|
||||||
|
Assert.AreEqual(source.VolumeRaw, target.VolumeRaw);
|
||||||
|
Assert.AreEqual(source.Impedance, target.Impedance);
|
||||||
|
Assert.AreEqual(source.CheckSum, target.CheckSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RecalculateVolumeAndTimeDeltaPerChannel_Returns_Recalculated_Output()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(0, 20, 200),
|
||||||
|
|
||||||
|
Rec(1, 10, 500),
|
||||||
|
Rec(1, 30, 560),
|
||||||
|
|
||||||
|
Rec(2, 10, 1000),
|
||||||
|
Rec(2, 15, 1050),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (OptoTelegramRaw[][])InvokePrivate(
|
||||||
|
"RecalculateVolumeAndTimeDeltaPerChannel",
|
||||||
|
(object)input,
|
||||||
|
input.Length,
|
||||||
|
0,
|
||||||
|
input.Length - 1);
|
||||||
|
|
||||||
|
Assert.IsNotNull(result);
|
||||||
|
Assert.AreEqual(3, result.Length);
|
||||||
|
|
||||||
|
for (int ch = 0; ch < 3; ch++)
|
||||||
|
{
|
||||||
|
Assert.IsNotNull(result[ch]);
|
||||||
|
Assert.AreEqual(2, result[ch].Length);
|
||||||
|
Assert.IsNotNull(result[ch][0]);
|
||||||
|
Assert.IsNotNull(result[ch][1]);
|
||||||
|
|
||||||
|
Assert.AreEqual(10, result[ch][0].TimestampExt, 0.0001);
|
||||||
|
Assert.AreEqual(30, result[ch][1].TimestampExt, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(100, result[0][0].VolumeRawExt, 0.0001);
|
||||||
|
Assert.AreEqual(300, result[0][1].VolumeRawExt, 0.0001);
|
||||||
|
|
||||||
|
Assert.AreEqual(500, result[1][0].VolumeRawExt, 0.0001);
|
||||||
|
Assert.AreEqual(560, result[1][1].VolumeRawExt, 0.0001);
|
||||||
|
|
||||||
|
Assert.AreEqual(1000, result[2][0].VolumeRawExt, 0.0001);
|
||||||
|
Assert.AreEqual(1200, result[2][1].VolumeRawExt, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RecalculateVolumeAndTimeDeltaPerChannel_Returns_Null_When_No_Channel_Has_Two_Records()
|
||||||
|
{
|
||||||
|
var input = new[]
|
||||||
|
{
|
||||||
|
Rec(0, 10, 100),
|
||||||
|
Rec(1, 20, 200),
|
||||||
|
Rec(2, 30, 300),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = (OptoTelegramRaw[][])InvokePrivate(
|
||||||
|
"RecalculateVolumeAndTimeDeltaPerChannel",
|
||||||
|
(object)input,
|
||||||
|
input.Length,
|
||||||
|
0,
|
||||||
|
input.Length - 1);
|
||||||
|
|
||||||
|
Assert.IsNull(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+163
@@ -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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+515
-87
@@ -1,5 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Common;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using TBF.Rig;
|
using TBF.Rig;
|
||||||
@@ -39,6 +45,18 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
return (T)field.GetValue(target);
|
return (T)field.GetValue(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void InvokePrepareCalculatedChannelData(GenesisSmartReader reader)
|
||||||
|
{
|
||||||
|
var method = typeof(GenesisSmartReader).GetMethod(
|
||||||
|
"PrepareCalculatedChannelData",
|
||||||
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
if (method == null)
|
||||||
|
throw new MissingMethodException(typeof(GenesisSmartReader).FullName, "PrepareCalculatedChannelData");
|
||||||
|
|
||||||
|
method.Invoke(reader, null);
|
||||||
|
}
|
||||||
|
|
||||||
private static void InitializeThreeChannelState(GenesisSmartReader reader)
|
private static void InitializeThreeChannelState(GenesisSmartReader reader)
|
||||||
{
|
{
|
||||||
SetPrivateField(reader, "volumeRawExtLast", new double[ChannelCount]);
|
SetPrivateField(reader, "volumeRawExtLast", new double[ChannelCount]);
|
||||||
@@ -53,6 +71,22 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
SetPrivateField(reader, "timestampSec", new[] { 0.0, 0.0, 0.0 });
|
SetPrivateField(reader, "timestampSec", new[] { 0.0, 0.0, 0.0 });
|
||||||
SetPrivateField(reader, "timestampSec0", 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]
|
[TestMethod]
|
||||||
public void Start_ShouldOpenPort_AndEnableProcessing()
|
public void Start_ShouldOpenPort_AndEnableProcessing()
|
||||||
@@ -65,7 +99,8 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
Assert.IsTrue(fake.IsOpen);
|
Assert.IsTrue(fake.IsOpen);
|
||||||
Assert.IsTrue(fake.OpenCalls >= 1);
|
Assert.IsTrue(fake.OpenCalls >= 1);
|
||||||
Assert.AreEqual(1, fake.DiscardInCalls);
|
Assert.AreEqual(2, fake.DiscardInCalls);
|
||||||
|
Assert.AreEqual(2, fake.DiscardOutCalls);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@@ -79,11 +114,37 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
Assert.IsTrue(fake.IsOpen);
|
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();
|
reader.Stop();
|
||||||
|
WaitForStopToFinish(reader);
|
||||||
|
|
||||||
Assert.IsFalse(fake.IsOpen);
|
Assert.IsFalse(fake.IsOpen);
|
||||||
Assert.AreEqual(2, fake.CloseCalls);
|
Assert.IsTrue(fake.CloseCalls >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Run_ShouldCaptureStartTelegramIndex_WhenTimeReached()
|
public void Run_ShouldCaptureStartTelegramIndex_WhenTimeReached()
|
||||||
@@ -105,36 +166,42 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ProcessOptoLine_ShouldIncreaseOptoDataCount()
|
public void ProcessOptoLine_ShouldInsertMultipleTelegrams_WithCorrectChannels()
|
||||||
{
|
{
|
||||||
var fake = new FakeSerialDriver();
|
var fake = new FakeSerialDriver();
|
||||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
|
||||||
|
|
||||||
reader.Initialize();
|
|
||||||
InitializeThreeChannelState(reader);
|
|
||||||
|
|
||||||
var line =
|
|
||||||
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331";
|
|
||||||
|
|
||||||
reader.optoSerialPort = fake;
|
|
||||||
fake.Open();
|
fake.Open();
|
||||||
|
|
||||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
reader.optoSerialPort = fake;
|
||||||
|
|
||||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
InitializeThreeChannelState(reader);
|
||||||
Assert.AreEqual(1, optoDataCount);
|
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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", DataStreamState.ProcessAndSave, out reset);
|
||||||
|
Assert.IsFalse(reset);
|
||||||
|
|
||||||
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
|
var optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||||
|
|
||||||
|
Assert.AreEqual(3, optoDataCount);
|
||||||
|
Assert.AreEqual(0, optoData[0].IChannel());
|
||||||
|
Assert.AreEqual(1, optoData[1].IChannel());
|
||||||
|
Assert.AreEqual(2, optoData[2].IChannel());
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataTestMethod]
|
[DataTestMethod]
|
||||||
[DataRow(
|
[DataRow("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", 0)]
|
||||||
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
[DataRow("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", 1)]
|
||||||
0)]
|
[DataRow("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", 2)]
|
||||||
[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_ShouldUpdateExpectedChannel(string line, int expectedChannelIndex)
|
public void ProcessOptoLine_ShouldUpdateExpectedChannel(string line, int expectedChannelIndex)
|
||||||
{
|
{
|
||||||
var fake = new FakeSerialDriver();
|
var fake = new FakeSerialDriver();
|
||||||
@@ -145,8 +212,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
reader.optoSerialPort = fake;
|
reader.optoSerialPort = fake;
|
||||||
InitializeThreeChannelState(reader);
|
InitializeThreeChannelState(reader);
|
||||||
|
EnableProcessingLoopForTests(reader);
|
||||||
|
|
||||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
|
||||||
|
|
||||||
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
|
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
|
||||||
var timestampExtLast = GetPrivateField<double[]>(reader, "timestampExtLast");
|
var timestampExtLast = GetPrivateField<double[]>(reader, "timestampExtLast");
|
||||||
@@ -185,7 +253,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
var ev = reader.Run();
|
var ev = reader.Run();
|
||||||
|
|
||||||
Assert.AreEqual(Event.ReadRegisterDone, ev);
|
Assert.AreEqual(Event.ReadRegisterDone, ev);
|
||||||
Assert.AreEqual(4.0, reader.WMVolume, 1E-6); // average of (3, 4, 5)
|
Assert.AreEqual(4.0, reader.WMVolume, 1E-6);
|
||||||
Assert.AreEqual(4000, reader.WMPulses);
|
Assert.AreEqual(4000, reader.WMPulses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,20 +268,27 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
reader.optoSerialPort = fake;
|
reader.optoSerialPort = fake;
|
||||||
InitializeThreeChannelState(reader);
|
InitializeThreeChannelState(reader);
|
||||||
|
EnableProcessingLoopForTests(reader);
|
||||||
|
|
||||||
var line =
|
var line =
|
||||||
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD";
|
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD";
|
||||||
|
|
||||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
|
||||||
|
|
||||||
int currentTelegramIx = GetPrivateField<int>(reader, "currentTelegramIx");
|
int currentTelegramIx = GetPrivateField<int>(reader, "currentTelegramIx");
|
||||||
Assert.AreEqual(0, currentTelegramIx);
|
Assert.AreEqual(0, currentTelegramIx);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataTestMethod]
|
[DataTestMethod]
|
||||||
[DataRow( "@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", 0)]
|
[DataRow(
|
||||||
[DataRow( "@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", 1)]
|
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
|
||||||
[DataRow( "@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", 2)]
|
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)
|
public void ProcessOptoLine_ShouldInsertTelegramAndUpdateExpectedChannel(string line, int expectedChannelIndex)
|
||||||
{
|
{
|
||||||
var fake = new FakeSerialDriver();
|
var fake = new FakeSerialDriver();
|
||||||
@@ -223,34 +298,35 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
reader.Initialize();
|
reader.Initialize();
|
||||||
reader.optoSerialPort = fake;
|
reader.optoSerialPort = fake;
|
||||||
|
|
||||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
InitializeThreeChannelState(reader);
|
||||||
|
EnableProcessingLoopForTests(reader);
|
||||||
|
|
||||||
|
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
|
||||||
|
|
||||||
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
|
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
|
||||||
var timestampExtLast = GetPrivateField<double[]>(reader, "timestampExtLast");
|
var timestampExtLast = GetPrivateField<double[]>(reader, "timestampExtLast");
|
||||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
var optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
var optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||||
|
|
||||||
Assert.AreEqual(1, optoDataCount, "Exactly one telegram should be inserted.");
|
Assert.AreEqual(1, optoDataCount);
|
||||||
|
|
||||||
var inserted = optoData[0];
|
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(expectedChannelIndex, inserted.IChannel());
|
||||||
Assert.AreEqual(0, inserted.Counter, "First inserted telegram should have counter 0.");
|
Assert.AreEqual(0, inserted.Counter);
|
||||||
Assert.AreEqual(OptoTelegramFlags.OK, inserted.Flags, "Inserted telegram should be marked OK.");
|
Assert.AreEqual(OptoTelegramFlags.OK, inserted.Flags);
|
||||||
Assert.AreNotEqual(default(DateTime), inserted.DateTime, "Inserted telegram DateTime should be initialized.");
|
|
||||||
|
|
||||||
Assert.AreNotEqual(0.0, inserted.VolumeRaw, "Inserted telegram VolumeRaw should be set.");
|
Assert.AreNotEqual(0.0, inserted.VolumeRawExt);
|
||||||
Assert.AreNotEqual(0.0, inserted.VolumeRawExt, "Inserted telegram VolumeRawExt should be set.");
|
Assert.AreNotEqual(0.0, inserted.TimestampExt);
|
||||||
Assert.AreNotEqual(0.0, inserted.Timestamp, "Inserted telegram Timestamp should be set.");
|
|
||||||
Assert.AreNotEqual(0.0, inserted.TimestampExt, "Inserted telegram TimestampExt should be set.");
|
|
||||||
|
|
||||||
for (int i = 0; i < ChannelCount; i++)
|
for (int i = 0; i < ChannelCount; i++)
|
||||||
{
|
{
|
||||||
if (i == expectedChannelIndex)
|
if (i == expectedChannelIndex)
|
||||||
{
|
{
|
||||||
Assert.AreNotEqual(0.0, volumeRawExtLast[i], $"Expected channel {i} volume cache was not updated.");
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -259,38 +335,12 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.AreEqual(volumeRawExtLast[expectedChannelIndex], inserted.VolumeRawExt, 1e-9,
|
Assert.AreEqual(volumeRawExtLast[expectedChannelIndex], inserted.VolumeRawExt, 1e-9);
|
||||||
"Inserted telegram VolumeRawExt should match updated channel cache.");
|
Assert.AreEqual(timestampExtLast[expectedChannelIndex], inserted.TimestampExt, 1e-9);
|
||||||
|
|
||||||
Assert.AreEqual(timestampExtLast[expectedChannelIndex], inserted.TimestampExt, 1e-9,
|
|
||||||
"Inserted telegram TimestampExt should match updated channel cache.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ProcessOptoLine_ShouldInsertMultipleTelegrams_WithCorrectChannels()
|
public void VolumeLtrStart_And_VolumeLtrEnd_ShouldUsePreparedCachedChannelData()
|
||||||
{
|
|
||||||
var fake = new FakeSerialDriver();
|
|
||||||
fake.Open();
|
|
||||||
|
|
||||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
|
||||||
reader.Initialize();
|
|
||||||
reader.optoSerialPort = fake;
|
|
||||||
|
|
||||||
reader.ProcessOptoLine( "@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave);
|
|
||||||
reader.ProcessOptoLine( "@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", DataStreamState.ProcessAndSave);
|
|
||||||
reader.ProcessOptoLine( "@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", DataStreamState.ProcessAndSave);
|
|
||||||
|
|
||||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
|
||||||
var optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
|
||||||
|
|
||||||
Assert.AreEqual(3, optoDataCount);
|
|
||||||
Assert.AreEqual(0, optoData[0].IChannel());
|
|
||||||
Assert.AreEqual(1, optoData[1].IChannel());
|
|
||||||
Assert.AreEqual(2, optoData[2].IChannel());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void VolumeLtrStart_And_VolumeLtrEnd_ShouldUsePerChannelAverages()
|
|
||||||
{
|
{
|
||||||
var fake = new FakeSerialDriver();
|
var fake = new FakeSerialDriver();
|
||||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
@@ -298,14 +348,6 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
|
|
||||||
// Build 18 records: 6 groups of channels 0,1,2
|
|
||||||
// Start group average = (10 + 20 + 30)/3 = 20
|
|
||||||
// Last 5 per channel:
|
|
||||||
// ch0: 11,12,13,14,15 => avg 13
|
|
||||||
// ch1: 21,22,23,24,25 => avg 23
|
|
||||||
// ch2: 31,32,33,34,35 => avg 33
|
|
||||||
// final average = (13 + 23 + 33)/3 = 23
|
|
||||||
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (int group = 0; group < 6; group++)
|
for (int group = 0; group < 6; group++)
|
||||||
{
|
{
|
||||||
@@ -315,11 +357,22 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetPrivateField(reader, "optoDataCount", 18);
|
SetPrivateField(reader, "optoDataCount", 18);
|
||||||
reader.TestStartTelegramIx = 2; // first full 3-channel group
|
reader.TestStartTelegramIx = 1;
|
||||||
reader.TestEndTelegramIx = 17; // last record
|
reader.TestEndTelegramIx = 17;
|
||||||
|
|
||||||
Assert.AreEqual(20.0, reader.VolumeLtrStart, 1e-9);
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
Assert.AreEqual(23.0, reader.VolumeLtrEnd, 1e-9);
|
|
||||||
|
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStart, 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.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)
|
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt)
|
||||||
@@ -332,7 +385,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
iChannel = channel
|
iChannel = channel
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void VolumeLtrEnd_ShouldAverageOnlyAvailableChannels()
|
public void VolumeLtrEnd_ShouldAverageOnlyAvailableChannels()
|
||||||
{
|
{
|
||||||
@@ -344,7 +397,6 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
// only channels 0 and 1
|
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
optoData[idx++] = CreateOptoRecord(0, 10 + i, 100 + i);
|
optoData[idx++] = CreateOptoRecord(0, 10 + i, 100 + i);
|
||||||
@@ -355,8 +407,384 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
reader.TestStartTelegramIx = 1;
|
reader.TestStartTelegramIx = 1;
|
||||||
reader.TestEndTelegramIx = idx - 1;
|
reader.TestEndTelegramIx = idx - 1;
|
||||||
|
|
||||||
// ch0 avg = 12, ch1 avg = 22 => total avg = 17
|
InvokePrepareCalculatedChannelData(reader);
|
||||||
Assert.AreEqual(17.0, reader.VolumeLtrEnd, 1e-9);
|
|
||||||
|
Assert.AreEqual(15.5, reader.VolumeLtrStart, 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]
|
||||||
|
public void ProcessOptoLine_Block_f_h1_h2_h3_f_ShouldResetBuffersOnlyAfterLastF()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
fake.Open();
|
||||||
|
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
reader.optoSerialPort = fake;
|
||||||
|
reader.ResetAfterBlockRepetitions = 1;
|
||||||
|
|
||||||
|
bool reset;
|
||||||
|
|
||||||
|
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
|
||||||
|
Assert.IsFalse(reset, "Reset must not happen on the first @f.");
|
||||||
|
|
||||||
|
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 @h 1.");
|
||||||
|
|
||||||
|
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 @h 2.");
|
||||||
|
|
||||||
|
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 immediately after @h 3.");
|
||||||
|
|
||||||
|
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
|
||||||
|
//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 ProcessingLoop_FullBlock_ShouldDiscardBuffersAfterClosingF()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
fake.Open();
|
||||||
|
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
reader.optoSerialPort = fake;
|
||||||
|
reader.ResetAfterBlockRepetitions = 1;
|
||||||
|
|
||||||
|
InitializeThreeChannelState(reader);
|
||||||
|
EnableProcessingLoopForTests(reader);
|
||||||
|
|
||||||
|
reader.StartProcessingLoop();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
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]
|
||||||
|
public void ProcessOptoLine_LastF_AfterH3_ShouldRequestBufferReset()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
fake.Open();
|
||||||
|
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
Assert.IsTrue(reset, "Closing @f after @h 3 must request reset.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ProcessOptoLine_LastF_AfterH3_ShouldNotRequestReset_WhenRepetitionCountIsGreaterThanOne()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
fake.Open();
|
||||||
|
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
reader.optoSerialPort = fake;
|
||||||
|
reader.ResetAfterBlockRepetitions = 3;
|
||||||
|
|
||||||
|
bool reset;
|
||||||
|
|
||||||
|
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
|
||||||
|
Assert.IsFalse(reset, "Reset must not happen after the first completed block when repetition count is 3.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ProcessOptoLine_ShouldResetOnlyAfterThirdCompletedBlock()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
fake.Open();
|
||||||
|
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (repetition < 3)
|
||||||
|
Assert.IsFalse(reset, "Reset must not happen before third full block.");
|
||||||
|
else
|
||||||
|
Assert.IsTrue(reset, "Reset must happen on third full block.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ProcessOptoLine_ShouldResetOnlyAfterFifthCompletedBlock()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
fake.Open();
|
||||||
|
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
reader.Initialize();
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (repetition < 5)
|
||||||
|
Assert.IsFalse(reset, "Reset must not happen before fifth full block.");
|
||||||
|
else
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+389
@@ -0,0 +1,389 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
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 GenesisSmartReaderThreadedReadTests
|
||||||
|
{
|
||||||
|
private const int ChannelCount = 3;
|
||||||
|
|
||||||
|
private static GenesisCfg CreateCfg()
|
||||||
|
{
|
||||||
|
var cfg = new GenesisCfg(null);
|
||||||
|
cfg.OptoComPortNr = 7;
|
||||||
|
cfg.RfidComPortNr = 8;
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 bool WaitUntil(Func<bool> condition, int timeoutMs = 1500, int pollMs = 20)
|
||||||
|
{
|
||||||
|
var start = Environment.TickCount;
|
||||||
|
|
||||||
|
while (Environment.TickCount - start < timeoutMs)
|
||||||
|
{
|
||||||
|
if (condition())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Thread.Sleep(pollMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InitializeThreeChannelState(GenesisSmartReader reader)
|
||||||
|
{
|
||||||
|
SetPrivateField(reader, "volumeRawExtLast", new double[ChannelCount]);
|
||||||
|
SetPrivateField(reader, "timestampExtLast", new double[ChannelCount]);
|
||||||
|
|
||||||
|
SetPrivateField(reader, "lastVolumeRaw", new double[ChannelCount]);
|
||||||
|
SetPrivateField(reader, "lastTimestamp", new double[ChannelCount]);
|
||||||
|
|
||||||
|
SetPrivateField(reader, "volumeLtr", new[] { 0.0, 0.0, 0.0 });
|
||||||
|
SetPrivateField(reader, "volumeLtr0", new[] { 0.0, 0.0, 0.0 });
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
|
||||||
|
reader.Initialize();
|
||||||
|
reader.Start();
|
||||||
|
|
||||||
|
Assert.IsTrue(fake.IsOpen);
|
||||||
|
Assert.IsTrue(fake.OpenCalls >= 1);
|
||||||
|
|
||||||
|
var readLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_readLoopTask");
|
||||||
|
Assert.IsNotNull(readLoopTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ProcessingLoop_ShouldConsumeQueuedLine()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
|
||||||
|
reader.Initialize();
|
||||||
|
InitializeThreeChannelState(reader);
|
||||||
|
reader.Start();
|
||||||
|
|
||||||
|
ForceProcessingEnabled(reader);
|
||||||
|
InstallSuccessfulProcessingOverride(reader);
|
||||||
|
|
||||||
|
EnqueueIncomingLine(reader, "TEST_LINE_1");
|
||||||
|
|
||||||
|
bool processed = WaitUntil(() =>
|
||||||
|
{
|
||||||
|
int optoDataCount = GetField<int>(reader, "optoDataCount");
|
||||||
|
return optoDataCount == 1;
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
Assert.IsTrue(processed, "Expected processing loop to consume queued line.");
|
||||||
|
|
||||||
|
int finalCount = GetField<int>(reader, "optoDataCount");
|
||||||
|
Assert.AreEqual(1, finalCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
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();
|
||||||
|
|
||||||
|
ForceProcessingEnabled(reader);
|
||||||
|
|
||||||
|
EnqueueIncomingLine(reader,
|
||||||
|
"@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, "Expected processing loop to consume queued line.");
|
||||||
|
|
||||||
|
int finalCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||||
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
||||||
|
|
||||||
|
Assert.AreEqual(1, finalCount);
|
||||||
|
Assert.AreEqual(1, optoData[0].IChannel());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ProcessingLoop_ShouldConsumeAllQueuedLines()
|
||||||
|
{
|
||||||
|
var fake = new FakeSerialDriver();
|
||||||
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||||
|
|
||||||
|
reader.Initialize();
|
||||||
|
InitializeThreeChannelState(reader);
|
||||||
|
reader.Start();
|
||||||
|
|
||||||
|
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 processed = WaitUntil(() =>
|
||||||
|
{
|
||||||
|
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||||
|
return optoDataCount >= 1;
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
Assert.IsTrue(processed, "Expected background processing loop to process line.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
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);
|
||||||
|
|
||||||
|
reader.Initialize();
|
||||||
|
reader.Start();
|
||||||
|
|
||||||
|
Assert.IsTrue(fake.IsOpen);
|
||||||
|
Assert.IsTrue(fake.OpenCalls >= 1);
|
||||||
|
|
||||||
|
var readLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_readLoopTask");
|
||||||
|
var processLoopTask = GetPrivateField<System.Threading.Tasks.Task>(reader, "_processLoopTask");
|
||||||
|
|
||||||
|
Assert.IsNotNull(readLoopTask);
|
||||||
|
Assert.IsNotNull(processLoopTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+427
@@ -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))]
|
[TestSubject(typeof(CliRunner))]
|
||||||
public class CliRunnerTest
|
public class CliRunnerTest
|
||||||
{
|
{
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ExtractJson_Test()
|
public void ExtractJson_Test()
|
||||||
{
|
{
|
||||||
String allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
|
string allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
|
||||||
CliRunner cliRunner = new CliRunner(false);
|
CliRunner cliRunner = new CliRunner(false);
|
||||||
string json = cliRunner.ExtractJson(allOutput);
|
string json = cliRunner.ExtractJson(allOutput);
|
||||||
|
|
||||||
Assert.IsTrue(!string.IsNullOrEmpty(json));
|
Assert.IsFalse(string.IsNullOrEmpty(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ExtractJson_Test2()
|
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);
|
CliRunner cliRunner = new CliRunner(false);
|
||||||
string json = cliRunner.ExtractJson(allOutput);
|
string json = cliRunner.ExtractJson(allOutput);
|
||||||
|
|
||||||
Assert.IsTrue(!string.IsNullOrEmpty(json));
|
Assert.IsFalse(string.IsNullOrEmpty(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TryJsonStringDeserialize_Test()
|
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);
|
CliRunner cliRunner = new CliRunner(false);
|
||||||
string json = cliRunner.ExtractJson(allOutput);
|
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.IsTrue(ok, "Deserialization failed");
|
||||||
Assert.IsNotNull(dto);
|
Assert.IsNotNull(dto);
|
||||||
Assert.AreEqual("1000000267", dto.DeviceId);
|
Assert.AreEqual("1000000267", dto.DeviceId);
|
||||||
@@ -53,120 +54,165 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
|||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RunMultipleTimesTestProgram_CheckParalelWork()
|
public void RunMultipleTimesTestProgram_CheckParalelWork()
|
||||||
{
|
{
|
||||||
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
|
SerialPortData serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
|
||||||
|
|
||||||
// Check if the executable exists in current directory
|
|
||||||
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CliRunner cliRunner = new CliRunner(false);
|
CliRunner cliRunner = new CliRunner(false);
|
||||||
|
|
||||||
CliRunner cliRunnerOne = new CliRunner(false);
|
CliRunner cliRunnerOne = new CliRunner(false);
|
||||||
DateTime StartTime = DateTime.Now;
|
DateTime startTime = DateTime.Now;
|
||||||
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
|
||||||
|
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||||
|
serialPort,
|
||||||
|
SerialPortData.EMeterArg.AllParams);
|
||||||
|
|
||||||
cliRunnerOne.WaitAll();
|
cliRunnerOne.WaitAll();
|
||||||
TimeSpan OneEndTime = DateTime.Now - StartTime;
|
|
||||||
|
TimeSpan oneEndTime = DateTime.Now - startTime;
|
||||||
StartTime = DateTime.Now;
|
|
||||||
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
startTime = DateTime.Now;
|
||||||
|
Console.WriteLine($"Start Time Loop: {startTime:yyyy-MM-dd HH:mm:ss}");
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||||
|
serialPort,
|
||||||
|
SerialPortData.EMeterArg.AllParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
cliRunner.WaitAll();
|
cliRunner.WaitAll();
|
||||||
|
|
||||||
DateTime EndTime = DateTime.Now;
|
DateTime endTime = DateTime.Now;
|
||||||
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
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} " +
|
TimeSpan delta = endTime - startTime;
|
||||||
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
|
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}");
|
Console.WriteLine($"Total tasks: {cliRunner.TaskPool.Count}");
|
||||||
|
|
||||||
|
foreach (CliTaskInfo taskInfo in cliRunner.TaskPool)
|
||||||
foreach (Task<JsonDataFromPoseidon> task 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;
|
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
|
||||||
Console.WriteLine($"Result: {jsonDataFromPoseidon.DeviceId}");
|
Console.WriteLine($"Result: {jsonDataFromPoseidon?.DeviceId}");
|
||||||
Assert.IsNotNull(jsonDataFromPoseidon);
|
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]
|
[TestMethod]
|
||||||
public async Task RunMultipleTimesTestProgram_CheckParalelWorkCumulative()
|
public async Task RunMultipleTimesTestProgram_CheckParalelWorkCumulative()
|
||||||
{
|
{
|
||||||
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
|
SerialPortData serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
|
||||||
|
|
||||||
// Check if the executable exists in current directory
|
|
||||||
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CliRunner> cliRunnerList = new List<CliRunner>();
|
List<CliRunner> cliRunnerList = new List<CliRunner>();
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
cliRunnerList.Add(new CliRunner(false));
|
cliRunnerList.Add(new CliRunner(false));
|
||||||
|
}
|
||||||
|
|
||||||
CliRunner cliRunnerOne = new CliRunner(false);
|
CliRunner cliRunnerOne = new CliRunner(false);
|
||||||
DateTime StartTime = DateTime.Now;
|
DateTime startTime = DateTime.Now;
|
||||||
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
|
||||||
|
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||||
|
serialPort,
|
||||||
|
SerialPortData.EMeterArg.AllParams);
|
||||||
|
|
||||||
cliRunnerOne.WaitAll();
|
cliRunnerOne.WaitAll();
|
||||||
TimeSpan OneEndTime = DateTime.Now - StartTime;
|
|
||||||
|
TimeSpan oneEndTime = DateTime.Now - startTime;
|
||||||
StartTime = DateTime.Now;
|
|
||||||
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
startTime = DateTime.Now;
|
||||||
|
Console.WriteLine($"Start Time Loop: {startTime:yyyy-MM-dd HH:mm:ss}");
|
||||||
|
|
||||||
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
|
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
|
||||||
{
|
{
|
||||||
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||||
|
serialPort,
|
||||||
SerialPortData.EMeterArg.AllParams);
|
SerialPortData.EMeterArg.AllParams);
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
||||||
|
serialPort,
|
||||||
SerialPortData.EMeterArg.AllParams);
|
SerialPortData.EMeterArg.AllParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for ALL tasks from ALL runners
|
Task[] allTasks = cliRunnerList
|
||||||
var allTasks = cliRunnerList.SelectMany(r => r.TaskPool).ToArray();
|
.SelectMany(r => r.TaskPool)
|
||||||
|
.Where(ti => ti != null && ti.Task != null)
|
||||||
|
.Select(ti => ti.Task)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
await Task.WhenAll(allTasks);
|
await Task.WhenAll(allTasks);
|
||||||
|
|
||||||
DateTime EndTime = DateTime.Now;
|
DateTime endTime = DateTime.Now;
|
||||||
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
|
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} " +
|
TimeSpan delta = endTime - startTime;
|
||||||
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
|
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)}");
|
Console.WriteLine($"Total tasks: {cliRunnerList.Sum(runner => runner.TaskPool.Count)}");
|
||||||
|
|
||||||
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
|
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
|
||||||
{
|
{
|
||||||
string results = $"iCliRunner: {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;
|
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
|
||||||
results += ($" ID: {jsonDataFromPoseidon.DeviceId}");
|
results += $" ID: {jsonDataFromPoseidon?.DeviceId}";
|
||||||
Assert.IsNotNull(jsonDataFromPoseidon);
|
Assert.IsNotNull(jsonDataFromPoseidon);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Fail(
|
||||||
|
$"Task did not complete successfully. Runner={iCliRunner}, State={taskInfo.State}, Status={taskInfo.Task.Status}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(results);
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -108,8 +108,13 @@
|
|||||||
<Compile Include="Rig\Output\FileWriters\Enhanced\WriterTest.cs" />
|
<Compile Include="Rig\Output\FileWriters\Enhanced\WriterTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\common\OptoTelegramRawTest.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\common\OptoTelegramRawTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\FakeSerialDriver.cs" />
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\FakeSerialDriver.cs" />
|
||||||
|
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisReaderTests.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\GenesisRegReader\implementations\GenesisSmartReaderChannelAveragingTests.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\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\diagnosticLed\DiagnosticLedParserTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\hexLogger\HexFormatterTest.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\hexLogger\HexFormatterTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\IperlHatProtocol\IperlHatFrameBuilderTests.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\IperlHatProtocol\IperlHatFrameBuilderTests.cs" />
|
||||||
@@ -120,6 +125,8 @@
|
|||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadBaudRateDetectionTests.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadBaudRateDetectionTests.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadFrameBuilderTest.cs" />
|
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadFrameBuilderTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTest.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\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
|
||||||
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
||||||
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user