===== 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