Standing Start roll over fix
Add volume rollover handling enhancements and corresponding unit tests: - Improve rollover logic in `PopulateVolume` for accurate volume compensation. - Add `TestStartEndFormTest` to validate rollover scenarios with unit tests. - Refactor and expand handling of initial volume state in `findBeginStateFromForm`. - Update project files to include new test dependencies and classes.
This commit is contained in:
parent
9606ce3588
commit
166cb28d28
@ -651,7 +651,7 @@ namespace TBF.Rig.DataEntry.Uni
|
||||
/// </summary>
|
||||
/// <param name="eArgsReader"></param>
|
||||
/// <param name="eArgsVolume"></param>
|
||||
private void PopulateVolume(IRegReader eArgsReader, double eArgsVolume)
|
||||
public void PopulateVolume(IRegReader eArgsReader, double eArgsVolume)
|
||||
{
|
||||
|
||||
if (regReaders == null || Double.IsNaN(eArgsVolume) || textBoxes == null)
|
||||
@ -668,27 +668,41 @@ namespace TBF.Rig.DataEntry.Uni
|
||||
|
||||
double VolumeRaw = eArgsVolume;
|
||||
double v = eArgsVolume;
|
||||
// // ---- normalize to [0, RANGE) in case upstream gives negative values ----
|
||||
// v = v % VOL_RANGE_LITERS;
|
||||
// if (v < 0) v += VOL_RANGE_LITERS;
|
||||
// VolumeRaw = v;
|
||||
// //Test and compensate roll over
|
||||
// if (isEnd)
|
||||
// {
|
||||
// if (eArgsReader != null)
|
||||
// {
|
||||
// double lastMod = eArgsReader.BeginWMState % VOL_RANGE_LITERS;
|
||||
// if (lastMod < 0) lastMod += VOL_RANGE_LITERS;
|
||||
//
|
||||
// double delta = v - lastMod;
|
||||
//
|
||||
// // choose the shortest jump across the modulo boundary
|
||||
// if (delta < -VOL_RANGE_LITERS / 2.0) delta += VOL_RANGE_LITERS;
|
||||
// else if (delta > VOL_RANGE_LITERS / 2.0) delta -= VOL_RANGE_LITERS;
|
||||
//
|
||||
// VolumeRaw = eArgsReader.BeginWMState + delta;
|
||||
// }
|
||||
// }
|
||||
// Test and compensate roll over
|
||||
if (isEnd)
|
||||
{
|
||||
if (eArgsReader != null && (!Double.IsNaN(eArgsReader.BeginWMState)))
|
||||
{
|
||||
double lastMod = eArgsReader.BeginWMState % VOL_RANGE_LITERS;
|
||||
if (lastMod < 0) lastMod += VOL_RANGE_LITERS;
|
||||
|
||||
double delta = v - lastMod;
|
||||
|
||||
// choose the shortest jump across the modulo boundary
|
||||
if (delta < -VOL_RANGE_LITERS / 2.0) delta += VOL_RANGE_LITERS;
|
||||
else if (delta > VOL_RANGE_LITERS / 2.0) delta -= VOL_RANGE_LITERS;
|
||||
|
||||
VolumeRaw = eArgsReader.BeginWMState + delta;
|
||||
log.Debug($"Roll over detected: {eArgsReader.Name} - {eArgsReader.BeginWMState} -> {VolumeRaw}");
|
||||
}
|
||||
else
|
||||
{
|
||||
//volume from form
|
||||
Double beginVolume = findBeginStateFromForm();
|
||||
|
||||
double lastMod = beginVolume % VOL_RANGE_LITERS;
|
||||
if (lastMod < 0) lastMod += VOL_RANGE_LITERS;
|
||||
|
||||
double delta = v - lastMod;
|
||||
|
||||
// choose the shortest jump across the modulo boundary
|
||||
if (delta < -VOL_RANGE_LITERS / 2.0) delta += VOL_RANGE_LITERS;
|
||||
else if (delta > VOL_RANGE_LITERS / 2.0) delta -= VOL_RANGE_LITERS;
|
||||
|
||||
VolumeRaw = beginVolume + delta;
|
||||
log.Debug($"Roll over detected: {eArgsReader.Name} - {eArgsReader.BeginWMState} -> {VolumeRaw}");
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < colItems.Count && k < comboRows; k++)
|
||||
{
|
||||
@ -722,6 +736,50 @@ namespace TBF.Rig.DataEntry.Uni
|
||||
}
|
||||
}
|
||||
|
||||
private Double findBeginStateFromForm()
|
||||
{
|
||||
|
||||
List<Ct> ctValues = new List<Ct> { Ct.StartState, Ct.StartStateAux };
|
||||
|
||||
int regReadersLength = regReaders.Length;
|
||||
int comboRows = textBoxes.GetLength(0);
|
||||
int comboCols = textBoxes.GetLength(1);
|
||||
|
||||
for (int k = 0; k < colItems.Count && k < comboRows; k++)
|
||||
{
|
||||
Ct current = (Ct)colItems[k].Content;
|
||||
if (ctValues.Contains(current)) // it define if is start or end
|
||||
{
|
||||
for (int ix = 0; ix < wmsCount && ix < comboCols; ix++)
|
||||
{
|
||||
int regIndex = ix;
|
||||
|
||||
if (regIndex >= 0 && regIndex < regReadersLength)
|
||||
{
|
||||
var textBox = textBoxes[k, ix];
|
||||
if (textBox != null && textBox.Text != null && textBox.Text.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (VolumeUnit == Unit.None)
|
||||
VolumeUnit = Unit.l;
|
||||
double VolumeRaw = Double.Parse(textBox.Text);
|
||||
Double convertBeginVolumeINLiters = Units.ConvertFrom(VolumeUnit, VolumeRaw);
|
||||
return convertBeginVolumeINLiters;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error($"Error converting volume to {VolumeUnit}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0D;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When one combo box is updated using drop-down menu, all combo boxes
|
||||
/// are updated by this function.
|
||||
|
||||
@ -1731,8 +1731,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
||||
//Solve roll over
|
||||
if (endWMState < beginWMState)
|
||||
{
|
||||
log.Debug($"Solve roll over! endWMState: {endWMState} < beginWMState: {beginWMState}");
|
||||
const double VOL_RANGE_LITERS = 16777216.0 * 0.00025; // 4,194.304 l
|
||||
endWMState += VOL_RANGE_LITERS;
|
||||
log.Debug($"Solve roll over! Upgraded endWMState: {endWMState}, beginWMState: {beginWMState}");
|
||||
}
|
||||
}
|
||||
ReadPulses();
|
||||
|
||||
166
TBFTests/Rig/DataEntry/Uni/TestStartEndFormTest.cs
Normal file
166
TBFTests/Rig/DataEntry/Uni/TestStartEndFormTest.cs
Normal file
@ -0,0 +1,166 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using JetBrains.Annotations;
|
||||
using Results.Entities;
|
||||
using TBF.Rig.DataEntry;
|
||||
using TBF.Rig.DataEntry.Uni;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.GenericDevices;
|
||||
|
||||
|
||||
namespace TBFTests.Rig.DataEntry.Uni
|
||||
{
|
||||
[TestClass]
|
||||
[TestSubject(typeof(TestStartEndForm))]
|
||||
public class TestStartEndFormTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void PopulateVolume_TestRollOver()
|
||||
{
|
||||
Exception staEx = null;
|
||||
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
double volRange = GetConstDouble(typeof(TestStartEndForm), "VOL_RANGE_LITERS");
|
||||
|
||||
// Example: begin = R-10, v=10 => expectedRaw = begin + 20 (shortest jump across modulo)
|
||||
double begin = volRange - 10.0;
|
||||
double entered = 10.0;
|
||||
double expectedRaw = begin + 20.0;
|
||||
|
||||
var reader = new FakeRegReader
|
||||
{
|
||||
Name = "R1",
|
||||
BeginWMState = begin
|
||||
};
|
||||
|
||||
var waterMeters = new List<WaterMeter>
|
||||
{
|
||||
new WaterMeter { Disabled = false }
|
||||
};
|
||||
|
||||
// Use your DEItem class exactly:
|
||||
// - Content must be Ct.EndState (because isEnd==true)
|
||||
// - Action must not be LoadReadOnly, otherwise textbox may be disabled (not critical for setting Text,
|
||||
// but keep it editable)
|
||||
IList<DEItem> colItems = new List<DEItem>
|
||||
{
|
||||
new DEItem(Ct.EndState, "End", Ac.Clear, 120)
|
||||
};
|
||||
|
||||
// Force isEnd=true (constructor: isEnd = (wmStartStateStr != null))
|
||||
// Length must match (isCompound?2:1)*waterMeters.Count -> here 1*1 = 1.
|
||||
string[] wmStartStateStr = new[] { "x" };
|
||||
|
||||
var sut = new TestStartEndForm(
|
||||
waterMeters: waterMeters,
|
||||
regReaders: new IRegReader[] { reader },
|
||||
_lineSize: 1,
|
||||
title: "test",
|
||||
sz: FontSz.S,
|
||||
isStartBoxAlwaysEn: false,
|
||||
isLrOrder: false,
|
||||
formCloseKeys: "",
|
||||
colItems: colItems,
|
||||
isCompound: false,
|
||||
initialVolumeUnit: Unit.l, // keep conversion identity
|
||||
isCameraPicture: false,
|
||||
startImages: Array.Empty<string>(),
|
||||
endImages: Array.Empty<string>(),
|
||||
ocrVidi: null,
|
||||
ocrMessage: "",
|
||||
streamName: "",
|
||||
wmStartStateStr: wmStartStateStr,
|
||||
refVolume: 0,
|
||||
errLimLo: 0,
|
||||
errLimHi: 0
|
||||
);
|
||||
|
||||
// Act
|
||||
sut.PopulateVolume(reader, entered);
|
||||
|
||||
// Assert
|
||||
var tb = GetTextBox(sut, row: 0, col: 0);
|
||||
Assert.IsNotNull(tb, "Expected TextBox[0,0] to exist.");
|
||||
Assert.AreEqual(expectedRaw.ToString(), tb.Text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
staEx = ex;
|
||||
}
|
||||
});
|
||||
|
||||
t.SetApartmentState(ApartmentState.STA); // WinForms UI objects => STA is safest
|
||||
t.Start();
|
||||
t.Join();
|
||||
|
||||
if (staEx != null)
|
||||
throw new AssertFailedException("PopulateVolume_TestRollOver failed.", staEx);
|
||||
}
|
||||
|
||||
// ----- helpers -----
|
||||
|
||||
private static double GetConstDouble(Type type, string fieldName)
|
||||
{
|
||||
var f = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
if (f == null) throw new MissingFieldException(type.FullName, fieldName);
|
||||
|
||||
object v = f.IsLiteral ? f.GetRawConstantValue() : f.GetValue(null);
|
||||
return Convert.ToDouble(v);
|
||||
}
|
||||
|
||||
private static System.Windows.Forms.TextBox GetTextBox(TestStartEndForm sut, int row, int col)
|
||||
{
|
||||
var f = typeof(TestStartEndForm).GetField("textBoxes", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (f == null) throw new MissingFieldException(typeof(TestStartEndForm).FullName, "textBoxes");
|
||||
|
||||
var grid = (System.Windows.Forms.TextBox[,])f.GetValue(sut);
|
||||
return grid[row, col];
|
||||
}
|
||||
|
||||
private sealed class FakeRegReader : IRegReader
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ClassName { get; }
|
||||
public string ParentName { get; }
|
||||
public DebugMode DebugLevel { get; }
|
||||
public LogLevel LogLevel { get; }
|
||||
public IComponentCfg Cfg { get; }
|
||||
public IList<MeasurementCorrection> Corrections { get; set; }
|
||||
public IList<Uncertainty> Uncertainties { get; set; }
|
||||
public void Initialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void StartChangeHandler()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void StopChangeHandler()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public RegisterReaderType RegisterReaderType { get; }
|
||||
public int Position { get; }
|
||||
public double PulsesPerLtr { get; set; }
|
||||
public double LtrsPerPulse { get; }
|
||||
public string QuantityUnits { get; set; }
|
||||
public int WMPulses { get; }
|
||||
public int WMRefPulses { get; }
|
||||
public double WMVolume { get; }
|
||||
public double BeginWMState { get; set; }
|
||||
public double EndWMState { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,6 +84,7 @@
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
@ -99,6 +100,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Rig\DataEntry\Uni\IperlHead_test_RollOver_Average.cs" />
|
||||
<Compile Include="Rig\DataEntry\Uni\PopulateVolumeRolloverTests_Concept.cs" />
|
||||
<Compile Include="Rig\DataEntry\Uni\TestStartEndFormTest.cs" />
|
||||
<Compile Include="Rig\Network\Camera\KeyenceIV3G120\CameraTest.cs" />
|
||||
<Compile Include="Rig\Network\Camera\RoiForFixedStartKeyence\RoiTest.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\common\OptoTelegramRawTest.cs" />
|
||||
@ -111,10 +113,18 @@
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj">
|
||||
<Project>{c8939821-ba5c-4988-a3d0-bf53b74865c7}</Project>
|
||||
<Name>Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Config\Config.csproj">
|
||||
<Project>{743df7db-c7b6-42eb-986d-0f485e5588e4}</Project>
|
||||
<Name>Config</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Results\Results.csproj">
|
||||
<Project>{9d0dcc88-dc81-47eb-9fdd-4c3907871bfb}</Project>
|
||||
<Name>Results</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\TBF\TBF.csproj">
|
||||
<Project>{8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48}</Project>
|
||||
<Name>TBF</Name>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user