본문으로 건너뛰기

Beckhoff TwinCAT/ADS 드라이버

개요

Beckhoff TwinCAT 의 AMS/ADS over TCP. JNI / 외부 라이브러리 없이 Beckhoff 가 공개한 infosys AMS/ADS wire spec 만으로 단일 JVM 안에서 socket 직접 통신합니다.

항목
opc_typeADS
구현 클래스plantpulse.driver.protocol.ads.ADSDriver
라이브러리(없음 — 자체 구현. Beckhoff infosys 공개 spec)
read양호 (indexGroup/Offset 또는 심볼 핸들)
write양호 (isWriteSupported() = true)
디폴트 포트48898 (ADS over TCP)
디폴트 AMS 포트851 (PLC Runtime 1)
보안없음 (TCP 직결, ADS Secure 미지원)
TwinCAT 라우터 접근

ADS 통신은 PC/PLC 의 AMS Router 에 등록된 정적 라우트가 필요합니다. PLC 측 TwinCAT System Manager 에서 엣지의 AmsNetId 를 라우트로 등록한 뒤 본 드라이버가 해당 NetId 로 요청합니다.


클래스 / 구조

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

요청-응답 매칭은 AtomicInteger invokeIdCounter 가 발급하는 32-bit invokeId 로 이루어지며 단일 socket 에서 synchronized sendCommand(...) 로 직렬화됩니다. 심볼 이름 → handle 변환 결과는 symbolHandleCache (HashMap) 에 캐시.


wire 포맷 요약

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)
  • 모든 정수 필드 little-endian.
  • AmsNetId 는 6 byte (예 5.40.40.116.1.1).
  • cmd : READ=2, WRITE=3, READ_STATE=4, READ_WRITE=9.
  • stateFlags : STATEFLAG_REQ_RESP = 0x0004 (응답 요구).

OPC 등록 옵션 (options)

의미디폴트
target-netidPLC AmsNetId, 예 5.40.40.116.1.1host + .1.1
target-portAMS 대상 포트 (PLC Runtime)851
source-netid로컬 AmsNetId127.0.0.1.1.1
source-port로컬 AMS 포트32905
connect-timeout연결 타임아웃 (ms)3000
read-timeout응답 대기 타임아웃 (ms)3000

connect() 직후 READ_STATE 호출로 핸드셰이크 검증합니다 — 실패 시 connected=false.


태그 주소 형식

표기의미indexGroup
M0:4%M offset 0, 4 byteIGRP_PLC_RW_MB (0x4020)
I0:2%I offset 0, 2 byteIGRP_PLC_RW_IB (0x4000)
Q0:1%Q offset 0IGRP_PLC_RW_QB (0x4030)
DB10:4DB10 offset 0IGRP_PLC_RW_DB (0x4040)
0x4020:0x10:4직접 indexGroup:indexOffset:length(그대로)
MAIN.fCounter:REAL심볼릭 (ReadWrite + IGRP_GET_SYMHANDLE_BYNAME → 캐시)(handle 기반)

: 뒤에는 byte 길이 또는 BOOL / INT / DINT / REAL / LREAL / STRING 등 TwinCAT 타입 키워드를 쓸 수 있고 sizeOfTypeKeyword(...) 가 byte 길이를 결정합니다.


데이터 인코딩 / 디코딩

decode(byte[], data_type) / encode(value, data_type, hintLen) 가 little-endian 으로 처리:

data_typebyte비고
Boolean / Bool1data[0] != 0
Byte1unsigned
Short / Int / Integer / Word2signed 16
UInt162unsigned
Int32 / DWord4signed 32
UInt324unsigned
Float / REAL4IEEE 754
Long / Int64 / LWord8signed
Double / LREAL8IEEE 754
StringNUTF-8, NUL-terminated 처리

지원 / 미지원

  • ✅ Memory area read/write (M / I / Q / DB)
  • ✅ 심볼 이름 → handle (IGRP_GET_SYMHANDLE_BYNAME = 0xF003) → IGRP_RW_SYMVAL_BYHANDLE (0xF005)
  • READ_STATE (ADS state + Device state)
  • ❌ ADS Notification (구독)
  • ❌ SUMUP (다중 read 1회 wrapping)
  • ❌ ADS Secure / TLS

테스트 커버리지

test/java/plantpulse/driver/protocol/ads/

클래스테스트 수
AdsAddressParseTest10
AdsCodecTest11
AdsReadTest5
AdsResponseTest5
AdsSpecComplianceTest23
AdsWriteTest5
AmsHeaderTest6
AmsNetIdTest7
AmsTcpHeaderTest7

총 79 테스트.


참고

  • Beckhoff infosys: TwinCAT ADS / AMS over TCP wire format
  • 코드: src/plantpulse/driver/protocol/ads/