Schema
The schema file defines the frame formats, parameters, callbacks, and RPC methods for remotely controlling the cube's V2X radio. It is the contract between the cube-radio-rpc server and any client built on Cap'n Proto.
Frames – The Core Data Structure
A Frame is the fundamental unit exchanged between client and radio. It is also the primary data observable over-the-air between V2X radios.
struct Frame { sourceAddress @0 :Data; destinationAddress @1 :Data; payload @2 :Data;}Fields:
- sourceAddress: the sender's MAC or sidelink address
- destinationAddress: the intended recipient's address (may be a broadcast address)
- payload: the V2X message data
Pass frames into transmitData() and receive them through DataListener callbacks.
Transmit Parameters
A Frame determines what is sent. TxParameters describes how it is sent. The adjustable parameters depend on the radio technology:
struct TxParameters { union { unspecified @0 :Void; wlan @1 :WlanParameters; cv2x @2 :Cv2xParameters; }}For ITS-G5 / WLAN
struct WlanParameters { priority @0 :UInt8; # Access category (0–7) power @1 :Int16; # Transmit power in dBm × 8 datarate @2 :UInt16; # Data rate in 500 kbps steps}Examples:
priority = 3: AC_BE (Best Effort)power = 160: 20 dBm (160 / 8)datarate = 12: 6 Mbps (12 × 500 kbps)
For C-V2X / LTE-V2X
struct Cv2xParameters { priority @0 :UInt8; # ProSe Per-Packet Priority (PPPP, 0–7) power @1 :Int16; # Transmit power in dBm × 8}Note: Lower PPPP values mean higher priority (0 is highest).
Receive Parameters
When a frame arrives, the cube provides additional metadata in the form of RxParameters:
struct RxParameters { union { unspecified @0 :Void; wlan @1 :WlanParameters; cv2x @2 :Cv2xParameters; }
timestamp :union { none @3 :Void; hardware @4 :UInt64; software @5 :UInt64; }}Returned:
- Link-layer parameters: same structure as TX (priority, power, data rate)
- Timestamp: reception time (timestamped by hardware if available, otherwise by software)
This data is useful for time-sensitive applications and reception quality analysis. The reported power value is the level measured by the receiving radio, not the value set by the transmitter.
Listeners – Asynchronous Callbacks
Instead of polling in a busy loop, subscribe and let the cube push frames:
interface DataListener { onDataIndication @0 (frame: Frame, rxParams :RxParameters);}
interface CbrListener { onCbrReport @0 (cbr :ChannelBusyRatio);}A subscribed DataListener receives every incoming V2X frame. A CbrListener monitors channel congestion by receiving Channel Busy Ratio (CBR) samples, which are required for ETSI Decentralized Congestion Control (DCC) compliance.
Register listeners once, then handle frames as they arrive. This is suited to real-time applications where latency matters.
RPC Methods
The LinkLayer interface provides five operations:
1. Radio identification: identify() → DeviceInfo
Returns the remote device's ID, software version, and additional information. The additional information field describes the active radio on the cube, for example cube-radio=dsrc or cube-radio=cv2x.
2. V2X transmission: transmitData(frame, txParams) → ErrorCode
Send a V2X frame with specific transmission parameters. Primary call for outgoing communication.
3. V2X subscription: subscribeData(listener) → ErrorCode
Register a DataListener to receive incoming frames asynchronously. Call once at startup, handle frames as they arrive.
4. CBR subscription: subscribeCbr(listener) → ErrorCode
Monitor Channel Busy Ratio, used for adapting the station to channel congestion levels. Recommended for production deployments to comply with ETSI DCC.
5. Source address: setSourceAddress(address) → ErrorCode
Configure the cube's own MAC/sidelink address. Set once unless dynamic address changes are required. The ETSI ITS security profile requires changing the source address based on the current pseudonym; the C-ITS stack typically handles this.
Error Handling
RPC calls that may fail (for example, transmissions with invalid settings) return an ErrorCode:
enum ErrorCode { ok @0; # Success invalidArgument @1; # Bad parameters (check your inputs) unsupported @2; # Feature not available on this radio internalError @3; # Something went wrong (check logs)}Always check the error code. It is the first debugging clue when a call fails.
Workflow
- Download the schema file
- Generate language bindings with Cap'n Proto tools
- Connect to the cube on port 23057
- Subscribe to listeners for incoming data
- Transmit frames with the appropriate parameters
See the Python Example for a working implementation.

