review(Driver.Modbus): validate FC03 RMW response + correct write error mapping
Re-review at 7286d320. Modbus-013 (Low): bit RMW now routes the FC03 read through the
validated ReadRegisterBlockAsync (was raw-indexing readResp -> IndexOutOfRange on a truncated
PDU). Modbus-014 (Low): WriteAsync maps InvalidDataException to BadCommunicationError (was
BadInternalError), matching ReadAsync. + TDD.
This commit is contained in:
@@ -987,6 +987,14 @@ public sealed class ModbusDriver
|
||||
{
|
||||
results[i] = new WriteResult(MapModbusExceptionToStatus(mex.ExceptionCode));
|
||||
}
|
||||
catch (InvalidDataException)
|
||||
{
|
||||
// Driver.Modbus-014: malformed/truncated PDU during a write (e.g. the FC03 RMW
|
||||
// read returning a short response). This is a communication-layer error — surface
|
||||
// as BadCommunicationError to match the ReadAsync path, not BadInternalError which
|
||||
// implies a driver code defect.
|
||||
results[i] = new WriteResult(StatusBadCommunicationError);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
results[i] = new WriteResult(StatusBadInternalError);
|
||||
@@ -1165,10 +1173,16 @@ public sealed class ModbusDriver
|
||||
try
|
||||
{
|
||||
// FC03 read 1 holding register at tag.Address.
|
||||
var readPdu = new byte[] { 0x03, (byte)(tag.Address >> 8), (byte)(tag.Address & 0xFF), 0x00, 0x01 };
|
||||
var readResp = await transport.SendAsync(ResolveUnitId(tag), readPdu, ct).ConfigureAwait(false);
|
||||
// resp = [fc][byte-count=2][hi][lo]
|
||||
var current = (ushort)((readResp[2] << 8) | readResp[3]);
|
||||
// Driver.Modbus-013: use ReadRegisterBlockAsync so the response is validated before
|
||||
// indexing (mirrors the fix applied to the normal read path in Driver.Modbus-005).
|
||||
// Direct transport.SendAsync previously skipped the length checks, letting a truncated
|
||||
// PDU throw IndexOutOfRangeException from readResp[2]/[3] — now surfaces as a clean
|
||||
// InvalidDataException, which WriteAsync's communication-error catch arm maps to
|
||||
// BadCommunicationError (see Driver.Modbus-014).
|
||||
var readRaw = await ReadRegisterBlockAsync(transport, ResolveUnitId(tag), 0x03, tag.Address, 1, ct).ConfigureAwait(false);
|
||||
// readRaw = [hi][lo] — ReadRegisterBlockAsync strips the fc+byte-count header and
|
||||
// validates the payload length, so [0] and [1] are always safe to index here.
|
||||
var current = (ushort)((readRaw[0] << 8) | readRaw[1]);
|
||||
|
||||
var updated = on
|
||||
? (ushort)(current | (1 << bit))
|
||||
|
||||
Reference in New Issue
Block a user