AbLegacy PCCC read/write fails against every ab_server family (BadCommunicationError) — path never validated against a simulator #534
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The AbLegacy PCCC read/write path fails against every ab_server PCCC family with
BadCommunicationError(0x80050000). Found on 2026-08-01 while deploying the fixture.Why this is new information.
AbLegacyReadSmokeTestshas never actually run against a simulator./opt/otopcua-ablegacy/did not exist on the Docker host — the stack was written but never deployed — and every ab_server service across BOTH ab fixtures bound:44818. So the AB CIP fixture's long-running ControlLogix container answered the AbLegacy suite's TCP reachability probe, the suite declined to skip, and it ran SLC500-mode PCCC against a ControlLogix. The 4 failures read as "fixture missing" and were dismissed as such (by me, in this session, before checking).Fixture side is now fixed (branch
fix/gitea-532-533-roles-and-string-identity): each family gets its own host port — slc500:44819, micrologix:44820, plc5:44821— all three deployed and running alongside AbCip's ControlLogix on:44818, and the skip guard is per-family so it can no longer mistake a foreign simulator for its own.What remains, and it is a real finding. With the suite now pointed at correct-family simulators, all 4 tests still fail:
Driver_reads_seeded_N_file_from_ab_server_PCCC— all three families,N7:0readSlc500_write_then_read_round_trip_on_N7_scratch_register—N7:5writeReproduced outside the test harness via the driver CLI, so it is not a test-fixture artifact:
Permutations tried, all identical:
--path1,01,01,01,0Notes for whoever picks this up:
AbLegacyStatusMappermapsBadCommunicationErrorfrom seven distinct libplctag statuses and from its_ =>default, so the mapped code does not identify the cause. Getting the rawStatusout ofLibplctagLegacyTagRuntime.GetStatus()is the obvious first step.ab_server, notag_rw, so libplctag's own reference client is not available to separate "our driver" from "libplctag ↔ ab_server PCCC" without building it.Leaving the 4 tests red rather than skipped on purpose: they are now correctly aimed at a live simulator of the right family, so the failure is a true signal about the driver, and making it skip would hide it.
Root-caused and fixed in
01538464. It was our bug, in two drivers, and it is a production defect — not a fixture or protocol limitation.Portwas carried and consumed by nobody.AbLegacyTagCreateParams/AbCipTagCreateParamsboth have aPortfield; both runtimes setTag.Gateway = p.Gateway— the bare host. libplctag does not fail on a portless gateway, it substitutes 44818. So an authored port was not ignored in the harmless sense: the connection was silently redirected to whatever answers on the default port. On a plant network that is another PLC, and the driver would read its tags and report themGood.That explains every observation in this issue. After each PCCC family moved to its own port, the driver still dialled 44818 and kept talking to the AB CIP fixture's ControlLogix container — so the four path permutations in the table above were never reaching a PCCC server at all. The
--pathaxis was a red herring; I was varying the wrong variable.The open question is answered: libplctag PCCC works fine against ab_server. A direct libplctag 1.5.2 probe outside the repo:
Since the library reached the simulators and the driver could not, the difference had to be in our
Tagconstruction, andGatewaywas the only field that differed. The same probe confirmed libplctag acceptshost:portin the gateway attribute, which is what the fix emits.(Note the one genuine trap the probe surfaced:
Path = ""throwsErrorBadDatawherePath = nullsucceeds. Not hit today —AbLegacyDriver.EffectiveCipPathfalls back to the family default when the parsed path is empty — but a real edge if that fallback is ever removed.)AbCip is fixed alongside, and had never been observable there. Every AbCip fixture profile binds 44818, so no test that driver has could distinguish "uses the authored port" from "always uses 44818". Worth keeping as a shape: a fixture that only ever exercises the default value cannot falsify a rule about non-default values, however many tests point at it.
Result: AbLegacy integration 4/4 green — having never passed once before. AbCip integration 10/13 (3 pre-existing skips), AbCip unit 345, AbLegacy unit 219.
The load-bearing guard is now the integration suite itself: it addresses each family on a non-default port, so it cannot pass unless the port is honoured. Unit tests in both drivers pin the composition for machines without fixtures. Falsified both directions — reverting the runtime line reddens all 4 integration tests; dropping the
port > 0guard reddens exactly the two fallback cases.