Knowledge Base

Everything you need to know and understand to develop V2X applications.

denm-generator.py
msg = self.generate_denm()
future = self.send_request(msg)
future.add_done_callback(self.request_completed)

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 (07)
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, 07)
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

  1. Download the schema file
  2. Generate language bindings with Cap'n Proto tools
  3. Connect to the cube on port 23057
  4. Subscribe to listeners for incoming data
  5. Transmit frames with the appropriate parameters

See the Python Example for a working implementation.

Previous
RPC