Files

6.7 KiB

AB Legacy Driver

In-process native-protocol driver that exposes legacy Allen-Bradley PLCs — SLC 500, MicroLogix, PLC-5, and Logix-via-PCCC — as OPC UA nodes. It runs inside the OtOpcUa server's .NET 10 AnyCPU process and speaks PCCC over EtherNet/IP through the same libplctag.NET wrapper as the AB CIP driver, but addresses data by file (data-table) rather than by symbolic tag. One driver instance can serve many devices; per-device routing is keyed on the canonical ab://gateway[:port]/cip-path host-address string. PCCC has no native push model, so subscriptions are a polling overlay on top of IReadable.

For the driver spec (capability surface, config shape, payload limits), see docs/v2/driver-specs.md §4. For the manual test client, see Driver.AbLegacy.Cli.md. For the integration fixture coverage map, see AbLegacy-Test-Fixture.md.

Project Layout

Project Role
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/ The driver — AbLegacyDriver, the libplctag runtime wrapper, the PCCC file-address parser (AbLegacyAddress), the host-address parser, and the status mapper.
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Contracts/ AbLegacyDriverOptions, AbLegacyDeviceOptions, AbLegacyTagDefinition, and the AbLegacyDataType / AbLegacyPlcFamily / AbLegacyPlcFamilyProfile records bound from the driver's DriverConfig JSON.

Per family the AbLegacyPlcFamilyProfile supplies the libplctag plc attribute, default CIP path, max-payload bytes, and the SupportsStringFile / SupportsLongFile capability flags. MicroLogix uses direct EIP (empty default path); MicroLogix and PLC-5 don't ship L-files; PLC-5 predates them entirely. Tag types are validated against the device's profile at init time — declaring a Long or String tag on a family that can't support it fails fast with a clear message.

Capability Surface

AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IHostConnectivityProbe, IPerCallHostResolver, IDisposable, IAsyncDisposable (Driver.AbLegacy/AbLegacyDriver.cs). There is no IAlarmSource — unlike the AB CIP driver, PCCC has no ALMD instruction to project, so alarms are out of scope.

Capability Implementation entry point Notes
ITagDiscovery DiscoverAsync Emits pre-declared tags under per-device folders. Tags are single-element today (IsArray hard-wired false); multi-element file ranges are a tracked follow-up.
IReadable ReadAsync Per-tag reads serialized per cached runtime under a lock (a libplctag Tag handle is not concurrency-safe across the server read path + poll loop).
IWritable WriteAsync Bit-within-word writes (N-file N7:0/3, B-file bits) do a per-parent-word read-modify-write under a lock. Non-writable tags return BadNotWritable.
ISubscribable SubscribeAsync driven by the shared PollGroupEngine No push model — subscriptions become polling groups.
IHostConnectivityProbe ProbeLoopAsync + GetHostStatuses One probe loop per device reading Probe.ProbeAddress; transitions log Warning (down) / Information (recover).
IPerCallHostResolver ResolveHost Routes each call to the tag's DeviceHostAddress; unknown references fall back to the first device, never throwing (per the interface contract).

Addressing Model

Per-device host addresses are the canonical ab://gateway[:port]/cip-path form parsed by AbLegacyHostAddress.TryParse. When the parsed CIP path is empty the family profile's default path is used (e.g. SLC 500 gets 1,0; MicroLogix stays empty for direct EIP).

Tags carry a PCCC file address parsed by AbLegacyAddress (AbLegacyAddress.cs) — file letter + file number + word number, with an optional bit index (/N) or structured sub-element (.ACC, .PRE, …). The string is passed straight through to libplctag's name= attribute; the parser validates shape and surfaces the pieces for driver-side routing (e.g. deciding a bit needs read-modify-write):

Form Meaning
N7:0 Integer file 7, word 0 (signed 16-bit)
F8:0 Float file 8, word 0 (32-bit IEEE-754)
B3:0/0 Bit file 3, word 0, bit 0
L9:0 Long-integer file (SLC 5/05+, 32-bit)
ST9:0 String file (82-byte fixed-length)
T4:0.ACC / C5:0.PRE Timer / counter sub-element
I:0/0 / O:1/2 / S:1 Input / output / status system files (no file number)

AbLegacyDataType covers the corresponding PCCC types: Bit, Int (N), Long (L), Float (F), AnalogInt (A), String (ST), and the TimerElement / CounterElement / ControlElement sub-element families. The parser enforces PCCC structural rules — bit-addressing only on 16/32-bit element files, sub-elements only on T/C/R files, no file number on I/O/S — rejecting malformed addresses before they reach libplctag.

Configuration

AbLegacyDriverOptions (Driver.AbLegacy.Contracts/AbLegacyDriverOptions.cs) binds from the driver's DriverConfig JSON:

  • Devices — one AbLegacyDeviceOptions per PLC (HostAddress, PlcFamily, optional DeviceName).
  • Tags — pre-declared AbLegacyTagDefinition list (Name, DeviceHostAddress, Address, DataType, Writable, WriteIdempotent).
  • Probe — connectivity-probe Enabled / Interval / Timeout / ProbeAddress.

Full per-field descriptions live in the contracts assembly. The JSON skeleton is reproduced in docs/v2/driver-specs.md §4.

Testing

  • Unit teststests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/ cover the driver, the PCCC address parser, and the host-address parser via fake tag runtimes.
  • Integration teststests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/ run against the AB Legacy Docker fixture. See AbLegacy-Test-Fixture.md for the coverage map.
  • Manual clientDriver.AbLegacy.Cli.md.

Operational Notes

  • Native heap is invisible to the GC. As with AB CIP, GetMemoryFootprint() reports CLR allocations only; watch whole-process RSS and use ReinitializeAsync to recycle libplctag handles.
  • PCCC reconnect is more expensive than CIP — legacy PLCs have no connection multiplexing, so the resilience pipeline should use longer backoff than for AB CIP (see docs/v2/driver-specs.md §4).
  • Single-element addressing today — a PCCC file is inherently an array (an N7 file is up to 256 words), but the current tag surface addresses one element per tag; range-spanning tags must be enumerated element-by-element until multi-element addressing lands.