diff --git a/Common/Iperl/OptoTelegramRaw.cs b/Common/Iperl/OptoTelegramRaw.cs index 6a51f94cf..effeceaa7 100644 --- a/Common/Iperl/OptoTelegramRaw.cs +++ b/Common/Iperl/OptoTelegramRaw.cs @@ -56,7 +56,7 @@ namespace Common.Iperl public double Flow(double scalingFactor) { return 0.225 * scalingFactor * (double)FlowRaw; } public double Volume(double scalingFactor) { return 0.0000625 * scalingFactor * (double)VolumeRawExt; } public Int32 FlipTime() { return Impedance; } - public decimal TimestampDec() { return (decimal)TimestampExt / (decimal)8192; } + public decimal TimestampDec() { return (decimal)TimestampExt; } public double VolumeDelta(double scalingFactor, OptoTelegramRaw previous) { return (previous == null) ? 0 : Volume(scalingFactor) - previous.Volume(scalingFactor); } public decimal TimeDelta() { return TimestampDec() - TestStartTimestampDec; } public string Label() diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index 0c99cc150..8bdd46065 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("3.9.3065.1")] -[assembly: AssemblyFileVersion("3.9.3065.1")] +[assembly: AssemblyVersion("3.9.3066.1")] +[assembly: AssemblyFileVersion("3.9.3066.1")] diff --git a/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs b/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs index 22acd7cbc..9ef2e4d5b 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRaw.cs @@ -58,7 +58,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.common public double Flow(double scalingFactor) { return 0.225 * scalingFactor * (double)FlowRaw; } public double Volume(double scalingFactor) { return 0.0000625 * scalingFactor * (double)VolumeRawExt; } public Int32 FlipTime() { return Impedance; } - public decimal TimestampDec() { return (decimal)TimestampExt / (decimal)8192; } + + public decimal TimestampDec() { return (decimal)TimestampExt;} public double VolumeDelta(double scalingFactor, OptoTelegramRaw previous) { return (previous == null) ? 0 : Volume(scalingFactor) - previous.Volume(scalingFactor); } public decimal TimeDelta() { return TimestampDec() - TestStartTimestampDec; } public string Label() @@ -330,9 +331,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.common (EmfRaw & 0x00FFFFFF).ToString("X6"), MagneticFieldRaw.ToString("X4"), FlowRaw.ToString("X4"), - VolumeRaw.ToString("X6"), + VolumeRaw.ToString("F4", culture), Impedance.ToString("X4"), - Timestamp.ToString("X8"), + Timestamp.ToString("F4", culture), CheckSum.ToString("X2"), EMF().ToString("F4", culture), MagneticField().ToString("F0", culture), diff --git a/TBFTests/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRawTest.cs b/TBFTests/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRawTest.cs new file mode 100644 index 000000000..30a66b7d4 --- /dev/null +++ b/TBFTests/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRawTest.cs @@ -0,0 +1,350 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TBF.Rig.TestMethods.iPerlCommunication.common; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer; + +namespace TBFTests.Rig.TestMethods.iPerlCommunication.common +{ + [TestClass] + public class OptoTelegramRawTest + { + private static DiagnosticLedState7Data CreateDiagnosticLedState7Data( + double volumeLiters, + double timeSeconds, + short rawFlow = 0) + { + uint rawVolumeTicks = (uint)Math.Round(volumeLiters / 0.00025); + uint timestampTicks = (uint)Math.Round(timeSeconds * 8192.0); + + string[] fields = + { + "000000", + "0000", + ((ushort)rawFlow).ToString("X4"), + rawVolumeTicks.ToString("X6"), + "0000", + "0000", + timestampTicks.ToString("X8"), + "00", + "00000000", + "0000", + "0000", + "0000", + "0000", + "00", + "0000", + "0000", + "00", + "00", + "00000000", + "00", + "000000", + "000000", + "0000", + "0000", + "00", + "00" + }; + + string rawLine = string.Join("\t", fields) + "\r\n"; + return new DiagnosticLedState7Data(rawLine, fields); + } + + [TestMethod] + public void UpdateFromSmart_FirstSample_ShouldInitializeFields() + { + var telegram = new OptoTelegramRaw(); + var data = CreateDiagnosticLedState7Data( + volumeLiters: 2.5, + timeSeconds: 100.0); + + double lastVolume = double.NaN; + double lastTimestamp = double.NaN; + + telegram.UpdateFromSmart(data, counter: 7, refFlow: 1.5f, ref lastVolume, ref lastTimestamp); + + Assert.AreEqual(7, telegram.Counter); + Assert.AreEqual(1.5f, telegram.RefFlow); + Assert.AreEqual(OptoTelegramFlags.OK, telegram.Flags); + + Assert.AreEqual(2.5, telegram.VolumeRaw, 1e-9); + Assert.AreEqual(2.5, telegram.VolumeRawExt, 1e-9); + Assert.AreEqual(2.5, lastVolume, 1e-9); + + Assert.AreEqual(100.0, telegram.Timestamp, 1e-9); + Assert.AreEqual(100.0, telegram.TimestampExt, 1e-9); + Assert.AreEqual(100.0, lastTimestamp, 1e-9); + + Assert.AreNotEqual(default(DateTime), telegram.DateTime); + 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] + public void UpdateFromSmart_RealDecodedSample_ShouldMapExpectedValues() + { + var telegram = new OptoTelegramRaw(); + + var data = CreateDiagnosticLedState7Data( + volumeLiters: 0.48025, + timeSeconds: 62727.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.Counter); + Assert.AreEqual(0.0f, telegram.RefFlow); + Assert.AreEqual(OptoTelegramFlags.OK, telegram.Flags); + + Assert.AreEqual(0.48025, telegram.VolumeRaw, 1e-9); + Assert.AreEqual(0.48025, telegram.VolumeRawExt, 1e-9); + Assert.AreEqual(0.48025, lastVolume, 1e-9); + + Assert.AreEqual(62727.0, telegram.Timestamp, 1e-9); + Assert.AreEqual(62727.0, telegram.TimestampExt, 1e-9); + Assert.AreEqual(62727.0, lastTimestamp, 1e-9); + } + + [TestMethod] + public void UpdateFromSmart_TimestampOverflow_ShouldKeepIncreasingExtendedTimestamp() + { + double lastVolumeExt = double.NaN; + double lastTimestampExt = double.NaN; + + double[] times = + { + 524280.0, + 524287.0, + 1.0, + 2.0, + 10.0 + }; + + double previousExt = double.NaN; + + for (int i = 0; i < times.Length; i++) + { + var telegram = new OptoTelegramRaw(); + var data = CreateDiagnosticLedState7Data(1.0, times[i]); + + telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt); + + if (!double.IsNaN(previousExt)) + { + Assert.IsTrue( + telegram.TimestampExt >= previousExt, + $"Timestamp decreased at index {i}. Prev={previousExt}, Current={telegram.TimestampExt}"); + } + + previousExt = telegram.TimestampExt; + } + } + + [TestMethod] + public void UpdateFromSmart_TimeDelta_ShouldNeverBeNegativeAcrossOverflow() + { + double lastVolumeExt = double.NaN; + double lastTimestampExt = double.NaN; + + OptoTelegramRaw.TestStartTimestampDec = 524280m; + + double[] times = + { + 524280.0, + 524287.0, + 1.0, + 2.0, + 10.0 + }; + + decimal previousDelta = decimal.MinValue; + + for (int i = 0; i < times.Length; i++) + { + var telegram = new OptoTelegramRaw(); + var data = CreateDiagnosticLedState7Data(1.0, times[i]); + + telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt); + + decimal delta = telegram.TimeDelta(); + + Assert.IsTrue(delta >= 0, $"Negative TimeDelta at index {i}: {delta}"); + Assert.IsTrue(delta >= previousDelta, + $"TimeDelta decreased at index {i}. Previous={previousDelta}, Current={delta}"); + + previousDelta = delta; + } + } + + [TestMethod] + public void UpdateFromSmart_VolumeOverflow_ShouldKeepIncreasingExtendedVolume() + { + double lastVolumeExt = double.NaN; + double lastTimestampExt = double.NaN; + + double volumeRange = 16777216.0 * 0.00025; // 4194.304 L + + double[] volumes = + { + 4194.0, + 4194.25, + volumeRange + 0.25, + volumeRange + 1.0, + volumeRange + 2.0 + }; + + double previousExt = double.NaN; + + for (int i = 0; i < volumes.Length; i++) + { + var telegram = new OptoTelegramRaw(); + var data = CreateDiagnosticLedState7Data(volumes[i], i); + + telegram.UpdateFromSmart(data, i, 0, ref lastVolumeExt, ref lastTimestampExt); + + if (!double.IsNaN(previousExt)) + { + Assert.IsTrue( + telegram.VolumeRawExt >= previousExt, + $"Volume decreased at index {i}. Prev={previousExt}, Current={telegram.VolumeRawExt}"); + } + + previousExt = telegram.VolumeRawExt; + } + } + + [TestMethod] + public void SetFlags_ShouldChangeFlags() + { + var telegram = new OptoTelegramRaw(); + + telegram.SetFlags(OptoTelegramFlags.SyncError); + + Assert.AreEqual(OptoTelegramFlags.SyncError, telegram.Flags); + } + + [TestMethod] + public void Label_ShouldReturnExpectedText() + { + var telegram = new OptoTelegramRaw(); + + telegram.Flags = OptoTelegramFlags.OK_TestStart; + Assert.AreEqual("#### start test ####", telegram.Label()); + + telegram.Flags = OptoTelegramFlags.OK_TestEnd; + Assert.AreEqual("#### end of test ####", telegram.Label()); + + telegram.Flags = OptoTelegramFlags.OK; + Assert.AreEqual(string.Empty, telegram.Label()); + } + + [TestMethod] + public void TimestampDec_ShouldConvertCorrectly() + { + var telegram = new OptoTelegramRaw + { + TimestampExt = 8192.0 + }; + + Assert.AreEqual(8192.0m, telegram.TimestampDec()); + } + + [TestMethod] + public void VolumeDelta_ShouldReturnDifferenceAgainstPrevious() + { + var previous = new OptoTelegramRaw { VolumeRawExt = 1000.0 }; + var current = new OptoTelegramRaw { VolumeRawExt = 2000.0 }; + + double scalingFactor = 2.0; + + double expectedPrevious = 0.0000625 * scalingFactor * 1000.0; + double expectedCurrent = 0.0000625 * scalingFactor * 2000.0; + double expectedDelta = expectedCurrent - expectedPrevious; + + Assert.AreEqual(expectedDelta, current.VolumeDelta(scalingFactor, previous), 1e-12); + } + + [TestMethod] + public void UpdateFromStringDummy_InvalidLength_ShouldReturnFalse_AndSetInvalidFlag() + { + var telegram = new OptoTelegramRaw(); + + bool result = telegram.UpdateFromStringDummy("short"); + + Assert.IsFalse(result); + Assert.AreEqual(OptoTelegramFlags.InvalidTelegram, telegram.Flags); + } + + [TestMethod] + public void UpdateFromStringDummy_ValidFormatButWrongChecksum_ShouldReturnFalse_AndSetInvalidFlag() + { + var telegram = new OptoTelegramRaw(); + + string dummy = "FFFFFE\t51EA\t0000\t65324E\t0087\tF6319DFF\t00\r\n"; + + bool result = telegram.UpdateFromStringDummy(dummy); + + Assert.IsFalse(result); + Assert.AreEqual(OptoTelegramFlags.InvalidTelegram, telegram.Flags); + } + + [TestMethod] + public void ToString_WhenSyncError_ShouldReturnSynchronizationErrorText() + { + var telegram = new OptoTelegramRaw + { + Flags = OptoTelegramFlags.SyncError + }; + + string text = telegram.ToString(1.0, null); + + Assert.AreEqual("Sychronization error", text); + } + + [TestMethod] + public void ToString_WhenInvalidTelegram_ShouldReturnInvalidTelegramText() + { + var telegram = new OptoTelegramRaw + { + Flags = OptoTelegramFlags.InvalidTelegram + }; + + string text = telegram.ToString(1.0, null); + + Assert.AreEqual("Invalid telegram", text); + } + + [TestMethod] + public void ToString_WhenOk_ShouldContainCounterAndLabel() + { + var telegram = new OptoTelegramRaw + { + Flags = OptoTelegramFlags.OK_TestStart, + DateTime = new DateTime(2024, 1, 1, 10, 11, 12, 123), + Counter = 5, + EmfRaw = 1, + MagneticFieldRaw = 2, + FlowRaw = 3, + VolumeRaw = 4, + Impedance = 5, + Timestamp = 6, + CheckSum = 7, + VolumeRawExt = 1000, + TimestampExt = 8192, + RefFlow = 1.25f + }; + + OptoTelegramRaw.TestStartTimestampDec = 0m; + + string text = telegram.ToString(2.0, null); + + Assert.IsTrue(text.Contains("5 :"), "Counter should be present in output."); + Assert.IsTrue(text.Contains("#### start test ####"), "Label should be present in output."); + } + } +} \ No newline at end of file diff --git a/TBFTests/TBFTests.csproj b/TBFTests/TBFTests.csproj index 69a472d5b..0dcbe63d1 100644 --- a/TBFTests/TBFTests.csproj +++ b/TBFTests/TBFTests.csproj @@ -9,7 +9,7 @@ Properties TBFTests TBFTests - v4.7.2 + v4.8 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0 @@ -19,6 +19,7 @@ UnitTest + 8 true @@ -135,6 +136,7 @@ + @@ -159,11 +161,10 @@ SchematicDrawing - {8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48} + {8648fd92-cda1-4c3a-b5f9-fe547ce1fa48} TBF -