130 lines
6.3 KiB
Markdown
130 lines
6.3 KiB
Markdown
# Beckhoff TwinCAT (ADS) Driver
|
|
|
|
Getting-started guide for the Beckhoff TwinCAT driver. This is the short path —
|
|
for the full per-field spec read [`docs/v2/driver-specs.md §6`](../v2/driver-specs.md),
|
|
for hands-on CLI testing read [Driver.TwinCAT.Cli.md](../Driver.TwinCAT.Cli.md),
|
|
and for the test-harness map read [TwinCAT-Test-Fixture.md](TwinCAT-Test-Fixture.md).
|
|
|
|
## What it talks to
|
|
|
|
Beckhoff PLC runtimes — **TwinCAT 2 and TwinCAT 3** — over the Beckhoff **ADS**
|
|
protocol carried by **AMS** routing. The driver runs in-process in the OtOpcUa
|
|
server's .NET 10 AnyCPU host. It compiles and runs without a local AMS router,
|
|
but every wire call returns `BadCommunicationError` until a router is reachable
|
|
(the router translates an AMS Net ID to an IP route).
|
|
|
|
Addressing is **symbol-based**: tags are referenced by their TwinCAT symbolic
|
|
name (e.g. `MAIN.bStart`, `GVL.Counter`, `Motor1.Status.Running`) rather than by
|
|
raw memory offset. One driver instance fans out to N targets, each identified by
|
|
an AMS Net ID + port.
|
|
|
|
## Project split
|
|
|
|
| Project | Target | Role |
|
|
|---------|--------|------|
|
|
| `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/` | net10.0 | In-process driver — hosts the ADS client, symbol-path parser, and per-device probe loops |
|
|
| `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/` | net10.0 | Config records + the `TwinCATDataType` enum bound from `DriverConfig` JSON |
|
|
|
|
## Minimum deployment
|
|
|
|
```jsonc
|
|
"Drivers": {
|
|
"twincat-cell-1": {
|
|
"Type": "TwinCAT",
|
|
"Config": {
|
|
"Devices": [ { "HostAddress": "ads://5.23.91.23.1.1:851", "DeviceName": "Cell1" } ],
|
|
"Tags": [
|
|
{ "Name": "Start", "DeviceHostAddress": "ads://5.23.91.23.1.1:851",
|
|
"SymbolPath": "MAIN.bStart", "DataType": "Bool", "Writable": true },
|
|
{ "Name": "Count", "DeviceHostAddress": "ads://5.23.91.23.1.1:851",
|
|
"SymbolPath": "GVL.Counter", "DataType": "Int32", "Writable": false }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### AMS address form
|
|
|
|
`HostAddress` is an `ads://{netId}:{port}` URI parsed by
|
|
`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATAmsAddress.cs`. The Net ID
|
|
is six dot-separated octets (NOT an IP — a Beckhoff-specific identifier the
|
|
router maps to a route); the port is the AMS service port (851 = TC3 PLC runtime
|
|
1, 852 = runtime 2, 801 / 811 / 821 = TC2 PLC runtimes). Port defaults to 851
|
|
when omitted (`ads://5.23.91.23.1.1`).
|
|
|
|
### Symbol path form
|
|
|
|
Symbol paths are parsed by
|
|
`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATSymbolPath.cs`, which
|
|
mirrors IEC 61131-3 structured-text identifiers: global-variable-list
|
|
(`GVL.Counter`), program variable (`MAIN.bStart`), struct member access
|
|
(`Motor1.Status.Running`), array subscripts (`Data[5]`, `Matrix[1,2]`), and
|
|
bit-access (`Flags.0`).
|
|
|
|
## Tag discovery
|
|
|
|
`DiscoverAsync` always emits the pre-declared `Tags` as the authoritative config
|
|
path, under `TwinCAT/{device}/`. When `EnableControllerBrowse` is set, the
|
|
driver also walks each device's symbol table and surfaces controller-resident
|
|
globals / program locals under a `Discovered/` sub-folder; any symbol-loader
|
|
error falls back to pre-declared-only so a flaky symbol download never blocks
|
|
discovery.
|
|
|
|
## Capability surface
|
|
|
|
`TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IHostConnectivityProbe, IPerCallHostResolver, IRediscoverable`
|
|
(`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs`).
|
|
|
|
| Capability | Path | Notes |
|
|
|------------|------|-------|
|
|
| `IReadable` | `ReadAsync` → ADS `ReadValueAsync` | Per-device client, lazily connected and serialized per device |
|
|
| `IWritable` | `WriteAsync` → ADS `WriteValueAsync` | Read-only tags return `BadNotWritable` |
|
|
| `ITagDiscovery` | `DiscoverAsync` | Pre-declared tags + opt-in controller symbol browse |
|
|
| `ISubscribable` | native ADS notifications (default), poll fallback | `UseNativeNotifications=true` registers device notifications so the PLC pushes changes; `false` uses the shared `PollGroupEngine` |
|
|
| `IHostConnectivityProbe` | per-device probe loop | One `HostConnectivityStatus` per configured device; `Running`/`Stopped` transitions raise `OnHostStatusChanged` |
|
|
| `IPerCallHostResolver` | `ResolveHost` lookup in the tag map | Routes each call to the device of the referenced tag; returns an empty-string sentinel when unresolved |
|
|
| `IRediscoverable` | symbol-version-changed callback | A PLC re-download fires `OnRediscoveryNeeded` so the address space is rebuilt |
|
|
|
|
### Rediscovery on PLC re-download
|
|
|
|
`IRediscoverable` is the distinguishing capability. When the ADS client detects
|
|
`DeviceSymbolVersionInvalid` (1809 / 0x0711) — the documented TwinCAT
|
|
symbol-version-changed signal, raised when a PLC program is re-downloaded —
|
|
every symbol and notification handle is invalidated. The driver raises
|
|
`OnRediscoveryNeeded` with a `TwinCAT` scope hint so Core rebuilds the address
|
|
space rather than treating it as a transient connection error.
|
|
|
|
### Native notifications
|
|
|
|
By default the driver registers native ADS device notifications: the PLC pushes
|
|
value changes on its own cycle, which is strictly better for latency and CPU
|
|
than polling. `NotificationMaxDelayMs` lets TwinCAT coalesce notifications up to
|
|
a batching delay for high-churn signals. Set `UseNativeNotifications=false` for
|
|
deployments where the AMS router has notification limits you can't raise — then
|
|
the driver falls through to the shared poll engine.
|
|
|
|
## Single-connection-per-device
|
|
|
|
Each device's ADS client is lazily connected and serialized by a per-device
|
|
connect gate, so a concurrent read / write / probe can't race a client
|
|
create-or-dispose. Probe-initiated connects use the probe timeout; reads and
|
|
writes use the driver-wide `Timeout`.
|
|
|
|
## Testing
|
|
|
|
- **Unit tests** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/` cover
|
|
the AMS / symbol-path parsers, the status mapper, and the driver lifecycle via
|
|
a fake ADS client factory.
|
|
- **Integration fixture** — see
|
|
[TwinCAT-Test-Fixture.md](TwinCAT-Test-Fixture.md) for the harness map.
|
|
- **CLI** — [Driver.TwinCAT.Cli.md](../Driver.TwinCAT.Cli.md) documents the
|
|
standalone read/write/browse/probe CLI for manual checks.
|
|
|
|
## Further reading
|
|
|
|
- [`docs/v2/driver-specs.md §6`](../v2/driver-specs.md) — full per-field spec and
|
|
DriverConfig JSON shape
|
|
- [Driver.TwinCAT.Cli.md](../Driver.TwinCAT.Cli.md) — standalone TwinCAT driver CLI
|
|
- [TwinCAT-Test-Fixture.md](TwinCAT-Test-Fixture.md) — test-harness map
|