Skip to content

feat: j2mod, jsmodbus, modbus-esp8266 and modbus4j; contract 1.2 transports - #20

Merged
boeboe merged 1 commit into
mainfrom
feat/four-peers
Nov 8, 2026
Merged

boeboe merged 1 commit into
mainfrom
feat/four-peers

Conversation

@boeboe

@boeboe boeboe commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Implementations added

Adapter Upstream Version Revision Pin Licence Published Transports (both roles)
j2mod steveohara/j2mod 3.4.0 d7861c90f40a7ac219a2dc6987ffa54caa5d47a7 jar sha256 0d4254d2… Apache-2.0 yes tcp, udp, rtu-over-tcp
jsmodbus Cloud-Automation/node-modbus 5.0.0 fdf02b2600b22519ae4e7465e9bec381a1653172 (npm gitHead, untagged) tarball sha512 integrity MIT yes tcp, rtu-over-tcp
modbusesp emelianov/modbus-esp8266 4.1.1 299666307a052df52f757f3131e292c2513bb57f git tag, commit checked; SOURCES.sha256 BSD-3-Clause yes tcp, rtu-over-tcp
modbus4j MangoAutomation/modbus4j 3.1.0 3325a2cbce786989156ba7999d6adc2755f7ea5b archive sha256 eb20d1fc… GPL-3.0-or-later no (built locally, R8.3) tcp, udp, rtu-over-tcp

Every pin is the latest stable upstream release (scripts/latest-upstream.py reports update=no for all four). Base images are the existing digest pins, plus node:26.13.0-trixie-slim@sha256:5adad64f… for jsmodbus.

modbus-esp8266 in Docker: this works. The library's Modbus sources are compiled unmodified for Linux against a small Arduino-core layer (sockets as Client/Server/Stream) that has no Modbus logic. Four of its documented compile-time settings are changed through an -include overlay; the upstream files are not edited. See adapters/modbusesp/README.md.

Contract 1.2

  • --transport tcp|udp|rtu-over-tcp on server and client, plus the capability field transports. The five 1.0 adapters declare tcp only.
  • Five new features that every adapter declares. When a pairing lacks one, the affected cases are recorded as unsupported; nothing is waived in tests/known-bugs.tsv.
Feature False for Why (spec V1.1b3)
serverIllegalFunction j2mod, jsmodbus, modbus4j j2mod over TCP and modbus4j over RTU close or stay silent instead of exception 1 (§7). jsmodbus never answers an undecodable request.
serverRejectedWriteUnchanged modbus4j A refused FC15/FC16 has already written its in-range part (§6.11/6.12 state diagrams, FIXTURES rule 2).
serverHighestAddress modbus-esp8266 addReg off-by-one: address 65535 can't be served (§4.4).
clientLargestRegisterWrites, serverLargestRegisterWrites jsmodbus FC16 byte count is capped at 0xF6. The client sends 240 data bytes for 123 registers, and the RTU server stalls (§6.12).

Scenarios

  • New: transport.<udp|rtu-over-tcp>.case.*, .agree.*, .values.* (tests/transport-cases.tsv), and values.rejected-write.unchanged.
  • Changed: the out-of-range FC15/FC16 cases now get a fresh server each, so a partly written refusal can't change later read-only cases.
  • Changed: the FC65, 65535 and largest-write cases and checks are now gated on the features above.

Results

All nine images on linux/arm64, make documents: 9453 pass, 0 fail, 5007 unsupported, 0 not-tested, 0 known-difference, 0 infra-error. Smoke: 46–58 checks per image, 0 failures. make validate lint is clean.

Reproduce: make images documents.

Findings

All findings, with PDUs and spec sections, are in docs/COMPATIBILITY.md#findings and each adapter's README. Highlights beyond the table:

  • j2mod: no CRC check on RTU; UDP FC20/FC24 frame lengths are wrong.
  • jsmodbus: FC43 exceptions carry the MEI byte; pipelined requests are answered LIFO.
  • modbus-esp8266: the FC20 byte count is off by 2, and the server can overflow its heap (the adapter refuses such requests first).
  • modbus4j: no answer for another unit or a bad quantity; FC22 is answered with exception 1 by its server.

Docs and policy

  • Updated: versions.yaml, THIRD_PARTY_NOTICES.md, README, AGENTS, PLAN, CAPABILITIES, CONTAINER_CONTRACT, FIXTURES, COMPATIBILITY.
  • REQUIREMENTS R2.1 (the list of stacks), R8.1 (the GPL adapter is GPL) and R8.3 (GPL images are not published).
  • RELEASE.md v0.4.0, interop_version 0.4.0.

CI

  • The selftest job's time limit is now 150 min and the release build's 180 min: there are 81 pairings instead of 25, and the local run took about 70 min.
  • The upstream drift matrix covers the four new stacks.
  • The own-stack workflow takes its reference list from ADAPTERS in the release it tests.

Not done here: the release itself (maintainer), and pinning in go-modbus (follows the release).

🤖 Generated with Claude Code

…sports

Four more reference stacks, each with a server and a client:
- j2mod 3.4.0 (Java, Apache-2.0): tcp, udp, rtu-over-tcp
- jsmodbus 5.0.0 (JavaScript, MIT): tcp, rtu-over-tcp
- modbus-esp8266 4.1.1 (C++, BSD-3-Clause): tcp, rtu-over-tcp, the library
  compiled unmodified for Linux against an Arduino-core layer
- modbus4j 3.1.0 (Java, GPL-3.0-or-later): tcp, udp, rtu-over-tcp; built
  locally from the pinned source, never published (REQUIREMENTS R8.3)

Contract 1.2:
- --transport tcp|udp|rtu-over-tcp on server and client, and the
  capability field transports. The five 1.0 adapters and the own image
  accept tcp only (the own client also udp and rtu-over-tcp).
- Features serverIllegalFunction, serverRejectedWriteUnchanged,
  serverHighestAddress, serverLargestRegisterWrites and
  clientLargestRegisterWrites, declared by every adapter, for behaviour
  that a stack of the matrix gets wrong on some transport. Pairings that
  lack one skip those cases (unsupported), nothing is waived.
- tests/transport-cases.tsv and write checks per transport.
- The out-of-range FC15/FC16 cases run on a fresh server, and a new value
  check verifies that a refused write writes nothing.

Self-tests, all nine images on linux/arm64: 9453 pass, 0 fail, 5007
unsupported, 0 known differences. Findings with PDUs and specification
sections in docs/COMPATIBILITY.md.

Also: upstream drift resolvers and matrix rows for the four stacks, the
own-stack workflow takes its references from the release's ADAPTERS,
longer CI and release time limits, interop_version 0.4.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@boeboe
boeboe merged commit 7b43cd3 into main Nov 8, 2026
7 checks passed
@boeboe
boeboe deleted the feat/four-peers branch November 8, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant