# Bluetooth LE Protocol Some data is made available via BLE so that a smartphone app can be used to display it in other use cases. ## General The BLE protocol contains some standardized services, but can also transport custom services. Each service is compromised of a set of characteristics which can be read or clients can even subscribe for changes. Sadly we can't use any of the standardized service/ profiles to transmit V2X data. Even notifications about DENMs can't be transmitted since the Alert Notification Profile is only meant for the companion device to query notifications from the phone, but not the other way around. So we will only use the Device Information Service to announce ourselves and use a custom service for everything else. ## V2X BLE Service V2X data is exposed via the service UUID `c0b70000-d4f4-4000-ada8-f99a02ee315c` (randomly generated UUID, with byte 3 and 4 set to zero) using the following characteristics: UUID | Type | Description ------------------------------------- | --------------- | ----------- c0b70001-d4f4-4001-ada8-f99a02ee315c | `PositionState` | Set position from external source c0b70001-d4f4-4001-ada8-f99a02ee315c | `RawMsgRx` | Raw CAM message (de-duplicated/ rate-limited) c0b70001-d4f4-4002-ada8-f99a02ee315c | `CamEvent` | Latest received CAM c0b70001-d4f4-4003-ada8-f99a02ee315c | `RawMsgRx` | Raw DENM message (de-duplicated/ rate-limited) c0b70001-d4f4-4004-ada8-f99a02ee315c | `DenmEvent` | Latest received DENM c0b70001-d4f4-4005-ada8-f99a02ee315c | `RawMsgRx` | Raw MAPEM message (de-duplicated/ rate-limited) c0b70001-d4f4-4006-ada8-f99a02ee315c | `RawMsgRx` | Raw SPATEM message (de-duplicated/ rate-limited) ## Message Format Messages are encoded according to the [Protocol Buffers](https://protobuf.dev/) specification since it provides decent binary size and has parser libraries for many programming languages. All data types are defined in one `.proto` file: [c_its-messages.proto](./c_its-messages.proto). ### Position State Input When there's no GNSS receiver connected to the ESP, position, heading and speed information can be set using a `PositionState` message (see [c_its-messages.proto](./c_its-messages.proto)). Maximum message size (assuming realistic value ranges): field name | tag size | (max.) data size ----------------- | -------- | --------- timestamp_ms | 1 | 8 (I64) position | 1 | 1 (LEN(10)) + sub-fields below \+ latitude_deg | 1 | 4 (I32) \+ longitude_deg | 1 | 4 (I32) heading | 1 | 2 (VARINT(3600)) speed | 1 | 2 (VARINT(~163 m/s)) **SUM** | 6 + | 21 = 27 byte ### DENM Event Each received DENM will be "published" as a `DenmEvent` message (see [c_its-messages.proto](./c_its-messages.proto)). Repetitions of the same message (e.g. no changes to the validity timeframe and location) may be dropped by the BLE server. Maximum message size (assuming realistic value ranges): field name | tag size | (max.) data size ----------------- | -------- | --------- timestamp | 1 | 8 (I64) validity_end_ts | 1 | 8 (I64) station_id | 1 | 8 (I64) seq_num | 1 | 3 (VARINT(65535)) event_position | 1 | 1 (LEN(10)) + sub-fields below \+ latitude_deg | 1 | 4 (I32) \+ longitude_deg | 1 | 4 (I32) event_heading_deg | 1 | 1 (VARINT(360)) direction | 1 | 1 (VARINT(3)) cause_code | 1 | 1 (VARINT(127)) sub_cause_code | 1 | 1 (VARINT(127)) **SUM** | 11 + | 40 = 51 byte Note: Cause code and sub-cause code are technically 0..255 in the ASN.1 spec, but that's mainly to ensure backwards-compatibility of the CHOICE with the old wire format. Realistically only cause codes up to 100 are defined and common sub-cause codes use values up to 22. ### CAM Event Each received (low-frequency) CAM will be "published" as a `CamEvent` message (see [c_its-messages.proto](./c_its-messages.proto)). Maximum message size (assuming realistic value ranges): field name | tag size | (max.) data size --------------------- | -------- | --------- station_id | 1 | 8 (I64) station_type | 1 | 1 (VARINT(15)) position | 1 | 1 (LEN(10)) + sub-fields below \+ latitude_deg | 1 | 4 (I32) \+ longitude_deg | 1 | 4 (I32) vehicle_role | 1 | 1 (VARINT(15)) vehicle_data | 1 | 1 (LEN(11)) + sub-fields below \+ heading_deg | 1 | 2 (VARINT(360)) \+ speed | 1 | 2 (VARINT(~163 m/s)) \+ vehicle_length_dm | 1 | 2 (VARINT(1023)) \+ vehicle_width_dm | 1 | 1 (VARINT(62)) **SUM** | 11 + | 27 = 38 byte ### Raw Received Message Received V2X messages will be "published" as a `RawMsgRx` message (see [c_its-messages.proto](./c_its-messages.proto)). Repetitions of the same message should be dropped by the BLE server. Consecutive messages with no relevant changes may be dropped by the BLE server while keeping some minimal publishing rate, e.g.: - only publish MAPEMs every 10 seconds (since content doesn't change, but client may be restarted after first MAPEM from an intersection was received) - drop high-frequency CAMs (only publish "full" CAMs which include the low-frequency container)