Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests/Docker/docker-compose.yml
T
Joseph Doherty 5018627b35 feat(abcip): #611 discovered UDT member writes + whole-UDT refusal by decision
Item 2 — controller-discovered UDT members are writable on both transports once
browse-committed and authored ReadWrite (writability is the operator's: the commit
lands AccessLevel Read with no writable key). The write names the member (one CIP
symbolic segment per member), its own type, its own bytes. BIT members are supported:
Z-35162 (read-only probe) exposes a UDT BIT member as a 1-byte 0xC1 BOOL, so the
controller applies the bit and the hidden host's other bits are never in the request.

- AbCipDriver: pre-write width check on BOTH transports (libplctag patched part of
  its read buffer and sent it all): BadTypeMismatch, Bool over a wider value
  BadNotSupported; nothing sent, handle kept, health untouched, warn once.
- A runtime NotSupportedException is a refusal: no longer latches Degraded.

Item 3 — whole-UDT writes refused BadNotSupported before any runtime exists, by
decision (a structure write overwrites hidden hosts + padding), documented.

ab_server patch 0003: serve member paths from dotted flat tags (UdtSeg.*), and
accept libplctag's pad byte on 1-byte writes (stock ab_server refused every
libplctag BOOL/SINT write with 0x03). New AbCipUdtMemberWriteTests (both
transports), AbCipDiscoveredMemberWriteTests, native request-byte theory, and a
browse-commit mapper pin. Docs: AbCip.md Member writes / Whole-UDT writes / Known
gaps, fixture docs, CLAUDE.md AB section.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
2026-10-09 04:23:59 -04:00

119 lines
3.8 KiB
YAML

# AB CIP integration-test fixture — ab_server (libplctag).
#
# One service per family. All bind :44818 on the host; only one runs at a
# time. Commands mirror the CLI args AbServerProfile.cs constructs for the
# native-binary path.
#
# Usage:
# docker compose --profile controllogix up
# docker compose --profile compactlogix up
# docker compose --profile micro800 up
# docker compose --profile guardlogix up
services:
controllogix:
profiles: ["controllogix"]
build:
context: .
dockerfile: Dockerfile
image: otopcua-ab-server:libplctag-release
container_name: otopcua-ab-server-controllogix
restart: "no"
ports:
- "44818:44818"
# The last three are here for the controller-browse gate (Gitea #468) and
# are additive — the read/write suites key off the Test* tags above.
# The UdtSeg.* tags (Gitea #611) stand in for the members of a UDT tag `UdtSeg`
# (modelled on the Z-35162 press's UDT_TemperatureProfile_Segment): ab_server has
# no structures, so patch 0003 serves a member path (one CIP symbolic segment per
# member) from the flat tag whose --tag name is that dotted path. They exist for
# the discovered-member write suite (AbCipUdtMemberWriteTests); a bare `UdtSeg`
# read stays unknown, as does any member not listed here.
# Odd-length names are deliberate: Symbol Object entries are packed with no
# padding, so a name with an odd byte count puts every following entry on an
# odd offset. A decoder that assumes even alignment reads all six correctly
# and then loses everything after the first odd name.
command: [
"ab_server",
"--plc=ControlLogix",
"--path=1,0",
"--port=44818",
"--tag=TestDINT:DINT[1]",
"--tag=TestREAL:REAL[1]",
"--tag=TestBOOL:BOOL[1]",
"--tag=TestSINT:SINT[1]",
"--tag=TestString:STRING[1]",
"--tag=TestArray:DINT[16]",
"--tag=Pump_1_Speed:REAL[1]",
"--tag=Line1_Count:DINT[1]",
"--tag=Motor_Run:BOOL[1]",
"--tag=UdtSeg.ID:DINT[1]",
"--tag=UdtSeg.Enable:BOOL[1]",
"--tag=UdtSeg.Ready:BOOL[1]",
"--tag=UdtSeg.RampTime:REAL[1]",
"--tag=UdtSeg.Sub.Code:INT[1]",
"--tag=UdtSeg.Points:DINT[4]"
]
compactlogix:
profiles: ["compactlogix"]
image: otopcua-ab-server:libplctag-release
build:
context: .
dockerfile: Dockerfile
container_name: otopcua-ab-server-compactlogix
restart: "no"
ports:
- "44818:44818"
# ab_server doesn't distinguish CompactLogix from ControlLogix — no
# dedicated --plc mode. Driver-side ConnectionSize cap is enforced
# separately (see AbServerProfile.CompactLogix Notes).
command: [
"ab_server",
"--plc=ControlLogix",
"--path=1,0",
"--port=44818",
"--tag=TestDINT:DINT[1]",
"--tag=TestREAL:REAL[1]",
"--tag=TestBOOL:BOOL[1]"
]
micro800:
profiles: ["micro800"]
image: otopcua-ab-server:libplctag-release
build:
context: .
dockerfile: Dockerfile
container_name: otopcua-ab-server-micro800
restart: "no"
ports:
- "44818:44818"
# ab_server does have a Micro800 plc mode (unconnected-only, empty path).
command: [
"ab_server",
"--plc=Micro800",
"--port=44818",
"--tag=TestDINT:DINT[1]",
"--tag=TestREAL:REAL[1]"
]
guardlogix:
profiles: ["guardlogix"]
image: otopcua-ab-server:libplctag-release
build:
context: .
dockerfile: Dockerfile
container_name: otopcua-ab-server-guardlogix
restart: "no"
ports:
- "44818:44818"
# ab_server has no safety subsystem — _S suffix triggers driver-side
# classification only.
command: [
"ab_server",
"--plc=ControlLogix",
"--path=1,0",
"--port=44818",
"--tag=TestDINT:DINT[1]",
"--tag=SafetyDINT_S:DINT[1]"
]