fix(driver-modbus-addressing): resolve Low code-review findings (Driver.Modbus.Addressing-006,007,009)
- Driver.Modbus.Addressing-006: broaden the catch in TryParseFamilyNative so a future helper throwing a non-Argument/Overflow type still satisfies the try-parse contract. - Driver.Modbus.Addressing-007: document that the address grammar does not carry ModbusStringByteOrder (the structured-tag path does); add a 'Grammar scope' bullet to docs/v2/dl205.md. - Driver.Modbus.Addressing-009: reword the ModbusModiconAddress comments so they don't imply a leading-digit invariant the parser doesn't enforce. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,15 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus;
|
||||
/// <item><c>C100</c> — Coils[99] (mnemonic).</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Grammar scope — out of band (Driver.Modbus.Addressing-007):</b> per-string byte
|
||||
/// order (<see cref="ModbusStringByteOrder"/>) is NOT expressible through this grammar.
|
||||
/// The DL205 low-byte-first string-packing knob is configurable only via the structured
|
||||
/// tag form (the driver's <c>ModbusTagDefinition.StringByteOrder</c> field). The 3rd
|
||||
/// grammar field is the multi-register word/byte order (ABCD/CDAB/BADC/DCBA), not the
|
||||
/// per-string byte order — adding a 5th token would conflict with the array-count slot.
|
||||
/// See <see cref="ModbusStringByteOrder"/> and <c>docs/v2/dl205.md</c> §Strings.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class ModbusAddressParser
|
||||
{
|
||||
@@ -341,8 +350,15 @@ public static class ModbusAddressParser
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is ArgumentException or OverflowException)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Driver.Modbus.Addressing-006: a try-parse method must never throw, so any helper
|
||||
// exception is converted to a structured error. The current helpers throw only
|
||||
// ArgumentException (incl. ArgumentOutOfRangeException) and OverflowException, but
|
||||
// catching narrowly would silently break the TryParse contract if a helper ever
|
||||
// switches to e.g. FormatException from a ushort.Parse swap. Config-bind hot-path
|
||||
// callers depend on TryParse returning a structured (false, error) rather than
|
||||
// throwing an unhandled exception that escapes their TryParse wrapper.
|
||||
error = $"Family-native parse for {family} failed on '{text}': {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,25 @@ public enum ModbusByteOrder
|
||||
/// each register. Word ordering across multiple registers is always ascending address for
|
||||
/// strings — only the byte order inside each register flips.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Grammar scope (Driver.Modbus.Addressing-007):</b> this enum is intentionally NOT
|
||||
/// expressible through the <see cref="ModbusAddressParser"/> grammar string. The grammar
|
||||
/// has no token form for it, and <see cref="ParsedModbusAddress"/> has no field for it —
|
||||
/// a DL205 string tag parsed from the grammar always carries the driver's default order.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The string byte order is configurable only via the structured tag definition (the
|
||||
/// driver's <c>ModbusTagDefinition.StringByteOrder</c> field). Adding a grammar token
|
||||
/// was explicitly considered and rejected: the 3rd-field slot is the multi-register
|
||||
/// word/byte order (ABCD/CDAB/BADC/DCBA) and the 4th-field slot is the array count, so
|
||||
/// a fifth <c>:<order></c> suffix would conflict with the count-shape disambiguation.
|
||||
/// Sites that need per-tag low-byte-first strings must use the structured form. The
|
||||
/// default high-byte-first matches the Modbus spec and Ignition / Kepware default
|
||||
/// behaviour.
|
||||
/// </para>
|
||||
/// <para>See <c>docs/v2/dl205.md</c> §Strings for the DL205-specific rationale.</para>
|
||||
/// </remarks>
|
||||
public enum ModbusStringByteOrder
|
||||
{
|
||||
HighByteFirst,
|
||||
|
||||
@@ -52,10 +52,14 @@ public static class ModbusModiconAddress
|
||||
return false;
|
||||
}
|
||||
|
||||
// Range check up-front — keeps the rest of the parser straight-line. 5-digit Modicon
|
||||
// is always exactly 5 chars (40001..49999, with the lead digit selecting region), and
|
||||
// 6-digit is exactly 6 (400001..465536-shaped). Anything else is unambiguously
|
||||
// malformed so we reject before doing the per-character work.
|
||||
// Range check up-front — keeps the rest of the parser straight-line. Modicon addresses
|
||||
// are exactly 5 or 6 characters: a leading region digit (0/1/3/4 — coils, discrete
|
||||
// inputs, input registers, holding registers respectively) followed by 4 (5-digit form)
|
||||
// or 5 (6-digit form) trailing digits encoding the 1-based register number. The
|
||||
// 5-digit form covers 1..9999 per region (e.g. coils 00001..09999, holding registers
|
||||
// 40001..49999); the 6-digit form covers the full 1..65536 wire range (e.g. coils
|
||||
// 000001..065536, holding 400001..465536). Anything else is unambiguously malformed so
|
||||
// we reject before doing the per-character work.
|
||||
var s = address.Trim();
|
||||
if (s.Length is not (5 or 6))
|
||||
{
|
||||
@@ -100,9 +104,10 @@ public static class ModbusModiconAddress
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5-digit form caps at 9999 by construction (4 trailing digits); reject if the parsed
|
||||
// value exceeds the wire-protocol maximum of 65536 (i.e. PDU offset 65535). 6-digit
|
||||
// form can address the full 65535-offset range.
|
||||
// Wire-protocol maximum is register number 65536 (PDU offset 65535). The 5-digit form's
|
||||
// 4 trailing digits can only encode up to 9999, so this check is reached only by the
|
||||
// 6-digit form in practice — but it is applied to both for safety / simplicity rather
|
||||
// than relying on the digit-count invariant.
|
||||
if (registerNumber > 65536)
|
||||
{
|
||||
error = $"Modicon register number {registerNumber} exceeds the wire maximum (65536 / PDU offset 65535)";
|
||||
|
||||
Reference in New Issue
Block a user