===== JRBusTCP Protocol v1 Specification =====
===== 1. Overview =====
JRBusTCP is a proprietary binary communication protocol designed for efficient, deterministic data exchange between JRobo / JRoboPLC instances and client applications. The protocol operates over TCP/IP and is optimized for:
* High-frequency data exchange
* Minimal bandwidth usage
* Deterministic behavior suitable for automation and PLC-like systems
* Explicit control over data serialization and transport
The protocol follows a request/response model with client-initiated communication. All messages are framed, version-agnostic at transport level, and protected by CRC32 checksums.
Maximum supported message size is **16384 bytes**.
---
===== 2. Transport Layer =====
* Transport protocol: **TCP**
* Connection model: persistent TCP connection
* Byte order: **Big Endian** (network byte order)
* Encoding for strings: **UTF-8**
JRBusTCP does not define connection establishment beyond TCP. Session state (authentication, tag list, update state) is maintained per TCP connection.
---
===== 3. Message Framing =====
==== 3.1 General Message Format ====
+--------+--------+----------------------------+--------+
| size | header | payload | crc |
| 2 B | 2 B | (size - 4 - 4 bytes) | 4 B |
+--------+--------+----------------------------+--------+
Where payload has the following structure:
+---------+------+---------------------------+
| reqId | cmd | body |
| 4 B | 1 B | variable length |
+---------+------+---------------------------+
==== 3.2 Field Description ====
* **size** (2 bytes): Total message size in bytes, from `header` through `crc` inclusive
* **header** (2 bytes): Constant magic value `0xABCD`
* **reqId** (4 bytes): Request identifier (int32, signed). Generated by client
* **cmd** (1 byte): Command code
* **body** (variable): Command-specific payload
* **crc** (4 bytes): CRC32 calculated over `[reqId..body]`
==== 3.3 Request Identifier (reqId) ====
* Generated by the client
* Initial value SHOULD be random
* Incremented by 1 for each subsequent request
* Server MUST return the same `reqId` value unchanged
* Client MUST verify response `reqId` matches request
Server does not validate or interpret `reqId`.
---
===== 4. Command Set =====
==== 4.1 Command Code Summary ====
^ Code ^ Name ^
| 0x01 | INIT |
| 0x02 | LIST |
| 0x03 | UPDATE |
| 0x04 | READ |
| 0x05 | WRITE |
| 0x06 | CRC |
| 0x07 | AUTH_INIT |
| 0x08 | AUTH_SUBMIT |
| 0xFE | UNAUTHENTICATED |
| 0xFF | UNKNOWN |
Response commands are formed by setting the highest bit (`cmd | 0x80`).
---
===== 5. INIT (0x01) =====
Initializes tag list and session parameters.
==== Request ====
cmd : 0x01
flen : 1 byte
filter : flen bytes (UTF-8 regex)
clen : 1 byte
client : clen bytes (UTF-8)
flags : 2 bytes
==== Flags Bitmask ====
* b0: Client supports tag descriptions
* b1: Client supports tag status in READ
* b2: Exclude tags with `external` flag
* b3: Include tags with `hidden` flag
==== Response ====
cmd : 0x81
listsize : 3 bytes (uint24)
`listsize` indicates total number of tags selected.
---
===== 6. LIST (0x02) =====
Retrieves tag metadata in chunks.
==== Request ====
cmd : 0x02
index : 3 bytes (uint24)
==== Response ====
cmd : 0x82
index : 3 bytes
quantity : 3 bytes
next : 3 bytes
[tag entries]
==== Tag Entry Format ====
type : 1 byte
nlen : 1 byte
tagname : nlen bytes (UTF-8)
dlen : 1 byte
descr : dlen bytes (UTF-8)
==== Data Types ====
^ Code ^ Type ^
| 1 | BOOL |
| 2 | INT32 |
| 3 | INT64 |
| 4 | DOUBLE |
| 5 | STRING |
---
===== 7. UPDATE (0x03) =====
Checks for tag value changes.
==== Request ====
cmd : 0x03
==== Response ====
cmd : 0x83
quantity : 3 bytes
next : 3 bytes
liststate : 1 byte
* 0x00: tag list unchanged
* 0xFF: tag list changed; client MUST re-run INIT + LIST
---
===== 8. READ (0x04) =====
Reads tag values.
==== Request ====
cmd : 0x04
index : 3 bytes
==== Response ====
cmd : 0x84
index : 3 bytes
quantity : 3 bytes
next : 3 bytes
[data blocks]
==== Index Blocks ====
* 0xFE: Next tag index, uint16
* 0xFF: Next tag index, uint24
==== Value Encodings (Compact) ====
* 0xF0: false / zero
* 0xF1: true / one
* 0xF2: 1-byte integer
* 0xF3: 2-byte integer
==== Value Encodings (Full) ====
* 0xF8: int32 (4 bytes)
* 0xF9: int64 (8 bytes)
* 0xFA: double (8 bytes)
* 0xFB: string (2-byte length + UTF-8 bytes)
Status bit: b4 of first value byte (if INIT.flags.b1 = 1)
* 1 = Good
* 0 = Bad
---
===== 9. WRITE (0x05) =====
Writes tag values.
==== Request ====
cmd : 0x05
index : 3 bytes
quantity : 3 bytes
[data blocks]
==== Response ====
cmd : 0x85
---
===== 10. CRC (0x06) =====
Returns CRC32 checksum of all tag values after last UPDATE.
==== Request ====
cmd : 0x06
==== Response ====
cmd : 0x86
crc : 4 bytes
---
===== 11. Authentication =====
==== AUTH_INIT (0x07) ====
request:
cmd : 0x07
klen : 2 bytes
keyname : klen bytes
response:
cmd : 0x87
status : 1 byte
nlen : 2 bytes
nonce : nlen bytes
Status:
* 0x00 OK
* 0x01 FAILED
* 0x02 DISABLED
==== AUTH_SUBMIT (0x08) ====
request:
cmd : 0x08
nlen : 2 bytes
nonce : nlen bytes
response:
cmd : 0x88
status : 1 byte
Status:
* 0x00 ACCEPTED
* 0xFF DENIED
---
===== 12. Error Responses =====
* 0xFE: UNAUTHENTICATED
* 0xFF: UNKNOWN
---
===== 13. Session Lifecycle =====
1. TCP connect
2. AUTH_INIT / AUTH_SUBMIT (optional)
3. INIT
4. LIST (paged)
5. UPDATE
6. READ / WRITE
7. CRC (optional)
8. TCP disconnect
---
===== 14. Design Notes =====
* Protocol favors deterministic binary layout
* Compact encodings reduce bandwidth
* Explicit pagination avoids oversized frames
* reqId enables async request matching
---
===== 15. Versioning =====
This document defines **JRBusTCP Protocol v1**. Any incompatible changes MUST increment protocol version and be negotiated out-of-band.
---
===== 16. Diagrams =====
==== 16.1 Typical Session Sequence ====
Client Server
| |
|--- TCP CONNECT ---------------->|
| |
|--- INIT ----------------------->|
|<-- INIT RESPONSE (listsize) ----|
| |
|--- LIST (index=0) ------------->|
|<-- LIST (chunk 1) --------------|
|--- LIST (next) ---------------->|
|<-- LIST (last chunk) -----------|
| |
|--- UPDATE --------------------->|
|<-- UPDATE (quantity,next) ------|
| |
|--- READ (index=first changed) ->|
|<-- READ (values) ---------------|
| |
|--- UPDATE / READ (loop) --------|
| |
==== 16.2 Binary Layout: READ Response ====
+---------+------+---------+-----------+-----------+----------------+
| reqId | cmd | index | quantity | next | data blocks |
| 4 B | 1 B | 3 B | 3 B | 3 B | variable |
+---------+------+---------+-----------+-----------+----------------+
==== 16.3 Binary Layout: WRITE Request ====
+---------+------+---------+-----------+----------------+
| reqId | cmd | index | quantity | data blocks |
| 4 B | 1 B | 3 B | 3 B | variable |
+---------+------+---------+-----------+----------------+
---
===== 17. Rationale =====
==== 17.1 Why Not JSON / Protobuf ====
* Determinism: binary layouts provide predictable parsing cost
* Zero allocations: no intermediate object trees required
* Bandwidth efficiency: compact numeric encodings outperform JSON
* Schema stability: no dependency on external IDL or runtime reflection
==== 17.2 Why TCP and Not UDP ====
* Guaranteed delivery and ordering
* Built-in congestion control
* Simplified client/server implementations
* NAT/firewall friendly
---
===== Appendix A: Examples =====
==== A.1 INIT Request (hex dump) ====
00 1A AB CD 00 00 00 01 01
05 2E 2A 00 06 4A 52 6F 62 6F
00 03
A1 B2 C3 D4
==== A.2 READ Response (single INT32 value) ====
00 14 AB CD 00 00 00 05 84
00 00 01 00 00 01 00 00 00
F8 00 00 00 2A
DE AD BE EF
---
===== Appendix B: Performance Considerations =====
==== B.1 Latency ====
* Typical RTT dominated by TCP latency
* Binary parsing cost negligible
* Suitable for polling rates up to several kHz on LAN
==== B.2 Batching ====
* READ/WRITE support bulk operations
* Clients SHOULD batch contiguous tag indices
* Server SHOULD maximize quantity per response until size limit reached
==== B.3 UPDATE Polling Strategy ====
* Poll UPDATE at fixed interval (e.g., 10–100 ms)
* Issue READ only when quantity > 0
* Use CRC command to validate full state synchronization when needed