Beckhoff TwinCAT/ADS Treiber
Überblick
AMS/ADS over TCP von Beckhoff TwinCAT. Ohne JNI / externe Bibliotheken erfolgt die Socket-Kommunikation direkt innerhalb einer einzelnen JVM, allein auf Basis der von Beckhoff veröffentlichten infosys AMS/ADS Wire-Spezifikation.
| Punkt | Wert |
|---|---|
opc_type | ADS |
| Implementierungsklasse | plantpulse.driver.protocol.ads.ADSDriver |
| Bibliothek | (keine — Eigenimplementierung. Beckhoff infosys, offene Spezifikation) |
| read | gut (indexGroup/Offset oder Symbol-Handle) |
| write | gut (isWriteSupported() = true) |
| Standardport | 48898 (ADS over TCP) |
| Standard-AMS-Port | 851 (PLC Runtime 1) |
| Sicherheit | keine (direkte TCP-Verbindung, ADS Secure nicht unterstützt) |
Die ADS-Kommunikation erfordert eine statische Route, die im AMS Router des PC/PLC eingetragen ist. Nachdem im TwinCAT System Manager auf PLC-Seite die AmsNetId des Edge als Route registriert wurde, richtet dieser Treiber seine Anfragen an die entsprechende NetId.
Klassen / Struktur
ADSDriver (BaseProtocolDriver)
├── AmsTcpHeader 6 byte reserved + length(LE)
├── AmsHeader 32 byte target/source NetId+Port + cmd + state + dataLen + err + invokeId
├── AdsRead.buildRequest(indexGroup, indexOffset, length)
├── AdsWrite.buildRequest(indexGroup, indexOffset, data)
├── AdsResponse.parse(payload) — errorCode + data
├── AdsCommand — READ / WRITE / READ_STATE / READ_WRITE 상수, IGRP_*
└── AdsCodec — putUInt16/32LE, getUInt16/32LE, getInt32LE
Die Zuordnung von Anfrage und Antwort erfolgt über eine 32-Bit-invokeId, die von AtomicInteger invokeIdCounter vergeben wird; auf einem einzelnen Socket wird per synchronized sendCommand(...) serialisiert. Die Ergebnisse der Umsetzung Symbolname → Handle werden in symbolHandleCache (HashMap) zwischengespeichert.
Zusammenfassung des Wire-Formats
AMS/TCP Header (6) | AMS Header (32) | ADS payload (가변)
└ reserved(2) len(4)│└ tgtNetId(6) tgtPort(2) srcNetId(6) srcPort(2) cmd(2) state(2) dataLen(4) err(4) invokeId(4)
- Alle Integer-Felder little-endian.
AmsNetIdist 6 Byte (z. B.5.40.40.116.1.1).cmd:READ=2,WRITE=3,READ_STATE=4,READ_WRITE=9.stateFlags:STATEFLAG_REQ_RESP = 0x0004(Antwort erforderlich).
OPC-Registrierungsoptionen (options)
| Schlüssel | Bedeutung | Standard |
|---|---|---|
target-netid | AmsNetId der PLC, z. B. 5.40.40.116.1.1 | host + .1.1 |
target-port | AMS-Zielport (PLC Runtime) | 851 |
source-netid | lokale AmsNetId | 127.0.0.1.1.1 |
source-port | lokaler AMS-Port | 32905 |
connect-timeout | Verbindungs-Timeout (ms) | 3000 |
read-timeout | Timeout für Antwort (ms) | 3000 |
Unmittelbar nach connect() wird der Handshake durch Aufruf von READ_STATE verifiziert — bei Fehlschlag connected=false.
Tag-Adressformate
| Notation | Bedeutung | indexGroup |
|---|---|---|
M0:4 | %M Offset 0, 4 Byte | IGRP_PLC_RW_MB (0x4020) |
I0:2 | %I Offset 0, 2 Byte | IGRP_PLC_RW_IB (0x4000) |
Q0:1 | %Q Offset 0 | IGRP_PLC_RW_QB (0x4030) |
DB10:4 | DB10 Offset 0 | IGRP_PLC_RW_DB (0x4040) |
0x4020:0x10:4 | direkt indexGroup:indexOffset:length | (unverändert) |
MAIN.fCounter:REAL | symbolisch (ReadWrite + IGRP_GET_SYMHANDLE_BYNAME → Cache) | (Handle-basiert) |
Nach : kann entweder die Byte-Länge oder ein TwinCAT-Typschlüsselwort wie BOOL / INT / DINT / REAL / LREAL / STRING angegeben werden; sizeOfTypeKeyword(...) bestimmt dann die Byte-Länge.
Datenkodierung / -dekodierung
decode(byte[], data_type) / encode(value, data_type, hintLen) verarbeiten little-endian:
data_type | Byte | Anmerkung |
|---|---|---|
| Boolean / Bool | 1 | data[0] != 0 |
| Byte | 1 | unsigned |
| Short / Int / Integer / Word | 2 | signed 16 |
| UInt16 | 2 | unsigned |
| Int32 / DWord | 4 | signed 32 |
| UInt32 | 4 | unsigned |
| Float / REAL | 4 | IEEE 754 |
| Long / Int64 / LWord | 8 | signed |
| Double / LREAL | 8 | IEEE 754 |
| String | N | UTF-8, NUL-terminiert verarbeitet |
Unterstützt / nicht unterstützt
- ✅ Memory Area read/write (M / I / Q / DB)
- ✅ Symbolname → Handle (
IGRP_GET_SYMHANDLE_BYNAME=0xF003) →IGRP_RW_SYMVAL_BYHANDLE(0xF005) - ✅
READ_STATE(ADS state + Device state) - ❌ ADS Notification (Subscription)
- ❌ SUMUP (Bündelung mehrerer Reads in einem Aufruf)
- ❌ ADS Secure / TLS
Testabdeckung
test/java/plantpulse/driver/protocol/ads/
| Klasse | Anzahl Tests |
|---|---|
AdsAddressParseTest | 10 |
AdsCodecTest | 11 |
AdsReadTest | 5 |
AdsResponseTest | 5 |
AdsSpecComplianceTest | 23 |
AdsWriteTest | 5 |
AmsHeaderTest | 6 |
AmsNetIdTest | 7 |
AmsTcpHeaderTest | 7 |
Insgesamt 79 Tests.
Referenzen
- Beckhoff infosys: TwinCAT ADS / AMS over TCP wire format
- Code:
src/plantpulse/driver/protocol/ads/