Refactor Genesis serial communication handling (ISerialDriver interface compatible with SerialPort):
- Replace method-based `IsOpen()` checks with property-based `IsOpen` usage in `ISerialDriver` and related classes. - Simplify `Open()` and add `Close()` methods to unify connection management. - Introduce `InitializeThreeChannelState()` helper in `GenesisSmartReaderTest` for multi-channel state initialization. - Adjust calculations in `CalculateTimeByChannels()` and `CalculateVolumeByChannels()` for clarity. - Add new tests for multi-channel processing and validation of updated telegram handling logic.
This commit is contained in:
parent
e26d88d437
commit
a5a68ec457
@ -5,8 +5,9 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
{
|
||||
public interface ISerialDriver : IDisposable
|
||||
{
|
||||
bool IsOpen();
|
||||
bool Open();
|
||||
bool IsOpen { get; }
|
||||
void Open();
|
||||
void Close();
|
||||
void CloseConnection();
|
||||
|
||||
void DiscardInBuffer();
|
||||
|
||||
@ -68,9 +68,9 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
_discardOutBufferOnOpen = discardOutBufferOnOpen;
|
||||
}
|
||||
|
||||
public bool Open()
|
||||
public void Open()
|
||||
{
|
||||
return OpenConnection(
|
||||
OpenConnection(
|
||||
_portName,
|
||||
_baudRate,
|
||||
_dataBits,
|
||||
@ -188,6 +188,11 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
public void CloseConnection()
|
||||
{
|
||||
if (_serialPort != null)
|
||||
@ -200,7 +205,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOpen() => _serialPort?.IsOpen == true;
|
||||
public bool IsOpen => _serialPort?.IsOpen == true;
|
||||
|
||||
public void DiscardInBuffer()
|
||||
{
|
||||
@ -216,7 +221,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
|
||||
public string ReadExisting()
|
||||
{
|
||||
if (!IsOpen())
|
||||
if (!IsOpen)
|
||||
throw new InvalidOperationException("Serial port not open");
|
||||
|
||||
return _serialPort.ReadExisting();
|
||||
@ -230,7 +235,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
|
||||
public string ReadLine()
|
||||
{
|
||||
if (!IsOpen())
|
||||
if (!IsOpen)
|
||||
throw new InvalidOperationException("Serial port not open");
|
||||
|
||||
return _serialPort.ReadLine();
|
||||
@ -238,7 +243,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
|
||||
public string ReadLine(int timeoutMs)
|
||||
{
|
||||
if (!IsOpen())
|
||||
if (!IsOpen)
|
||||
throw new InvalidOperationException("Serial port not open");
|
||||
|
||||
int originalTimeout = _serialPort.ReadTimeout;
|
||||
@ -256,7 +261,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
|
||||
public bool SendMessage(byte[] sendDataBytes, int length, int readTimeout = 1000, int writeTimeout = 1000)
|
||||
{
|
||||
if (!IsOpen()) return false;
|
||||
if (!IsOpen) return false;
|
||||
if (sendDataBytes == null || sendDataBytes.Length == 0) return true;
|
||||
|
||||
try
|
||||
@ -275,7 +280,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
|
||||
public byte[] SendAndWait(byte[] data, int timeoutMs)
|
||||
{
|
||||
if (!IsOpen())
|
||||
if (!IsOpen)
|
||||
throw new InvalidOperationException("Serial port not open");
|
||||
|
||||
try
|
||||
|
||||
@ -175,7 +175,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
|
||||
public SerialDriver BuildAndOpen()
|
||||
{
|
||||
var driver = Build();
|
||||
if (!driver.Open())
|
||||
driver.Open();
|
||||
if (!driver.IsOpen)
|
||||
{
|
||||
throw new InvalidOperationException(driver.ErrorMessage);
|
||||
}
|
||||
|
||||
@ -962,13 +962,13 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
private double CalculateTimeByChannels()
|
||||
{
|
||||
double[] timestampSec = new double[iChanelsCount];
|
||||
double[] timeDelta = new double[iChanelsCount];
|
||||
for (int iChanel = 0; iChanel < iChanelsCount; iChanel++)
|
||||
{
|
||||
timestampSec[iChanel] = timestampSec[iChanel] - timestampSec0[iChanel];
|
||||
timeDelta[iChanel] = this.timestampSec[iChanel] - this.timestampSec0[iChanel];
|
||||
}
|
||||
|
||||
return Average(timestampSec);
|
||||
|
||||
return Average(timeDelta);
|
||||
}
|
||||
|
||||
private double CalculateVolumeByChannels()
|
||||
@ -976,7 +976,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
double[] volumeDelta = new double[iChanelsCount];
|
||||
for (int iChanel = 0; iChanel < iChanelsCount; iChanel++)
|
||||
{
|
||||
volumeDelta[iChanel] = volumeLtr[iChanel] - volumeLtr0[iChanel];
|
||||
volumeDelta[iChanel] = this.volumeLtr[iChanel] - this.volumeLtr0[iChanel];
|
||||
}
|
||||
|
||||
return Average(volumeDelta);
|
||||
@ -1008,7 +1008,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
if (_serialFactory != null)
|
||||
{
|
||||
optoSerialPort = _serialFactory();
|
||||
if (!optoSerialPort.Open())
|
||||
optoSerialPort.Open();
|
||||
if (!optoSerialPort.IsOpen)
|
||||
throw new InvalidOperationException("Failed to open injected serial driver.");
|
||||
}
|
||||
else
|
||||
@ -1045,7 +1046,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
if (optoSerialPort != null)
|
||||
{
|
||||
optoSerialPort.CloseConnection();
|
||||
optoSerialPort.Close();
|
||||
optoSerialPort = null;
|
||||
log.FatalFormat($"{Name} OptoPort closed: {this}");
|
||||
}
|
||||
@ -1076,7 +1077,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
endTelegramIdx3 = 0;
|
||||
TestEndTelegramIx = 0;
|
||||
|
||||
if (optoSerialPort != null && optoSerialPort.IsOpen()) optoSerialPort.DiscardInBuffer();
|
||||
if (optoSerialPort != null && optoSerialPort.IsOpen) optoSerialPort.DiscardInBuffer();
|
||||
|
||||
if (flowDirectionDetection != null) flowDirectionDetection.ClearFifo(); /// Clear FIFO for flow direction detection
|
||||
|
||||
@ -1853,10 +1854,10 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
public async Task<double> DataEntry_EndVolumeAsync()
|
||||
{
|
||||
|
||||
if (optoSerialPort == null || !optoSerialPort.IsOpen())
|
||||
if (optoSerialPort == null || !optoSerialPort.IsOpen)
|
||||
{
|
||||
StartDataStreamProcessing();
|
||||
if (optoSerialPort == null || !optoSerialPort.IsOpen())
|
||||
if (optoSerialPort == null || !optoSerialPort.IsOpen)
|
||||
{
|
||||
log.Error($"optoSerialPort COM: {this.OptoComPortNr} is not open - DataEntry_EndVolumeAsync()");
|
||||
return Double.NaN;
|
||||
@ -1900,7 +1901,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
|
||||
log.Debug($"Try get End Volume! COM: {this.OptoComPortNr}, Volume: {volumeLtr}");
|
||||
if (optoSerialPort != null && optoSerialPort.IsOpen()) CloseOptoSerialPort();
|
||||
if (optoSerialPort != null && optoSerialPort.IsOpen) CloseOptoSerialPort();
|
||||
|
||||
if (!Double.IsNaN(volumeLtr[channel0]))
|
||||
{
|
||||
@ -1975,7 +1976,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
}
|
||||
|
||||
log.Debug($"Try get Start Volume! COM: {this.OptoComPortNr}, Volume: {volumeLtr0}");
|
||||
if (optoSerialPort != null && optoSerialPort.IsOpen()) CloseOptoSerialPort();
|
||||
if (optoSerialPort != null && optoSerialPort.IsOpen) CloseOptoSerialPort();
|
||||
|
||||
if (!Double.IsNaN(volumeLtr0[channel0]))
|
||||
{
|
||||
|
||||
@ -24,13 +24,17 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
public void EnqueueLine(string line) => _lines.Enqueue(line);
|
||||
|
||||
public bool IsOpen() => _isOpen;
|
||||
public bool IsOpen => _isOpen;
|
||||
|
||||
public bool Open()
|
||||
public void Open()
|
||||
{
|
||||
OpenCalls++;
|
||||
_isOpen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
public void CloseConnection()
|
||||
|
||||
@ -6,34 +6,18 @@ using TBF.Rig;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader;
|
||||
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
||||
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
{
|
||||
[TestClass]
|
||||
[TestSubject(typeof(GenesisSmartReader))]
|
||||
public class GenesisSmartReaderTest
|
||||
{
|
||||
|
||||
private const int ChannelCount = 3;
|
||||
|
||||
private static GenesisCfg CreateCfg()
|
||||
{
|
||||
Factory factory = new Factory();
|
||||
|
||||
return new GenesisCfg(factory);
|
||||
// {
|
||||
// OptoComPortNr = 7,
|
||||
// RfidComPortNr = 8,
|
||||
// MuxBoardNr = 1,
|
||||
// Group = 1,
|
||||
// CommunicationInterface = CommunicationInterface.RFID,
|
||||
// ProcParams = new ProcParams
|
||||
// {
|
||||
// CalibTarget = 0,
|
||||
// FactorLimitLo = 0,
|
||||
// FactorLimitHi = 65535,
|
||||
// Counting = Counting.Arbitrary
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
private static void SetPrivateField(object target, string fieldName, object value)
|
||||
@ -54,6 +38,21 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
return (T)field.GetValue(target);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Start_ShouldOpenPort_AndEnableProcessing()
|
||||
{
|
||||
@ -62,8 +61,8 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
|
||||
reader.Initialize();
|
||||
reader.Start();
|
||||
|
||||
Assert.IsTrue(fake.IsOpen());
|
||||
|
||||
Assert.IsTrue(fake.IsOpen);
|
||||
Assert.IsTrue(fake.OpenCalls >= 1);
|
||||
Assert.AreEqual(1, fake.DiscardInCalls);
|
||||
}
|
||||
@ -77,11 +76,11 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.Initialize();
|
||||
reader.Start();
|
||||
|
||||
Assert.IsTrue(fake.IsOpen());
|
||||
Assert.IsTrue(fake.IsOpen);
|
||||
|
||||
reader.Stop();
|
||||
|
||||
Assert.IsFalse(fake.IsOpen());
|
||||
Assert.IsFalse(fake.IsOpen);
|
||||
Assert.AreEqual(2, fake.CloseCalls);
|
||||
}
|
||||
|
||||
@ -96,11 +95,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
SetPrivateField(reader, "currentTelegramIx", 12);
|
||||
SetPrivateField(reader, "timeFromStart", 7);
|
||||
|
||||
// prevent ReadPulses() from crashing if needed
|
||||
SetPrivateField(reader, "volumeLtr", 0.0);
|
||||
SetPrivateField(reader, "volumeLtr0", 0.0);
|
||||
SetPrivateField(reader, "timestampSec", 0.0);
|
||||
SetPrivateField(reader, "timestampSec0", 0.0);
|
||||
InitializeThreeChannelState(reader);
|
||||
|
||||
var ev = reader.Run();
|
||||
|
||||
@ -115,17 +110,13 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
InitializeThreeChannelState(reader);
|
||||
|
||||
// Important if these arrays are not initialized elsewhere
|
||||
SetPrivateField(reader, "volumeRawExtLast", new double[3]);
|
||||
SetPrivateField(reader, "timestampExtLast", new double[3]);
|
||||
|
||||
// valid sample line for your protocol
|
||||
var line = "FFFFFE\t51EA\t0000\t65324E\t0087\tF6319DFF\t86";
|
||||
var line = "@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331";
|
||||
|
||||
reader.optoSerialPort = fake;
|
||||
fake.Open();
|
||||
|
||||
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
||||
|
||||
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
|
||||
@ -145,19 +136,69 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
||||
reader.Initialize();
|
||||
|
||||
reader.optoSerialPort = fake;
|
||||
|
||||
SetPrivateField(reader, "volumeRawExtLast", new double[3]);
|
||||
SetPrivateField(reader, "timestampExtLast", new double[3]);
|
||||
InitializeThreeChannelState(reader);
|
||||
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
||||
|
||||
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
|
||||
var timestampExtLast = GetPrivateField<double[]>(reader, "timestampExtLast");
|
||||
|
||||
Assert.IsTrue(
|
||||
volumeRawExtLast[expectedChannelIndex] != 0 ||
|
||||
timestampExtLast[expectedChannelIndex] != 0,
|
||||
$"Channel {expectedChannelIndex} was not updated");
|
||||
for (int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
if (i == expectedChannelIndex)
|
||||
{
|
||||
Assert.IsTrue(
|
||||
volumeRawExtLast[i] != 0 || timestampExtLast[i] != 0,
|
||||
$"Channel {i} was expected to be updated, but it was not.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(0.0, volumeRawExtLast[i], $"Unexpected volume update in channel {i}");
|
||||
Assert.AreEqual(0.0, timestampExtLast[i], $"Unexpected timestamp update in channel {i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Run_WhenChannel0IsAverageModeMinus2_ShouldReadUsingAllThreeChannels()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
|
||||
reader.Initialize();
|
||||
reader.Start();
|
||||
|
||||
SetPrivateField(reader, "channel0", -2);
|
||||
SetPrivateField(reader, "volumeLtr0", new[] { 10.0, 20.0, 30.0 });
|
||||
SetPrivateField(reader, "volumeLtr", new[] { 13.0, 24.0, 35.0 });
|
||||
SetPrivateField(reader, "timestampSec0", new[] { 100.0, 100.0, 100.0 });
|
||||
SetPrivateField(reader, "timestampSec", new[] { 110.0, 112.0, 114.0 });
|
||||
|
||||
var ev = reader.Run();
|
||||
|
||||
Assert.AreEqual(Event.ReadRegisterDone, ev);
|
||||
Assert.AreEqual(4.0, reader.WMVolume, 1E-6); // average of (3, 4, 5)
|
||||
Assert.AreEqual(4000, reader.WMPulses);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessOptoLine_FirstValidTelegram_ShouldSetCurrentTelegramIndex()
|
||||
{
|
||||
var fake = new FakeSerialDriver();
|
||||
fake.Open();
|
||||
|
||||
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
||||
reader.Initialize();
|
||||
|
||||
reader.optoSerialPort = fake;
|
||||
InitializeThreeChannelState(reader);
|
||||
|
||||
var line = "@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD";
|
||||
|
||||
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave);
|
||||
|
||||
int currentTelegramIx = GetPrivateField<int>(reader, "currentTelegramIx");
|
||||
Assert.AreEqual(0, currentTelegramIx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user