Files
lmxopcua/docs/Driver.TwinCAT.Cli.md
Joseph Doherty 4dc685a365 Task #251 — S7 + TwinCAT test-client CLIs (driver CLI suite complete)
Final two of the five driver test clients. Pattern carried forward from
#249 (Modbus) + #250 (AB CIP, AB Legacy) — each CLI inherits Driver.Cli.Common
for DriverCommandBase + SnapshotFormatter and adds a protocol-specific
CommandBase + 4 commands (probe / read / write / subscribe).

New projects:
  - src/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/ — otopcua-s7-cli.
    S7CommandBase carries host/port/cpu/rack/slot/timeout. Handles all S7
    atomic types (Bool, Byte, Int16..UInt64, Float32/64, String, DateTime).
    DateTime parses via RoundtripKind so "2026-04-21T12:34:56Z" works.
  - src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli/ — otopcua-twincat-cli.
    TwinCATCommandBase carries ams-net-id + ams-port + --poll-only toggle
    (flips UseNativeNotifications=false). Covers the full IEC 61131-3
    atomic set: Bool, SInt/USInt, Int/UInt, DInt/UDInt, LInt/ULInt, Real,
    LReal, String, WString, Time/Date/DateTime/TimeOfDay. Structure writes
    refused as out-of-scope (same as AB CIP). IEC time/date variants marshal
    as UDINT on the wire per IEC spec. Subscribe banner announces "ADS
    notification" vs "polling" so the mechanism is obvious in bug reports.

Tests (49 new, 122 cumulative driver-CLI):
  - S7: 22 tests. Every S7DataType has a happy-path + bounds case. DateTime
    round-trips an ISO-8601 string. Tag-name synthesis round-trips every
    S7 address form (DB / M / I / Q, bit/word/dword, strings).
  - TwinCAT: 27 tests. Full IEC type matrix including WString UTF-8 pass-
    through + the four IEC time/date variants landing on UDINT. Structure
    rejection case. Tag-name synthesis for Program scope, GVL scope, nested
    UDT members, and array elements.

Docs:
  - docs/Driver.S7.Cli.md — address grammar cheat sheet + the PUT/GET-must-
    be-enabled gotcha every S7-1200/1500 operator hits.
  - docs/Driver.TwinCAT.Cli.md — AMS router prerequisite (XAR / standalone
    Router NuGet / remote AMS route) + per-command examples.

Wiring:
  - ZB.MOM.WW.OtOpcUa.slnx grew 4 entries (2 src + 2 tests).

Full-solution build clean. Both --help outputs verified end-to-end.

Driver CLI suite complete: 5 CLIs (otopcua-{modbus,abcip,ablegacy,s7,twincat}-cli)
sharing a common base + formatter. 122 CLI tests cumulative. Every driver family
shipped in v2 now has a shell-level ad-hoc validation tool.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 08:44:53 -04:00

102 lines
3.4 KiB
Markdown

# `otopcua-twincat-cli` — Beckhoff TwinCAT test client
Ad-hoc probe / read / write / subscribe tool for Beckhoff TwinCAT 2 / TwinCAT 3
runtimes via ADS. Uses the **same** `TwinCATDriver` the OtOpcUa server does
(`Beckhoff.TwinCAT.Ads` package). Native ADS notifications by default;
`--poll-only` falls back to the shared `PollGroupEngine`.
Fifth (final) of the driver test-client CLIs.
## Build + run
```powershell
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli -- --help
```
## Prerequisite: AMS router
The `Beckhoff.TwinCAT.Ads` library needs a reachable AMS router to open ADS
sessions. Pick one:
1. **Local TwinCAT XAR** — install the free TwinCAT 3 XAR Engineering install
on the machine running the CLI; it ships the router.
2. **Beckhoff.TwinCAT.Ads.TcpRouter** — standalone NuGet router. Run in a
sidecar process when no XAR is installed.
3. **Remote AMS route** — any Windows box with TwinCAT installed, with an AMS
route authorised to the CLI host.
The CLI compiles + runs without a router, but every wire call fails with a
transport error until one is reachable.
## Common flags
| Flag | Default | Purpose |
|---|---|---|
| `-n` / `--ams-net-id` | **required** | AMS Net ID (e.g. `192.168.1.40.1.1`) |
| `-p` / `--ams-port` | `851` | AMS port (TwinCAT 3 PLC = 851, TwinCAT 2 = 801) |
| `--timeout-ms` | `5000` | Per-operation timeout |
| `--poll-only` | off | Disable native ADS notifications, use `PollGroupEngine` instead |
| `--verbose` | off | Serilog debug output |
## Data types
TwinCAT exposes the IEC 61131-3 atomic set: `Bool`, `SInt`, `USInt`, `Int`,
`UInt`, `DInt`, `UDInt`, `LInt`, `ULInt`, `Real`, `LReal`, `String`, `WString`,
`Time`, `Date`, `DateTime`, `TimeOfDay`. The four IEC time/date variants
marshal as `UDINT` on the wire — CLI takes a numeric raw value and lets the
caller interpret semantics.
## Commands
### `probe`
```powershell
# Local TwinCAT 3, probe a canonical global
otopcua-twincat-cli probe -n 127.0.0.1.1.1 -s "TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"
# Remote, probe a project variable
otopcua-twincat-cli probe -n 192.168.1.40.1.1 -s MAIN.bRunning --type Bool
```
### `read`
```powershell
# Bool symbol
otopcua-twincat-cli read -n 192.168.1.40.1.1 -s MAIN.bStart -t Bool
# Counter
otopcua-twincat-cli read -n 192.168.1.40.1.1 -s GVL.Counter -t DInt
# Nested UDT member
otopcua-twincat-cli read -n 192.168.1.40.1.1 -s Motor1.Status.Running -t Bool
# Array element
otopcua-twincat-cli read -n 192.168.1.40.1.1 -s "Recipe[3]" -t Real
# WString
otopcua-twincat-cli read -n 192.168.1.40.1.1 -s GVL.sMessage -t WString
```
### `write`
```powershell
otopcua-twincat-cli write -n 192.168.1.40.1.1 -s MAIN.bStart -t Bool -v true
otopcua-twincat-cli write -n 192.168.1.40.1.1 -s GVL.Counter -t DInt -v 42
otopcua-twincat-cli write -n 192.168.1.40.1.1 -s GVL.sMessage -t WString -v "running"
```
Structure writes refused — drop to driver config JSON for those.
### `subscribe`
```powershell
# Native ADS notifications (default) — PLC pushes on its own cycle
otopcua-twincat-cli subscribe -n 192.168.1.40.1.1 -s GVL.Counter -t DInt -i 500
# Fall back to polling for runtimes where native notifications are constrained
otopcua-twincat-cli subscribe -n 192.168.1.40.1.1 -s GVL.Counter -t DInt -i 500 --poll-only
```
The subscribe banner announces which mechanism is in play — "ADS notification"
or "polling" — so it's obvious in screen-recorded bug reports.