Phase 3 PR 41 — Document AutomationDirect DL205 / DL260 Modbus quirks #40

Merged
dohertj2 merged 1 commits from phase-3-pr41-dl205-quirks-doc into v2 2026-04-18 19:52:21 -04:00
Owner

Pure documentation PR. New docs/v2/dl205.md (~300 lines, 8 H2 sections, 8 primary-source citations) covering every place the DL205/DL260 family diverges from textbook Modbus or has non-obvious behavior a generic client gets wrong. The user explicitly flagged that DL205/DL260 strings don't follow Modbus convention; research turned up that and a lot more.

Headline findings

  • String packing — two chars per V-memory register but the first char is in the LOW byte (opposite of the big-endian convention generic drivers default to). 'Hello' reads back as 'eHll o\0' on a textbook decoder. Kepware exposes a String Byte Order toggle for exactly this; we'll need the same.
  • V-memory addressing — DirectLOGIC is octal natively, Modbus is decimal. V2000 octal = decimal 1024 = Modbus PDU 0x0400. The widespread V40400 = register 0 shorthand is wrong on modern firmware; on H2-ECOM100 absolute mode (factory default) V40400 = 0x2100.
  • Word order CDAB for all 32-bit values. DL205 + DL260 agree, ECOM modules don't re-swap. Already supported via ModbusByteOrder.WordSwap; just needs to be the default in the DL205 profile.
  • BCD-as-default numeric storage. V2000 = 1234 in ladder stores as 0x1234 on the wire, not 0x04D2. IEEE 754 only when ladder used the R type. New decoder mode required.
  • FC quantity caps — FC03/04 cap at 128 (above spec's 125 — bonus territory), FC16 caps at 100 (below spec's 123 — bulk-write batching gotcha).
  • Coil/discrete mappings — DL260: X0→discrete 0, Y0→coil 2048, C0→coil 3072. CPU-wired constants; need to be hardcoded in the device profile.
  • Register 0 is valid on DL205/DL260 — the rejects-register-0 rumour was an older DL05/DL06 relative-mode artefact. Our probe default is safe.
  • Max 4 simultaneous TCP clients on H2-ECOM100, no TCP keepalive, no mid-stream resync on malformed MBAP.
  • Exception codes — only standard 01-04. Write-protect returns 02 newer firmware / 04 older.

What this enables

12 DL205_<behavior> integration-test names ready to fill in PR 42+ as ModbusPal validation completes (one PR per quirk per the existing convention). modbus-test-plan.md DL205 section rewritten as a priority-ordered table that doubles as the test roadmap.

What's NOT in this PR

The actual driver work — string-byte-order option, BCD decoder mode, V-memory address helper, FC16 cap-per-device-family, multi-client TCP handling. Each ships as its own focused PR.

References

8 sources cited inline in dl205.md, primarily:

  • AutomationDirect D2-USER-M (DL205/DL260 user manual)
  • AutomationDirect HA-ECOM-M (H2-ECOM100 module manual)
  • Kepware DirectLogic Ethernet driver manual (vendor-quirks documentation because they have to cope with them)

Unconfirmed items (forum reports only) explicitly flagged with _unconfirmed_ so future-me knows what's manual-sourced vs hardware-reproduced.

