using System; using JetBrains.Annotations; 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] [TestSubject(typeof(OptoTelegramRaw))] public class OptoTelegramRawTest { private const double EPS = 1e-6; private static OptoTelegramRaw Create() => new OptoTelegramRaw(); private static DiagnosticLedState4Data CreateTelegram(uint rawVolume24, uint timestamp32) { string HexU(uint value, int bytes) => value.ToString($"X{bytes * 2}"); string[] fields = { "000000","0000","0000", HexU(rawVolume24,3),"0000","0000", HexU(timestamp32,4),"00","00000000", "0000","0000","0000","0000","00" }; return new DiagnosticLedState4Data("TEST", fields); } // helper: compute liters per tick exactly as production private static double LitersPerTick => (4.0 / 1000.0) / 3.785411784 / 2.0; private static double TimestampPerTick => 1.0 / 4096.0; [TestMethod] public void NormalProgression_NoWrap() { var sample = Create(); var d1 = CreateTelegram(1000, 2000); double volLast = d1.RawVolume; double tsLast = d1.AsicTimestamp; var d2 = CreateTelegram(1010, 2010); sample.UpdateFromSmart(d2, 0, 0, ref volLast, ref tsLast); Assert.AreEqual(d2.RawVolume, sample.VolumeRawExt, EPS); Assert.AreEqual(d2.AsicTimestamp, sample.TimestampExt, EPS); } [TestMethod] public void VolumeForwardWrap_AddsOneFullVolumeRange() { var sample = Create(); var dLast = CreateTelegram((uint)((1 << 24) - 5), 0); double volLast = dLast.RawVolume; double tsLast = dLast.AsicTimestamp; var dNew = CreateTelegram(3u, 0u); sample.UpdateFromSmart(dNew, 0, 0, ref volLast, ref tsLast); double expectedIncrease = (1 << 24) * LitersPerTick; Assert.AreEqual(dNew.RawVolume + expectedIncrease, sample.VolumeRawExt, 1e-3); } [TestMethod] public void TimestampForwardWrap_AddsOneFullTimeRange() { var sample = Create(); var dLast = CreateTelegram(0, (uint)((1UL << 32) - 10)); double volLast = dLast.RawVolume; double tsLast = dLast.AsicTimestamp; var dNew = CreateTelegram(0, 5); sample.UpdateFromSmart(dNew, 0, 0, ref volLast, ref tsLast); double expectedIncrease = (1UL << 32) * TimestampPerTick; Assert.AreEqual(dNew.AsicTimestamp + expectedIncrease, sample.TimestampExt, 1e-3); } [TestMethod] public void HugeJump_UsesFallback() { var sample = Create(); var dLast = CreateTelegram(1000, 1000); double volLast = dLast.RawVolume; double tsLast = dLast.AsicTimestamp; var dNew = CreateTelegram((uint)(1 << 23), (uint)(1UL << 31)); sample.UpdateFromSmart(dNew, 0, 0, ref volLast, ref tsLast); Assert.AreEqual(dNew.RawVolume, sample.VolumeRawExt, EPS); Assert.AreEqual(dNew.AsicTimestamp, sample.TimestampExt, EPS); } [TestMethod] public void LongRun_MultipleWraps_RemainsMonotonic() { var sample = new OptoTelegramRaw(); double volLast = double.NaN; double tsLast = double.NaN; uint volCounter = (uint)((1 << 24) - 100); uint tsCounter = (uint)((1UL << 32) - 1000); double prevVol = double.NegativeInfinity; double prevTs = double.NegativeInfinity; for (int i = 0; i < 500; i++) { unchecked { volCounter += 200_000u; // < 2^23 tsCounter += 50_000_000u; // < 2^31 } var data = CreateTelegram(volCounter, tsCounter); sample.UpdateFromSmart(data, 0, 0, ref volLast, ref tsLast); Assert.IsTrue(sample.VolumeRawExt >= prevVol, $"Volume went backwards at i={i}"); Assert.IsTrue(sample.TimestampExt >= prevTs, $"Timestamp went backwards at i={i}"); prevVol = sample.VolumeRawExt; prevTs = sample.TimestampExt; } } } }