OPTHO FORMATING improve (ASIC,genesis)
Enhance iPerlHat protocol logging and error handling: add optical HEX formatting, improve diagnostic messages, and extend test command descriptions.
This commit is contained in:
parent
3488939995
commit
39941842d4
@ -2143,6 +2143,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
|
|||||||
var encoding = optoSerialPort?.Encoding ?? Encoding.ASCII;
|
var encoding = optoSerialPort?.Encoding ?? Encoding.ASCII;
|
||||||
byte[] bytes = encoding.GetBytes(line);
|
byte[] bytes = encoding.GetBytes(line);
|
||||||
log.Debug("ComPort: " + OptoComPortNr + " OPTHO RX ← " + HexFormatter.ToSerialHex(bytes));
|
log.Debug("ComPort: " + OptoComPortNr + " OPTHO RX ← " + HexFormatter.ToSerialHex(bytes));
|
||||||
|
log.Debug("ComPort: " + OptoComPortNr + " OPTHO ASCII ← " + line.Replace('\t', ' '));
|
||||||
|
|
||||||
var streamingDecode = new StreamingDecoder(true);
|
var streamingDecode = new StreamingDecoder(true);
|
||||||
streamingDecode.DecodeMsg(line);
|
streamingDecode.DecodeMsg(line);
|
||||||
|
|||||||
@ -1062,6 +1062,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
|
|||||||
|
|
||||||
byte[] bytes = optoSerialPort.Encoding.GetBytes(line);
|
byte[] bytes = optoSerialPort.Encoding.GetBytes(line);
|
||||||
log.Debug("ComPort: " + OptoComPortNr + " OPTHO RX ← " + HexFormatter.ToSerialHex(bytes));
|
log.Debug("ComPort: " + OptoComPortNr + " OPTHO RX ← " + HexFormatter.ToSerialHex(bytes));
|
||||||
|
log.Debug("ComPort: " + OptoComPortNr + " OPTHO ASCII ← " + line.Replace('\t', ' '));
|
||||||
|
|
||||||
if (optoState == DataStreamState.ProcessAndSave)
|
if (optoState == DataStreamState.ProcessAndSave)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -485,7 +485,11 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
string line = port.ReadLine(); // string
|
string line = port.ReadLine(); // string
|
||||||
byte[] bytes = port.Encoding.GetBytes(line);
|
byte[] bytes = port.Encoding.GetBytes(line);
|
||||||
|
|
||||||
Console.WriteLine("RX ← " + HexFormatter.ToSerialHex(bytes));
|
// Original byte-level output. Keep it for diagnostics.
|
||||||
|
Console.WriteLine( "RX ASCII bytes ← " + HexFormatter.ToSerialHex(bytes));
|
||||||
|
// Customer-compatible optical HEX packet.
|
||||||
|
string opticalHex = FormatOpticalHexPacket(line);
|
||||||
|
Console.WriteLine( "OPTO HEX ← " + opticalHex);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -532,18 +536,24 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
TestViewCalibration(port);
|
TestViewCalibration(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IperlHatResponse SendRequest(
|
private static IperlHatResponse SendRequest(
|
||||||
SerialPort port,
|
SerialPort port,
|
||||||
byte[] request,
|
byte[] request,
|
||||||
string commandName)
|
string commandName,
|
||||||
|
string commandDescription)
|
||||||
{
|
{
|
||||||
var parser = new IperlHatFrameParser();
|
var parser = new IperlHatFrameParser();
|
||||||
port.DiscardInBuffer();
|
|
||||||
|
|
||||||
Console.WriteLine( $"{commandName} TX → " + HexFormatter.ToSerialHexWithAscii(request));
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("==================================================");
|
||||||
|
Console.WriteLine($"Command : {commandName}");
|
||||||
|
Console.WriteLine($"Description : {commandDescription}");
|
||||||
|
Console.WriteLine($"TX packet : {HexFormatter.ToSerialHexWithAscii(request)}");
|
||||||
|
|
||||||
|
port.DiscardInBuffer();
|
||||||
port.Write(request, 0, request.Length);
|
port.Write(request, 0, request.Length);
|
||||||
|
|
||||||
byte[] response;
|
byte[] response;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -552,30 +562,74 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
}
|
}
|
||||||
catch (TimeoutException ex)
|
catch (TimeoutException ex)
|
||||||
{
|
{
|
||||||
Assert.Fail( $"{commandName}: Timeout while waiting for response. " + ex.Message);
|
Assert.Fail($"{commandName}: Timeout while waiting for response." +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"Description: {commandDescription}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"TX packet: {HexFormatter.ToSerialHexWithAscii(request)}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"Error: {ex.Message}");
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.IsNotNull( response, $"{commandName}: Response is null.");
|
Assert.IsNotNull(response,
|
||||||
Assert.IsTrue( response.Length > 0, $"{commandName}: Response is empty.");
|
$"{commandName}: Response is null. TX packet: {HexFormatter.ToSerialHexWithAscii(request)}");
|
||||||
|
|
||||||
Console.WriteLine( $"{commandName} RX ← " + HexFormatter.ToSerialHexWithAscii(response));
|
Assert.IsTrue(response.Length > 0,
|
||||||
|
$"{commandName}: Response is empty. TX packet: {HexFormatter.ToSerialHexWithAscii(request)}");
|
||||||
|
|
||||||
|
Console.WriteLine($"RX packet : {HexFormatter.ToSerialHexWithAscii(response)}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IperlHatResponse decoded = parser.Parse(response);
|
IperlHatResponse decoded = parser.Parse(response);
|
||||||
|
|
||||||
Assert.IsNotNull( decoded, $"{commandName}: Parser returned null.");
|
Assert.IsNotNull(
|
||||||
Assert.IsTrue( decoded.IsOk, $"{commandName}: Device returned NOK. " + $"Payload={BitConverter.ToString(decoded.Payload ?? new byte[0])}");
|
decoded,
|
||||||
|
$"{commandName}: Parser returned null." +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"TX packet: {HexFormatter.ToSerialHexWithAscii(request)}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"RX packet: {HexFormatter.ToSerialHexWithAscii(response)}");
|
||||||
|
|
||||||
|
Assert.IsTrue(
|
||||||
|
decoded.IsOk,
|
||||||
|
$"{commandName}: Device returned NOK." +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"TX packet: {HexFormatter.ToSerialHexWithAscii(request)}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"RX packet: {HexFormatter.ToSerialHexWithAscii(response)}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"Payload: {BitConverter.ToString(decoded.Payload ?? new byte[0])}");
|
||||||
|
|
||||||
|
Console.WriteLine($"Result : OK");
|
||||||
|
Console.WriteLine($"Payload : {BitConverter.ToString(decoded.Payload ?? new byte[0])}");
|
||||||
|
|
||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
|
catch (AssertFailedException)
|
||||||
|
{
|
||||||
|
// Zachová pôvodnú a podrobnejšiu Assert chybu.
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Assert.Fail( $"{commandName}: Response frame could not be parsed. " + $"Frame={BitConverter.ToString(response)}. Error={ex}");
|
Assert.Fail(
|
||||||
|
$"{commandName}: Response frame could not be parsed." +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"Description: {commandDescription}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"TX packet: {HexFormatter.ToSerialHexWithAscii(request)}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"RX packet: {HexFormatter.ToSerialHexWithAscii(response)}" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"Error: {ex}");
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TestViewVersionAndType(
|
private static void TestViewVersionAndType(
|
||||||
SerialPort port)
|
SerialPort port)
|
||||||
{
|
{
|
||||||
@ -587,7 +641,8 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
IperlHatResponse response = SendRequest(
|
IperlHatResponse response = SendRequest(
|
||||||
port,
|
port,
|
||||||
request,
|
request,
|
||||||
nameof(ProtocolCommand.ViewVersionAndType));
|
nameof(ProtocolCommand.ViewVersionAndType),
|
||||||
|
"Reads the TouchRead version, meter device type and meter firmware version.");
|
||||||
|
|
||||||
Assert.IsNotNull( response.Payload, "ViewVersionAndType: Payload is null.");
|
Assert.IsNotNull( response.Payload, "ViewVersionAndType: Payload is null.");
|
||||||
Assert.IsTrue( response.Payload.Length > 0, "ViewVersionAndType: Payload is empty.");
|
Assert.IsTrue( response.Payload.Length > 0, "ViewVersionAndType: Payload is empty.");
|
||||||
@ -613,7 +668,12 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
.AddCommand(ProtocolCommand.ViewReadingUnits)
|
.AddCommand(ProtocolCommand.ViewReadingUnits)
|
||||||
.BuildBytes();
|
.BuildBytes();
|
||||||
|
|
||||||
IperlHatResponse response = SendRequest( port, request, nameof(ProtocolCommand.ViewReadingUnits));
|
IperlHatResponse response = SendRequest(
|
||||||
|
port,
|
||||||
|
request,
|
||||||
|
nameof(ProtocolCommand.ViewReadingUnits),
|
||||||
|
"Reads the measurement units currently configured in the meter.");
|
||||||
|
|
||||||
ReadingUnits units = response.GetResponse<ReadingUnits>(out bool responseOk);
|
ReadingUnits units = response.GetResponse<ReadingUnits>(out bool responseOk);
|
||||||
|
|
||||||
Assert.IsTrue( responseOk, $"ViewReadingUnits: Invalid payload. Payload={BitConverter.ToString(response.Payload ?? new byte[0])}");
|
Assert.IsTrue( responseOk, $"ViewReadingUnits: Invalid payload. Payload={BitConverter.ToString(response.Payload ?? new byte[0])}");
|
||||||
@ -632,7 +692,8 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
IperlHatResponse response = SendRequest(
|
IperlHatResponse response = SendRequest(
|
||||||
port,
|
port,
|
||||||
request,
|
request,
|
||||||
nameof(ProtocolDeviceSubCommand.ViewFlipMode));
|
nameof(ProtocolDeviceSubCommand.ViewFlipMode),
|
||||||
|
"Reads the current display flip mode.");
|
||||||
|
|
||||||
FlipMode flipMode = response.GetResponse<FlipMode>(out bool responseOk);
|
FlipMode flipMode = response.GetResponse<FlipMode>(out bool responseOk);
|
||||||
|
|
||||||
@ -649,7 +710,11 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
.AddDeviceCommand(ProtocolDeviceSubCommand.ViewCalibration)
|
.AddDeviceCommand(ProtocolDeviceSubCommand.ViewCalibration)
|
||||||
.BuildBytes();
|
.BuildBytes();
|
||||||
|
|
||||||
IperlHatResponse response = SendRequest( port, request, nameof(ProtocolDeviceSubCommand.ViewCalibration));
|
IperlHatResponse response = SendRequest(
|
||||||
|
port,
|
||||||
|
request,
|
||||||
|
nameof(ProtocolDeviceSubCommand.ViewCalibration),
|
||||||
|
"Reads the raw two-byte calibration factor used to calculate the calibration percentage.");
|
||||||
|
|
||||||
ushort rawValue = response.GetUInt16LittleEndian(out bool responseOk);
|
ushort rawValue = response.GetUInt16LittleEndian(out bool responseOk);
|
||||||
|
|
||||||
@ -665,5 +730,51 @@ namespace TBFTests.Rig.RegisterReaders.iPerlASICReader.communication.C4.IperlHat
|
|||||||
Assert.IsTrue( rawValue > 0, "ViewCalibration: Calibration factor must be greater than zero.");
|
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.");
|
Assert.IsTrue( percentage > 0.0, "ViewCalibration: Calculated percentage must be greater than zero.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string FormatOpticalHexPacket(string asciiPacket)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(asciiPacket))
|
||||||
|
throw new FormatException("Optical packet is empty.");
|
||||||
|
|
||||||
|
string[] fields = asciiPacket.Split(
|
||||||
|
new[] { ' ', '\t', '\r', '\n' },
|
||||||
|
StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
for (int i = 0; i < fields.Length; i++)
|
||||||
|
{
|
||||||
|
string field = fields[i].Trim();
|
||||||
|
|
||||||
|
if (!IsHexadecimal(field))
|
||||||
|
{
|
||||||
|
throw new FormatException(
|
||||||
|
$"Optical packet contains a non-HEX field at index {i}: '{field}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fields[i] = field.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(" ", fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsHexadecimal(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
{
|
||||||
|
char c = value[i];
|
||||||
|
|
||||||
|
bool isHexDigit =
|
||||||
|
(c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'A' && c <= 'F') ||
|
||||||
|
(c >= 'a' && c <= 'f');
|
||||||
|
|
||||||
|
if (!isHexDigit)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user