Skip to content

Commit

Permalink
improving error handling - chasing a customer issue
Browse files Browse the repository at this point in the history
  • Loading branch information
ctacke committed Oct 12, 2023
1 parent 77902be commit 26d783a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
29 changes: 22 additions & 7 deletions src/Meadow.Modbus/Clients/ModbusRtuClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,34 @@ protected override async Task<byte[]> 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)
{
// 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);
}

Expand Down Expand Up @@ -156,7 +168,7 @@ protected override async Task<byte[]> 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);
Expand All @@ -165,7 +177,10 @@ protected override async Task<byte[]> 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
Expand Down
20 changes: 18 additions & 2 deletions src/Meadow.Modbus/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,28 @@ namespace Meadow.Modbus;
/// </summary>
public class CrcException : Exception
{
/// <summary>
/// The expected CRC value
/// </summary>
public ushort ExpectedCrc { get; } = 0;
/// <summary>
/// The calculated CRC
/// </summary>
public ushort ActualCrc { get; } = 0;
/// <summary>
/// The message failing the CRC check
/// </summary>
public byte[] MessageBytes { get; } = default!;

/// <summary>
/// Initializes a new instance of the <see cref="CrcException"/> class with a default error message.
/// </summary>
internal CrcException()
: base("CRC Failure")
internal CrcException(string message, ushort expectedCrc, ushort actualCrc, byte[] messageBytes)
: base(message)
{
ExpectedCrc = expectedCrc;
ActualCrc = actualCrc;
MessageBytes = messageBytes;
}
}

Expand Down

0 comments on commit 26d783a

Please sign in to comment.