Atlas Copco Open Protocol Driver
Overview
A proprietary Java implementation based on Atlas Copco's Open Protocol Specification (vendor-published PDF). It handles torque controller / tightening result collection entirely within a single JVM, eliminating the dependency on an external Node.js runner / NDJSON pipe.
| Item | Value |
|---|---|
opc_type | OP (native) |
| Implementation class | plantpulse.driver.protocol.op.OpenProtocolJavaDriver |
| Library | (none — proprietary implementation. Atlas Copco OP spec) |
| read | Good (subscription cache based) |
| write | Good (isWriteSupported() = true) — only certain MIDs |
| Default port | 4545 |
| Security | None (direct TCP) |
OPDriverThe legacy OPDriver in the same package spawned an external Node.js process, whereas
OpenProtocolJavaDriver runs on a pure Java socket + receiver thread, which
simplifies deployment. Use this driver for new registrations.
Class / Structure
OpenProtocolJavaDriver (BaseProtocolDriver)
├── Socket — host:4545
├── receiverThread — daemon, "OP-Receiver-<opc_id>"
├── lastByMID — ConcurrentHashMap<MID4, Map<field,value>>
├── pendingWriteAck — CompletableFuture<String> (MID 0005/0004 단일-flight)
└── writeLock — synchronized (write 직렬화)
connect() → handshake (MID 0001 → 0002) → subscribe to the main MIDs (0060, 0070) → start receiverThread.
Wire Format Summary
LLLL MMMM RRR x SS PP CC m n | <body ASCII> | NUL(0x00)
└ 4 4 3 1 2 2 2 1 1 = 20 byte 헤더
| Field | Length | Meaning |
|---|---|---|
| LLLL | 4 | Total length (header 20 + body, NUL excluded) |
| MMMM | 4 | MID (0-padded, e.g. 0061) |
| RRR | 3 | revision |
| NoAck | 1 | ' ' (ack required) / '1' (no-ack) |
| SS | 2 | StationID |
| PP | 2 | SpindleID |
| CC | 2 | Sequence |
| m | 1 | MsgNum |
| n | 1 | MsgTotal |
All fields are ASCII (US-ASCII). Messages are terminated with \0.
Main MIDs
Receive (subscription)
| MID | Meaning |
|---|---|
| 0001 → 0002 | Communication start / handshake |
| 0060 → 0061 | Last tightening result subscription / data. Acked with 0062 on receipt |
| 0070 → 0071 | Alarm subscription / alarm data |
| 9999 | Keep-alive (sent automatically on receive timeout) |
Send (write support)
| Constant | MID | Action | body |
|---|---|---|---|
MID_SELECT_PSET | 0018 | Select Pset | 4-char ASCII |
MID_SELECT_JOB | 0038 | Select Job | 2-char ASCII |
MID_DISABLE_TOOL | 0042 | Disable tool | empty string |
MID_ENABLE_TOOL | 0043 | Enable tool | empty string |
MID_SET_VEHICLE_ID | 0050 | Set Vehicle ID | 25-char ASCII (right-padded with spaces) |
MID_ABORT_TIGHTEN | 0127 | Abort tightening | empty string |
For write acks, when receiverLoop receives MID 0005 (accepted) / 0004 (error) it triggers pendingWriteAck.complete(...),
and write() waits via future.get(DEFAULT_WRITE_ACK_TIMEOUT_MS=5000ms, ...).
Tag Address Format
| Notation | Meaning |
|---|---|
0061:resultData | The resultData field of MID 0061 (tightening result) |
0061 | Full raw message of the MID |
0071:alarmCode | alarmCode of the alarm message |
61 | Automatic 4-digit 0-padding → 0061 |
read() only returns the cache of lastByMID, so the polling interval (timecycle) has no bearing on PLC load.
Write address aliases (case-insensitive): pset, job, select-job, vehicle-id / vehicleid,
disable / disable-tool, enable / enable-tool, abort / abort-tightening,
or the MID:0018, MID0018, 0018, 18 forms.
Supported / Not Supported
- ✅ Handshake / keep-alive / automatic re-subscription
- ✅ MID 0061 / 0071 cache (raw + extraction of the first few fields)
- ✅ Write MID 0018 / 0038 / 0042 / 0043 / 0050 / 0127 (synchronous ack wait)
- ❌ Per-MID detailed field parsers (currently only
__raw__+data— later phase) - ❌ spindleId routing for multi-spindle controllers
- ❌ Security/authentication (not present in Open Protocol itself)
Test Coverage
test/java/plantpulse/driver/protocol/op/
| Class | Test count |
|---|---|
OPDriverTest | 9 (legacy driver) |
OpenProtocolJavaDriverTest | 10 |
OpenProtocolSpecTest | 15 |
OpenProtocolWriteTest | 31 |
65 tests in total.
References
- Atlas Copco Open Protocol Specification (vendor-published PDF)
- Code:
src/plantpulse/driver/protocol/op/OpenProtocolJavaDriver.java