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:
Joseph Doherty
2026-05-23 08:18:15 -04:00
parent 1f29b215c8
commit 9263519852
6 changed files with 178 additions and 15 deletions
@@ -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;
}