review(Driver.Modbus.Contracts): first review; guard equipment-tag bitIndex/stringLength
First review at 7286d320. -001 (Medium): reject bitIndex>15 for BitInRegister equipment tags
(was silent always-false/no-op via the (1<<16) mask). -002 (Medium): reject stringLength<1
for String (was misleading BadCommunicationError). -003/-004 cap-doc + [Range(0,2000)] on
MaxCoilsPerRead. Consuming Driver.Modbus.Tests green.
This commit is contained in:
@@ -37,7 +37,9 @@ public sealed class ModbusDriverOptions
|
||||
/// Omron CJ/CS cap at <c>125</c>. Set to the lowest cap across the devices this driver
|
||||
/// instance talks to; the driver auto-chunks larger reads into consecutive requests.
|
||||
/// Default <c>125</c> — the spec maximum, safe against any conforming server. Setting
|
||||
/// to <c>0</c> disables the cap (discouraged — the spec upper bound still applies).
|
||||
/// to <c>0</c> resets to the spec maximum (<c>125</c>) without requiring the operator
|
||||
/// to hard-code the limit. Values above <c>125</c> are spec-illegal for conforming
|
||||
/// servers; only use them when the target device's documentation explicitly allows it.
|
||||
/// </summary>
|
||||
public ushort MaxRegistersPerRead { get; init; } = 125;
|
||||
|
||||
@@ -55,8 +57,11 @@ public sealed class ModbusDriverOptions
|
||||
/// spec allows up to <c>2000</c> bits per request — separate from
|
||||
/// <see cref="MaxRegistersPerRead"/> because the underlying packing is different
|
||||
/// (1 bit per coil vs 16 bits per register). Default <c>2000</c>; setting to <c>0</c>
|
||||
/// disables the cap. The driver auto-chunks coil-array reads above the cap.
|
||||
/// resets to the spec maximum (<c>2000</c>). Values above <c>2000</c> are spec-illegal
|
||||
/// and will cause most PLCs to reject the request with exception 03. The driver
|
||||
/// auto-chunks coil-array reads above the cap.
|
||||
/// </summary>
|
||||
[Range(0, 2000)]
|
||||
public ushort MaxCoilsPerRead { get; init; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -34,6 +34,16 @@ public static class ModbusEquipmentTagParser
|
||||
var byteOrder = ReadEnum(root, "byteOrder", ModbusByteOrder.BigEndian);
|
||||
var bitIndex = (byte)ReadInt(root, "bitIndex");
|
||||
var stringLength = (ushort)ReadInt(root, "stringLength");
|
||||
// Guard: String tags require StringLength >= 1. RegisterCount = (StringLength+1)/2,
|
||||
// so StringLength=0 → 0 registers → spec-illegal FC03/FC04 with quantity=0 → PLC
|
||||
// returns exception 03. Reject here (analogous to Driver.Modbus-009 / ValidateStringLength
|
||||
// in the pre-declared tag path) so the driver surfaces BadNodeIdUnknown rather than a
|
||||
// misleading BadCommunicationError. (Driver.Modbus.Contracts-002)
|
||||
if (dataType == ModbusDataType.String && stringLength < 1) return false;
|
||||
// Guard: BitInRegister tags require BitIndex 0–15. Shift by ≥ 16 on an int overflows
|
||||
// a ushort mask silently — reads always return false, writes have no effect.
|
||||
// (Driver.Modbus.Contracts-001)
|
||||
if (dataType == ModbusDataType.BitInRegister && bitIndex > 15) return false;
|
||||
// isArray / arrayLength — optional keys authored by the typed Modbus tag editor.
|
||||
// Canonical rule: a tag is an array iff isArray:true AND arrayLength >= 1.
|
||||
// isArray:false (with any arrayLength) is scalar — the foundation materialises a
|
||||
|
||||
Reference in New Issue
Block a user