From 26d783ab6503c396d997cbecf52eefc379843223 Mon Sep 17 00:00:00 2001 From: Chris Tacke Date: Thu, 12 Oct 2023 09:52:51 -0500 Subject: [PATCH] improving error handling - chasing a customer issue --- src/Meadow.Modbus/Clients/ModbusRtuClient.cs | 29 +++++++++++++++----- src/Meadow.Modbus/Exceptions.cs | 20 ++++++++++++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Meadow.Modbus/Clients/ModbusRtuClient.cs b/src/Meadow.Modbus/Clients/ModbusRtuClient.cs index ad53cd8..f993ff5 100644 --- a/src/Meadow.Modbus/Clients/ModbusRtuClient.cs +++ b/src/Meadow.Modbus/Clients/ModbusRtuClient.cs @@ -101,7 +101,11 @@ protected override async Task ReadResult(ModbusFunction function) var header = new byte[headerLen]; // first read 3 bytes so we can look for an error - _port.Read(header, 0, 3); + var read = 0; + while (read < 3) + { + read += _port.Read(header, read, 3 - read); + } // check for an error bit (MSB in byte 2) if ((header[1] & 0x80) != 0) @@ -109,14 +113,22 @@ protected override async Task ReadResult(ModbusFunction function) // an error response has come back - read the remaining 2 bytes (CRC of the error) var errpacket = new byte[5]; Array.Copy(header, 0, errpacket, 0, 3); - _port.Read(errpacket, 3, 2); - expectedCrc = RtuHelpers.Crc(errpacket, 0, errpacket.Length - 2); - actualCrc = (ushort)(errpacket[errpacket.Length - 2] | errpacket[errpacket.Length - 1] << 8); - if (expectedCrc != actualCrc) { throw new CrcException(); } + read = 0; + while (read < 2) + { + _port.Read(errpacket, 3 + read, 2 - read); + } var errorCode = (ModbusErrorCode)errpacket[2]; + expectedCrc = RtuHelpers.Crc(errpacket, 0, errpacket.Length - 2); + actualCrc = (ushort)(errpacket[errpacket.Length - 2] | errpacket[errpacket.Length - 1] << 8); + if (expectedCrc != actualCrc) + { + throw new CrcException($"CRC error in {errorCode} message", expectedCrc, actualCrc, errpacket); + } + throw new ModbusException(errorCode, function); } @@ -156,7 +168,7 @@ protected override async Task ReadResult(ModbusFunction function) // the CRC includes the header, so we need those in the buffer Array.Copy(header, buffer, headerLen); - var read = headerLen; + read = headerLen; while (read < buffer.Length) { read += _port.Read(buffer, read, buffer.Length - read); @@ -165,7 +177,10 @@ protected override async Task ReadResult(ModbusFunction function) // do a CRC on all but the last 2 bytes, then see if that matches the last 2 expectedCrc = RtuHelpers.Crc(buffer, 0, buffer.Length - 2); actualCrc = (ushort)(buffer[buffer.Length - 2] | buffer[buffer.Length - 1] << 8); - if (expectedCrc != actualCrc) { throw new CrcException(); } + if (expectedCrc != actualCrc) + { + throw new CrcException("CRC error in response message", expectedCrc, actualCrc, buffer); + } if (resultLen == 0) { //happens on write multiples diff --git a/src/Meadow.Modbus/Exceptions.cs b/src/Meadow.Modbus/Exceptions.cs index 6d93251..1b25918 100644 --- a/src/Meadow.Modbus/Exceptions.cs +++ b/src/Meadow.Modbus/Exceptions.cs @@ -9,12 +9,28 @@ namespace Meadow.Modbus; /// public class CrcException : Exception { + /// + /// The expected CRC value + /// + public ushort ExpectedCrc { get; } = 0; + /// + /// The calculated CRC + /// + public ushort ActualCrc { get; } = 0; + /// + /// The message failing the CRC check + /// + public byte[] MessageBytes { get; } = default!; + /// /// Initializes a new instance of the class with a default error message. /// - internal CrcException() - : base("CRC Failure") + internal CrcException(string message, ushort expectedCrc, ushort actualCrc, byte[] messageBytes) + : base(message) { + ExpectedCrc = expectedCrc; + ActualCrc = actualCrc; + MessageBytes = messageBytes; } }