diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ReadingUnits.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ReadingUnits.cs index 7fb0aece4..9cbcfa563 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ReadingUnits.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/ReadingUnits.cs @@ -4,6 +4,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommon { CubicMeters = 0x00, CubicFeet = 0x01, - UsGallons = 0x02 + UsGallons = 0x02, + UsGallons1 = 0x04, + UsGallons2 = 0x08, + UsGallons3 = 0x10, } } \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/VersionTypeResult.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/VersionTypeResult.cs index dd8b07815..692ea7e08 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/VersionTypeResult.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/C4/protocolCommons/VersionTypeResult.cs @@ -2,58 +2,134 @@ using System.Text.RegularExpressions; namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons { - public class VersionTypeResult + using System; +using System.Text.RegularExpressions; + + namespace TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol { - public string TouchReadVersion { get; set; } - public string MeterDeviceType { get; set; } - public string MeterFirmwareVersion { get; set; } - - public override string ToString() + public class VersionTypeResult { - return $"TouchReadVersion={TouchReadVersion}, " + - $"MeterDeviceType={MeterDeviceType}, " + - $"MeterFirmwareVersion={MeterFirmwareVersion}"; - } - - - public static VersionTypeResult ParseVersionTypePayload(string payload) - { - if (string.IsNullOrWhiteSpace(payload)) - return null; + public string TouchReadVersion { get; set; } - // Example: - // vers: Harry T:B800, V:06.06.01, FW:190215, - // 7ECE, B1.6.01, HW:4, Serial:0 + public string MeterDeviceType { get; set; } - string meterDeviceType = GetPayloadValue(payload, "T"); - string touchReadVersion = GetPayloadValue(payload, "V"); - string meterFirmwareVersion = GetPayloadValue(payload, "FW"); + public string MeterFirmwareVersion { get; set; } - if (string.IsNullOrWhiteSpace(meterDeviceType) && - string.IsNullOrWhiteSpace(touchReadVersion) && - string.IsNullOrWhiteSpace(meterFirmwareVersion)) + public static VersionTypeResult ParseVersionTypePayload( + string payload) { - return null; + if (string.IsNullOrWhiteSpace(payload)) + { + return null; + } + + string normalizedPayload = payload + .Trim('\0', '\r', '\n', ' '); + + VersionTypeResult result = + ParseCompactPayload(normalizedPayload); + + if (result != null) + { + return result; + } + + return ParseLegacyPayload(normalizedPayload); } - return new VersionTypeResult + private static VersionTypeResult ParseCompactPayload( + string payload) { - MeterDeviceType = meterDeviceType, - TouchReadVersion = touchReadVersion, - MeterFirmwareVersion = meterFirmwareVersion - }; - } + // Expected format: + // B1.23,SWM004,1.00 - private static string GetPayloadValue(string payload, string key) - { - Match match = Regex.Match( - payload, - @"(?:^|[\s,])" + Regex.Escape(key) + @":\s*([^,\s]+)", - RegexOptions.IgnoreCase); + string[] parts = payload.Split(','); - return match.Success - ? match.Groups[1].Value.Trim() - : null; + if (parts.Length != 3) + { + return null; + } + + string touchReadVersion = parts[0].Trim(); + string meterDeviceType = parts[1].Trim(); + string meterFirmwareVersion = parts[2].Trim(); + + if (string.IsNullOrWhiteSpace(touchReadVersion) || + string.IsNullOrWhiteSpace(meterDeviceType) || + string.IsNullOrWhiteSpace(meterFirmwareVersion)) + { + return null; + } + + return new VersionTypeResult + { + TouchReadVersion = touchReadVersion, + MeterDeviceType = meterDeviceType, + MeterFirmwareVersion = meterFirmwareVersion + }; + } + + private static VersionTypeResult ParseLegacyPayload( + string payload) + { + // Expected example: + // + // vers: Harry T:B800, V:06.06.01, FW:190215, + // 7ECE, B1.6.01, HW:4, Serial:0 + + Match deviceTypeMatch = Regex.Match( + payload, + @"(?:^|[\s,])T\s*:\s*([^,\s]+)", + RegexOptions.IgnoreCase); + + Match versionMatch = Regex.Match( + payload, + @"(?:^|[\s,])V\s*:\s*([^,\s]+)", + RegexOptions.IgnoreCase); + + Match firmwareMatch = Regex.Match( + payload, + @"(?:^|[\s,])FW\s*:\s*([^,\s]+)", + RegexOptions.IgnoreCase); + + if (!deviceTypeMatch.Success || + !versionMatch.Success || + !firmwareMatch.Success) + { + return null; + } + + string meterDeviceType = + deviceTypeMatch.Groups[1].Value.Trim(); + + string touchReadVersion = + versionMatch.Groups[1].Value.Trim(); + + string meterFirmwareVersion = + firmwareMatch.Groups[1].Value.Trim(); + + if (string.IsNullOrWhiteSpace(touchReadVersion) || + string.IsNullOrWhiteSpace(meterDeviceType) || + string.IsNullOrWhiteSpace(meterFirmwareVersion)) + { + return null; + } + + return new VersionTypeResult + { + TouchReadVersion = touchReadVersion, + MeterDeviceType = meterDeviceType, + MeterFirmwareVersion = meterFirmwareVersion + }; + } + + public override string ToString() + { + return + $"TouchReadVersion={TouchReadVersion}, " + + $"MeterDeviceType={MeterDeviceType}, " + + $"MeterFirmwareVersion={MeterFirmwareVersion}"; + } } } } \ No newline at end of file diff --git a/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs b/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs index a70fa75f2..9055f0853 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/communication/RadioService.cs @@ -5,6 +5,7 @@ using log4net; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons.TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol; using TBF.Rig.TestMethods.iPerlCommunication.communication.Utils; using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; diff --git a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/IperlHatProtocol/IperlHatIntegrationTests.cs b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/IperlHatProtocol/IperlHatIntegrationTests.cs index 1e0a73c06..7475c2bd7 100644 --- a/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/IperlHatProtocol/IperlHatIntegrationTests.cs +++ b/TBFTests/Rig/RegisterReaders/iPerlASICReader/communication/C4/IperlHatProtocol/IperlHatIntegrationTests.cs @@ -9,6 +9,7 @@ using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.pars using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.hexLogger; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons.TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHatProtocol @@ -16,7 +17,8 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat [TestClass] public class IperlHatIntegrationTests { - private const string ComPort = "COM3"; // CHANGE THIS + private const string ComPort = "COM12"; // CHANGE THIS + private const string ComPortOptho = "COM13"; private const int BaudRate = 2400; private const int BaudRateOpto = 38400; private const int ReadTimeoutMs = 2000; @@ -461,7 +463,7 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat //method test connection to optho head private void Serial_OptoRawSniff() { - using (var port = new SerialPort("COM4", BaudRateOpto, Parity.None, 8, StopBits.One)) + using (var port = new SerialPort(ComPortOptho, BaudRateOpto, Parity.None, 8, StopBits.One)) { port.Handshake = Handshake.None; port.ReadTimeout = 10000; @@ -506,5 +508,163 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat } } + + // ---- NEXT COMMUNICATION ---- + + [TestMethod] + [TestCategory("Hardware")] + [TestCategory("Serial")] + public void Serial_ViewConfigurationCommands_ReturnValidResponses() + { + using (var port = new SerialPort( + ComPort, + BaudRate, + Parity.None, + 8, + StopBits.One)) + { + port.Handshake = Handshake.None; + port.ReadTimeout = 5000; + port.Open(); + + TestViewVersionAndType(port); + TestViewReadingUnits(port); + TestViewFlipMode(port); + TestViewCalibration(port); + } + } + + private static IperlHatResponse SendRequest( + SerialPort port, + byte[] request, + string commandName) + { + var parser = new IperlHatFrameParser(); + port.DiscardInBuffer(); + + Console.WriteLine( $"{commandName} TX → " + HexFormatter.ToSerialHexWithAscii(request)); + port.Write(request, 0, request.Length); + + byte[] response; + + try + { + response = ReadResponse(port); + } + catch (TimeoutException ex) + { + Assert.Fail( $"{commandName}: Timeout while waiting for response. " + ex.Message); + return null; + } + + Assert.IsNotNull( response, $"{commandName}: Response is null."); + Assert.IsTrue( response.Length > 0, $"{commandName}: Response is empty."); + + Console.WriteLine( $"{commandName} RX ← " + HexFormatter.ToSerialHexWithAscii(response)); + + try + { + IperlHatResponse decoded = parser.Parse(response); + + Assert.IsNotNull( decoded, $"{commandName}: Parser returned null."); + Assert.IsTrue( decoded.IsOk, $"{commandName}: Device returned NOK. " + $"Payload={BitConverter.ToString(decoded.Payload ?? new byte[0])}"); + return decoded; + } + catch (Exception ex) + { + Assert.Fail( $"{commandName}: Response frame could not be parsed. " + $"Frame={BitConverter.ToString(response)}. Error={ex}"); + return null; + } + } + + private static void TestViewVersionAndType( + SerialPort port) + { + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.ViewVersionAndType) + .BuildBytes(); + + IperlHatResponse response = SendRequest( + port, + request, + nameof(ProtocolCommand.ViewVersionAndType)); + + Assert.IsNotNull( response.Payload, "ViewVersionAndType: Payload is null."); + Assert.IsTrue( response.Payload.Length > 0, "ViewVersionAndType: Payload is empty."); + + string payloadText = Encoding.ASCII.GetString(response.Payload).Trim('\0', '\r', '\n', ' '); + + Console.WriteLine( "ViewVersionAndType payload: " + payloadText); + + VersionTypeResult result = VersionTypeResult.ParseVersionTypePayload(payloadText); + + Assert.IsNotNull( result, "ViewVersionAndType: Payload cannot be parsed. " + $"Payload='{payloadText}'"); + Assert.IsFalse( string.IsNullOrWhiteSpace(result.TouchReadVersion), "ViewVersionAndType: TouchReadVersion is empty."); + Assert.IsFalse( string.IsNullOrWhiteSpace(result.MeterDeviceType), "ViewVersionAndType: MeterDeviceType is empty."); + Assert.IsFalse( string.IsNullOrWhiteSpace(result.MeterFirmwareVersion), "ViewVersionAndType: MeterFirmwareVersion is empty."); + + Console.WriteLine( "ViewVersionAndType result: " + result); + } + + private static void TestViewReadingUnits(SerialPort port) + { + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddCommand(ProtocolCommand.ViewReadingUnits) + .BuildBytes(); + + IperlHatResponse response = SendRequest( port, request, nameof(ProtocolCommand.ViewReadingUnits)); + ReadingUnits units = response.GetResponse(out bool responseOk); + + Assert.IsTrue( responseOk, $"ViewReadingUnits: Invalid payload. Payload={BitConverter.ToString(response.Payload ?? new byte[0])}"); + + Assert.IsTrue( Enum.IsDefined(typeof(ReadingUnits), units), $"ViewReadingUnits: Unknown value 0x{Convert.ToByte(units):X2}."); + Console.WriteLine( $"ViewReadingUnits result: {units} " + $"(0x{Convert.ToByte(units):X2})"); + } + + private static void TestViewFlipMode(SerialPort port) + { + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddDeviceCommand(ProtocolDeviceSubCommand.ViewFlipMode) + .BuildBytes(); + + IperlHatResponse response = SendRequest( + port, + request, + nameof(ProtocolDeviceSubCommand.ViewFlipMode)); + + FlipMode flipMode = response.GetResponse(out bool responseOk); + + Assert.IsTrue( responseOk, $"ViewFlipMode: Invalid payload. Payload={BitConverter.ToString(response.Payload ?? new byte[0])}"); + Assert.IsTrue( Enum.IsDefined(typeof(FlipMode), flipMode),$"ViewFlipMode: Unknown value 0x{Convert.ToByte(flipMode):X2}."); + + Console.WriteLine( $"ViewFlipMode result: {flipMode} (0x{Convert.ToByte(flipMode):X2})"); + } + + private static void TestViewCalibration(SerialPort port) + { + byte[] request = new IperlHatFrameBuilder() + .RequestResponse(true) + .AddDeviceCommand(ProtocolDeviceSubCommand.ViewCalibration) + .BuildBytes(); + + IperlHatResponse response = SendRequest( port, request, nameof(ProtocolDeviceSubCommand.ViewCalibration)); + + ushort rawValue = response.GetUInt16LittleEndian(out bool responseOk); + + Assert.IsTrue( responseOk, "ViewCalibration: Expected a two-byte little-endian payload. " + + $"Payload={BitConverter.ToString(response.Payload ?? new byte[0])}"); + + double percentage = rawValue * 100.0 / 4096.0; + double correctionPercentage = percentage - 100.0; + + Console.WriteLine( $"ViewCalibration result: RawValue={rawValue}, Percentage={percentage:F4} %, " + + $"Correction={correctionPercentage:+0.0000;-0.0000;0.0000} %"); + + Assert.IsTrue( rawValue > 0, "ViewCalibration: Calibration factor must be greater than zero."); + Assert.IsTrue( percentage > 0.0, "ViewCalibration: Calculated percentage must be greater than zero."); + } } } \ No newline at end of file diff --git a/TBFTests/Rig/TestMethods/iPerlCommunication/communication/RadioServiceTest.cs b/TBFTests/Rig/TestMethods/iPerlCommunication/communication/RadioServiceTest.cs index 3d0467761..a14e56136 100644 --- a/TBFTests/Rig/TestMethods/iPerlCommunication/communication/RadioServiceTest.cs +++ b/TBFTests/Rig/TestMethods/iPerlCommunication/communication/RadioServiceTest.cs @@ -5,6 +5,7 @@ using TBF.Rig.TestMethods.iPerlCommunication.communication; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons; +using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.protocolCommons.TBF.Rig.TestMethods.iPerlCommunication.communication.C4.IperlHatProtocol; using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.wiredProtocol; using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead; @@ -47,23 +48,14 @@ namespace TBFTests.Rig.TestMethods.iPerlCommunication.communication IperlResponseFactory.CreateVersionResponse(responseText); // Act - VersionTypeResult result = - service.SetViewVersionAndType(head); + VersionTypeResult result = service.SetViewVersionAndType(head); // Assert Assert.IsNotNull(result); - Assert.AreEqual( - "B800", - result.MeterDeviceType); - - Assert.AreEqual( - "06.06.01", - result.TouchReadVersion); - - Assert.AreEqual( - "190215", - result.MeterFirmwareVersion); + Assert.AreEqual( "B800", result.MeterDeviceType); + Assert.AreEqual( "06.06.01", result.TouchReadVersion); + Assert.AreEqual( "190215", result.MeterFirmwareVersion); Assert.AreEqual(1, serialDriver.SendAndWaitCallCount); Assert.AreEqual(5000, serialDriver.LastTimeout);