Pure documentation PR. New `docs/v2/dl205.md` (~300 lines, 8 H2 sections, 8 primary-source citations) covering every place the DL205/DL260 family diverges from textbook Modbus or has non-obvious behavior a generic client gets wrong. The user explicitly flagged that DL205/DL260 strings don't follow Modbus convention; research turned up that and a lot more. ## Headline findings - **String packing** — two chars per V-memory register but the **first char is in the LOW byte** (opposite of the big-endian convention generic drivers default to). `'Hello'` reads back as `'eHll o\0'` on a textbook decoder. Kepware exposes a `String Byte Order` toggle for exactly this; we'll need the same. - **V-memory addressing** — DirectLOGIC is **octal natively**, Modbus is decimal. `V2000` octal = decimal 1024 = Modbus PDU `0x0400`. The widespread `V40400 = register 0` shorthand is wrong on modern firmware; on H2-ECOM100 absolute mode (factory default) `V40400 = 0x2100`. - **Word order CDAB** for all 32-bit values. DL205 + DL260 agree, ECOM modules don't re-swap. Already supported via `ModbusByteOrder.WordSwap`; just needs to be the default in the DL205 profile. - **BCD-as-default** numeric storage. `V2000 = 1234` in ladder stores as `0x1234` on the wire, not `0x04D2`. IEEE 754 only when ladder used the `R` type. New decoder mode required. - **FC quantity caps** — FC03/04 cap at **128** (above spec's 125 — bonus territory), FC16 caps at **100** (below spec's 123 — bulk-write batching gotcha). - **Coil/discrete mappings** — DL260: X0→discrete 0, Y0→coil 2048, C0→coil 3072. CPU-wired constants; need to be hardcoded in the device profile. - **Register 0 is valid** on DL205/DL260 — the rejects-register-0 rumour was an older DL05/DL06 relative-mode artefact. Our probe default is safe. - **Max 4 simultaneous TCP clients** on H2-ECOM100, no TCP keepalive, no mid-stream resync on malformed MBAP. - **Exception codes** — only standard 01-04. Write-protect returns `02` newer firmware / `04` older. ## What this enables 12 `DL205_<behavior>` integration-test names ready to fill in PR 42+ as ModbusPal validation completes (one PR per quirk per the existing convention). `modbus-test-plan.md` DL205 section rewritten as a priority-ordered table that doubles as the test roadmap. ## What's NOT in this PR The actual driver work — string-byte-order option, BCD decoder mode, V-memory address helper, FC16 cap-per-device-family, multi-client TCP handling. Each ships as its own focused PR. ## References 8 sources cited inline in `dl205.md`, primarily: - AutomationDirect D2-USER-M (DL205/DL260 user manual) - AutomationDirect HA-ECOM-M (H2-ECOM100 module manual) - Kepware DirectLogic Ethernet driver manual (vendor-quirks documentation because they have to cope with them) Unconfirmed items (forum reports only) explicitly flagged with `_unconfirmed_` so future-me knows what's manual-sourced vs hardware-reproduced.
dohertj2 added 1 commit 2026-04-18 19:52:19 -04:00
The user explicitly flagged that DL205/DL260 strings don't follow Modbus convention; research turned up that and a lot more. Headline findings:
String packing — TWO chars per V-memory register but the FIRST char is in the LOW byte (opposite of the big-endian Modbus convention generic drivers default to). 'Hello' in V2000 reads back as 'eHll o\0' on a textbook decoder. Kepware's DirectLogic driver exposes a per-tag 'String Byte Order = Low/High' toggle specifically for this; we'll need the same. Null-terminated, no length prefix, no dedicated KSTR address space — strings live wherever ladder allocates them in V-memory.
V-memory addressing — DirectLOGIC's native V-memory is OCTAL (V2000, V40400) but Modbus is decimal. The CPU translates: V2000 octal = decimal 1024 = Modbus PDU 0x0400. The widespread 'V40400 = register 0' shorthand is wrong on modern firmware (that was DL05/DL06 relative mode); on H2-ECOM100 absolute mode (factory default) V40400 = PDU 0x2100. We'd surface this with an address-format helper in the device profile so operators write V2000 instead of computing 1024 by hand.
Word order CDAB for all 32-bit values — DL205 and DL260 agree, ECOM modules don't re-swap. Already supported via ModbusByteOrder.WordSwap; just needs to be the default in the DL205 profile.
BCD-as-default numeric storage — bit one I didn't expect. DirectLOGIC stores 'V2000 = 1234' as 0x1234 on the wire (BCD nibbles), not as 0x04D2 (decimal 1234). IEEE 754 Float32 only works when ladder used the explicit R type (LDR/OUTR instructions). We need a new decoder mode for BCD-encoded registers — current code assumes binary integers.
FC quantity caps — FC03/04 cap at 128 (above spec's 125 — Bonus territory, current code already respects 125), FC16 caps at 100 (BELOW spec's 123 — important bulk-write batching gotcha). Quantity overrun returns exception 03 IllegalDataValue.
Coil/discrete mappings — DL260: X0->discrete input 0, Y0->coil 2048, C0->coil 3072. SP specials at discrete input 1024-1535 RO. These are CPU-wired constants and cannot be remapped; need to be hardcoded in the DL205/DL260 device profile.
Register 0 — accepted on DL205/DL260 with ECOM in absolute mode, contrary to the widespread internet claim that 'DirectLOGIC rejects register 0'. That rumour was an older DL05/DL06 relative-mode artefact. Our ModbusProbeOptions.ProbeAddress default of 0 is therefore safe for DL205/DL260.
Exception codes — only the standard 01-04. Write-to-protected-bit returns 02 on newer firmware, 04 on older (firmware-transition revision unconfirmed); driver should map both to BadNotWritable. No proprietary exception codes.
Behavioral oddities — H2-ECOM100 accepts MAX 4 simultaneous TCP connections (5th refused at TCP accept). No TCP keepalive (intermediate NAT/firewall drops idle sockets after 2-5 min — periodic probe required). No mid-stream resync on malformed MBAP — driver must reconnect + replay. TxId-drop-under-load forum rumour is unconfirmed; our single-flight + TxId-match guard handles it either way.
Each H2 section ends with the integration-test names we'd ship per the modbus-test-plan.md DL205_<behavior> convention — twelve named test slots ready for PR 42+ to fill in one at a time. References (8) cited inline, primarily D2-USER-M, HA-ECOM-M, and the Kepware DirectLogic Ethernet driver manual which documents these vendor quirks explicitly because they have to cope with them.
modbus-test-plan.md DL205 section rewritten as a priority-ordered table with three columns (quirk / driver impact / test name), pointing the reader at dl205.md for the full reference. Operator-reported items separated into a tail subsection so future-me knows which behaviors are documented vs reproduced-on-hardware.
Pure documentation PR — no code changes. The actual driver work (string-byte-order option, BCD decoder mode, V-memory address helper, FC16 cap-per-device-family, multi-client TCP handling) lands one PR per quirk in PR 42+ as ModbusPal validation completes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 7009483d16 into v2 2026-04-18 19:52:21 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#40