harden(modbus-rtu): factory throws on unknown transport + document RTU FC-shape assumption
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -105,8 +105,9 @@ public static class ModbusRtuFraming
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Write-echo response (FC 05/06/15/16) or any other length-less fixed shape:
|
// Fixed 4-byte echo: correct for the write FCs this driver emits (05/06/0F/10). A future
|
||||||
// fixed 4 payload bytes + CRC(2).
|
// variable-length response FC outside 01-04 (e.g. FC23) would be mis-sized here and
|
||||||
|
// surface as a desync — revisit the FC-shape table if the driver starts emitting one.
|
||||||
trailing = 4 + 2;
|
trailing = 4 + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ public static class ModbusTransportFactory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">Driver configuration options.</param>
|
/// <param name="options">Driver configuration options.</param>
|
||||||
/// <returns>A <see cref="ModbusRtuOverTcpTransport"/> when <see cref="ModbusTransportMode.RtuOverTcp"/>
|
/// <returns>A <see cref="ModbusRtuOverTcpTransport"/> when <see cref="ModbusTransportMode.RtuOverTcp"/>
|
||||||
/// is selected; otherwise a <see cref="ModbusTcpTransport"/> (also the default/unrecognized fallback).</returns>
|
/// is selected; a <see cref="ModbusTcpTransport"/> when <see cref="ModbusTransportMode.Tcp"/> is selected.</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">
|
||||||
|
/// <paramref name="options"/>.<see cref="ModbusDriverOptions.Transport"/> is not a recognized
|
||||||
|
/// <see cref="ModbusTransportMode"/> member — fail loudly rather than silently falling back to TCP/MBAP.
|
||||||
|
/// </exception>
|
||||||
public static IModbusTransport Create(ModbusDriverOptions options)
|
public static IModbusTransport Create(ModbusDriverOptions options)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(options);
|
ArgumentNullException.ThrowIfNull(options);
|
||||||
@@ -27,11 +31,13 @@ public static class ModbusTransportFactory
|
|||||||
keepAlive: options.KeepAlive,
|
keepAlive: options.KeepAlive,
|
||||||
idleDisconnect: options.IdleDisconnectTimeout,
|
idleDisconnect: options.IdleDisconnectTimeout,
|
||||||
reconnect: options.Reconnect),
|
reconnect: options.Reconnect),
|
||||||
_ => new ModbusTcpTransport(
|
ModbusTransportMode.Tcp => new ModbusTcpTransport(
|
||||||
options.Host, options.Port, options.Timeout, options.AutoReconnect,
|
options.Host, options.Port, options.Timeout, options.AutoReconnect,
|
||||||
keepAlive: options.KeepAlive,
|
keepAlive: options.KeepAlive,
|
||||||
idleDisconnect: options.IdleDisconnectTimeout,
|
idleDisconnect: options.IdleDisconnectTimeout,
|
||||||
reconnect: options.Reconnect),
|
reconnect: options.Reconnect),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(options), options.Transport, "Unknown Modbus transport mode."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,4 +19,9 @@ public sealed class ModbusTransportFactoryTests
|
|||||||
public void Default_options_build_tcp_transport()
|
public void Default_options_build_tcp_transport()
|
||||||
=> ModbusTransportFactory.Create(new ModbusDriverOptions())
|
=> ModbusTransportFactory.Create(new ModbusDriverOptions())
|
||||||
.ShouldBeOfType<ModbusTcpTransport>();
|
.ShouldBeOfType<ModbusTcpTransport>();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Unknown_transport_mode_throws()
|
||||||
|
=> Should.Throw<ArgumentOutOfRangeException>(
|
||||||
|
() => ModbusTransportFactory.Create(new ModbusDriverOptions { Transport = (ModbusTransportMode)999 }));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user