Project CARS 1 & 2 — UDP Telemetry Protocol Specification

# Project CARS 1 & 2 — UDP Telemetry Protocol Specification

> Source: Verified against `leroythelegend/rough_idea_project_cars_cpp` C++ implementation and SMS official spec.  
> Date researched: 2026-06-04

---

## Cross-References

- **AC original protocol**: [Assetto Corsa — UDP Telemetry Protocol Specification](joplin://aed9f3be040943048273a16e05a8100f)
- **ACC protocol**: [ACC — UDP Telemetry Protocol Specification](joplin://6ae7005d9810437093d63470cff98b59)
- **AC EVO status**: [AC EVO — Telemetry Status & Research](joplin://2171d34ab9c1431ea3a979d30d206e23)
- **AC Rally status**: [AC Rally — Telemetry Status & Research](joplin://b7b331aa87544b6ebe5db5b8d7bcd2a0)
- **DiRT Rally protocol**: [DiRT Rally 1 & 2.0 — UDP Telemetry Protocol Specification](joplin://877a753ad06a40e08059834d8c8fb438)
- **Main project plan**: [Sim Racing Telemetry Analysis Platform — Project Plan](joplin://6c0dcb2a567348fd9796f50c790082e4)

---

## 1. Overview

| Property | PCARS 1 (Format 1) | PCARS 2 (Format 2) |
|---|---|---|
| **Default Port** | 5606 | 5606 |
| **Format** | Binary, little-endian | Binary, little-endian |
| **Update Rate** | ~10 Hz | Configurable (10/20/etc Hz) |
| **Direction** | Game → Target IP:Port | Game → Target IP:Port |
| **Binding** | Listener binds to port, game sends TO it | Same |
| **Max Participants** | 56 | 32 |

Both games send UDP packets **to a configured IP:port**. You do NOT broadcast — you configure the target in-game.

---

## 2. Configuration

### PCARS 1
- In-game: **Options → Visual → UDP Protocol**
- Set to "Project CARS" or "Generic" mode
- Configure target IP and port (default 5606)

### PCARS 2
- In-game: **Options → System → UDP Protocol**
- Select format: **1** = PCARS1-compatible, **2** = PCARS2 native (recommended)
- Configure target IP, port, and update frequency
- Config stored in game profile settings

### Config File Locations
- PCARS1: `Documents/C.A.M.S./Project CARS/settings.cfg`
- PCARS2: `Documents/Project CARS 2/savegame/<profile>/race.bin` or via in-game menu

---

## 3. Packet Types

### PCARS 1 (Format 1) — 3 Packet Types

| Type ID | Name | Description |
|---|---|---|
| 0 | Telemetry Data | Main physics/telemetry packet (~1367 bytes) |
| 1 | Participant Info Strings | Driver names (up to 56) |
| 2 | Participant Info Strings Additional | Extra participant data |

### PCARS 2 (Format 2) — 9 Packet Types

| Type ID | Name | Sent? |
|---|---|---|
| 0 | Car Physics | Yes — main telemetry |
| 1 | Race Definition | Yes |
| 2 | Participants | Yes |
| 3 | Timings | Yes |
| 4 | Game State | Yes (includes weather) |
| 5 | Weather State | No — merged into Game State |
| 6 | Vehicle Names | No |
| 7 | Time Stats | Yes |
| 8 | Participant Vehicle Names | Yes |

---

## 4. PCARS 1 (Format 1) — Telemetry Packet Byte Structure

Total size: **1367 bytes**

### Header (3 bytes)

| Offset | Size | Type | Field | Notes |
|---|---|---|---|---|
| 0 | 2 | uint16_le | build_version | e.g. 1104 |
| 2 | 1 | packed uint8 | sequence_number (MSB 6 bits) + packet_type (LSB 2 bits) | seq 0-63, type 0-2 |

### Session & State (3 bytes)

| Offset | Size | Type | Field | Notes |
|---|---|---|---|---|
| 3 | 1 | packed uint8 | session_state (MSB 3 bits) + game_state (LSB 3 bits) | See enums below |
| 4 | 1 | int8 | viewed_participant_index | |
| 5 | 1 | int8 | num_participants | |

### Inputs (4 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 6 | 1 | uint8 | unfiltered_throttle | 0-255 |
| 7 | 1 | uint8 | unfiltered_brake | 0-255 |
| 8 | 1 | int8 | unfiltered_steering | -127 to 127 |
| 9 | 1 | uint8 | unfiltered_clutch | 0-255 |

### Race Info (2 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 10 | 1 | packed uint8 | race_state_flags (LSB 3 bits) |
| 11 | 1 | uint8 | laps_in_event |

### Timing (88 bytes — 22 × float32)

| Offset | Size | Type | Field |
|---|---|---|---|
| 12 | 4 | float32_le | best_lap_time |
| 16 | 4 | float32_le | last_lap_time |
| 20 | 4 | float32_le | current_time |
| 24 | 4 | float32_le | split_time_ahead |
| 28 | 4 | float32_le | split_time_behind |
| 32 | 4 | float32_le | split_time |
| 36 | 4 | float32_le | event_time_remaining |
| 40 | 4 | float32_le | personal_fastest_lap_time |
| 44 | 4 | float32_le | world_fastest_lap_time |
| 48 | 4 | float32_le | current_sector1_time |
| 52 | 4 | float32_le | current_sector2_time |
| 56 | 4 | float32_le | current_sector3_time |
| 60 | 4 | float32_le | fastest_sector1_time |
| 64 | 4 | float32_le | fastest_sector2_time |
| 68 | 4 | float32_le | fastest_sector3_time |
| 72 | 4 | float32_le | personal_fastest_sector1_time |
| 76 | 4 | float32_le | personal_fastest_sector2_time |
| 80 | 4 | float32_le | personal_fastest_sector3_time |
| 84 | 4 | float32_le | world_fastest_sector1_time |
| 88 | 4 | float32_le | world_fastest_sector2_time |
| 92 | 4 | float32_le | world_fastest_sector3_time |

### Flags & Pit (3 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 96 | 2 | uint16_le | joy_pad |
| 98 | 1 | packed | highest_flag_colour (MSB 2 bits) + highest_flag_reason (LSB 3 bits) |
| 99 | 1 | packed | pit_schedule (MSB 2 bits) + pit_mode (LSB 3 bits) |

### Engine & Fuel (18 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 100 | 2 | int16_le | oil_temp_celsius |
| 102 | 2 | uint16_le | oil_pressure_kpa |
| 104 | 2 | int16_le | water_temp_celsius |
| 106 | 2 | uint16_le | water_pressure_kpa |
| 108 | 2 | uint16_le | fuel_pressure_kpa |
| 110 | 1 | uint8 | car_flags |
| 111 | 1 | uint8 | fuel_capacity |
| 112 | 1 | uint8 | brake | 0-255 |
| 113 | 1 | uint8 | throttle | 0-255 |
| 114 | 1 | uint8 | clutch | 0-255 |
| 115 | 1 | int8 | steering | -127 to 127 |

### Vehicle Dynamics (16 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 116 | 4 | float32_le | fuel_level |
| 120 | 4 | float32_le | speed |
| 124 | 2 | uint16_le | rpm |
| 126 | 2 | uint16_le | max_rpm |
| 128 | 1 | packed uint8 | num_gears (MSB 4 bits) + gear (LSB 4 bits) |
| 129 | 1 | uint8 | boost_amount |
| 130 | 1 | int8 | enforced_pit_stop_lap |
| 131 | 1 | packed uint8 | crash_state (LSB 3 bits) |
| 132 | 4 | float32_le | odometer_km |

### Vectors — 7 × 3 floats = 84 bytes

| Offset | Size | Type | Field |
|---|---|---|---|
| 136 | 12 | 3 × float32_le | orientation (pitch, yaw, roll) |
| 148 | 12 | 3 × float32_le | local_velocity |
| 160 | 12 | 3 × float32_le | world_velocity |
| 172 | 12 | 3 × float32_le | angular_velocity |
| 184 | 12 | 3 × float32_le | local_acceleration |
| 196 | 12 | 3 × float32_le | world_acceleration |
| 208 | 12 | 3 × float32_le | extents_centre |

### Tyres & Suspension — Per-wheel data (4 wheels: FL, FR, RL, RR)

| Offset | Size | Type | Field |
|---|---|---|---|
| 220 | 4 | 4 × uint8 | tyre_flags |
| 224 | 4 | 4 × uint8 | terrain |
| 228 | 16 | 4 × float32_le | tyre_y |
| 244 | 16 | 4 × float32_le | tyre_rps |
| 260 | 16 | 4 × float32_le | tyre_slip_speed |
| 276 | 4 | 4 × uint8 | tyre_temp |
| 280 | 4 | 4 × uint8 | tyre_grip |
| 284 | 16 | 4 × float32_le | tyre_height_above_ground |
| 300 | 16 | 4 × float32_le | tyre_lateral_stiffness |
| 316 | 4 | 4 × uint8 | tyre_wear |
| 320 | 4 | 4 × uint8 | brake_damage |
| 324 | 4 | 4 × uint8 | suspension_damage |
| 328 | 8 | 4 × int16_le | brake_temp_celsius |
| 336 | 8 | 4 × uint16_le | tyre_tread_temp |
| 344 | 8 | 4 × uint16_le | tyre_layer_temp |
| 352 | 8 | 4 × uint16_le | tyre_carcass_temp |
| 360 | 8 | 4 × uint16_le | tyre_rim_temp |
| 368 | 8 | 4 × uint16_le | tyre_internal_air_temp |
| 376 | 16 | 4 × float32_le | wheel_local_position_y |
| 392 | 16 | 4 × float32_le | ride_height |
| 408 | 16 | 4 × float32_le | suspension_travel |
| 424 | 16 | 4 × float32_le | suspension_velocity |
| 440 | 8 | 4 × uint16_le | air_pressure |

### Engine & Weather (14 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 448 | 4 | float32_le | engine_speed |
| 452 | 4 | float32_le | engine_torque |
| 456 | 1 | uint8 | aero_damage |
| 457 | 1 | uint8 | engine_damage |
| 458 | 1 | int8 | ambient_temperature |
| 459 | 1 | int8 | track_temperature |
| 460 | 1 | uint8 | rain_density |
| 461 | 1 | int8 | wind_speed |
| 462 | 1 | int8 | wind_direction_x |
| 463 | 1 | int8 | wind_direction_y |

### Participant Info (56 entries × 16 bytes = 896 bytes)

Each participant entry (16 bytes):

| Sub-Offset | Size | Type | Field |
|---|---|---|---|
| 0 | 6 | 3 × int16_le | world_position (x, y, z) |
| 6 | 2 | uint16_le | current_lap_distance |
| 8 | 1 | packed uint8 | is_active (MSB 1 bit) + race_position (7 bits) |
| 9 | 1 | packed uint8 | lap_invalidated (MSB 1 bit) + laps_completed (7 bits) |
| 10 | 1 | uint8 | current_lap |
| 11 | 1 | packed uint8 | same_class (1 bit) + sector (2 bits) + ? (2 bits) + ? (3 bits) |
| 12 | 4 | float32_le | last_sector_time |

56 entries at offset 464: [464, 1360)

### Trailer (7 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 1360 | 4 | float32_le | track_length |
| 1364 | 2 | 2 × uint8 | wings (front, rear) |
| 1366 | 1 | uint8 | dpad |

**Total PCARS 1 Telemetry Packet: 1367 bytes**

---

## 5. PCARS 2 (Format 2) — Car Physics Packet Byte Structure

Total size: **559 bytes**

### Base Header (12 bytes — all Format 2 packets share this)

| Offset | Size | Type | Field | Notes |
|---|---|---|---|---|
| 0 | 4 | uint32_le | packet_number | Incrementing counter |
| 4 | 4 | uint32_le | category_packet_number | |
| 8 | 1 | uint8 | partial_packet_index | For multi-packet messages |
| 9 | 1 | uint8 | partial_packet_number | |
| 10 | 1 | uint8 | packet_type | 0=Car Physics, 1=Race Def, etc. |
| 11 | 1 | uint8 | packet_version | |

### Inputs (5 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 12 | 1 | int8 | viewed_participant_index |
| 13 | 1 | uint8 | unfiltered_throttle | 0-255 |
| 14 | 1 | uint8 | unfiltered_brake | 0-255 |
| 15 | 1 | int8 | unfiltered_steering | -127 to 127 |
| 16 | 1 | uint8 | unfiltered_clutch | 0-255 |

### Engine & Fuel (22 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 17 | 1 | uint8 | car_flags |
| 18 | 2 | int16_le | oil_temp_celsius |
| 20 | 2 | uint16_le | oil_pressure_kpa |
| 22 | 2 | int16_le | water_temp_celsius |
| 24 | 2 | uint16_le | water_pressure_kpa |
| 26 | 2 | uint16_le | fuel_pressure_kpa |
| 28 | 1 | uint8 | fuel_capacity |
| 29 | 1 | uint8 | brake |
| 30 | 1 | uint8 | throttle |
| 31 | 1 | uint8 | clutch |
| 32 | 4 | float32_le | fuel_level |
| 36 | 4 | float32_le | speed |
| 40 | 2 | uint16_le | rpm |
| 42 | 2 | uint16_le | max_rpm |
| 44 | 1 | int8 | steering |
| 45 | 1 | packed uint8 | num_gears (MSB 4 bits) + gear (LSB 4 bits) |
| 46 | 1 | uint8 | boost_amount |
| 47 | 1 | uint8 | crash_state |
| 48 | 4 | float32_le | odometer_km |

### Vectors — 7 × 3 floats = 84 bytes

| Offset | Size | Type | Field |
|---|---|---|---|
| 52 | 12 | 3 × float32_le | orientation |
| 64 | 12 | 3 × float32_le | local_velocity |
| 76 | 12 | 3 × float32_le | world_velocity |
| 88 | 12 | 3 × float32_le | angular_velocity |
| 100 | 12 | 3 × float32_le | local_acceleration |
| 112 | 12 | 3 × float32_le | world_acceleration |
| 124 | 12 | 3 × float32_le | extents_centre |

### Tyres & Suspension (4 wheels: FL, FR, RL, RR)

| Offset | Size | Type | Field |
|---|---|---|---|
| 136 | 4 | 4 × uint8 | tyre_flags |
| 140 | 4 | 4 × uint8 | terrain |
| 144 | 16 | 4 × float32_le | tyre_y |
| 160 | 16 | 4 × float32_le | tyre_rps |
| 176 | 4 | 4 × uint8 | tyre_temp |
| 180 | 16 | 4 × float32_le | tyre_height_above_ground |
| 196 | 4 | 4 × uint8 | tyre_wear |
| 200 | 4 | 4 × uint8 | brake_damage |
| 204 | 4 | 4 × uint8 | suspension_damage |
| 208 | 8 | 4 × int16_le | brake_temp_celsius |
| 216 | 8 | 4 × uint16_le | tyre_tread_temp |
| 224 | 8 | 4 × uint16_le | tyre_layer_temp |
| 232 | 8 | 4 × uint16_le | tyre_carcass_temp |
| 240 | 8 | 4 × uint16_le | tyre_rim_temp |
| 248 | 8 | 4 × uint16_le | tyre_internal_air_temp |
| 256 | 8 | 4 × uint16_le | tyre_temp_left |
| 264 | 8 | 4 × uint16_le | tyre_temp_center |
| 272 | 8 | 4 × uint16_le | tyre_temp_right |
| 280 | 16 | 4 × float32_le | wheel_local_position_y |
| 296 | 16 | 4 × float32_le | ride_height |
| 312 | 16 | 4 × float32_le | suspension_travel |
| 328 | 16 | 4 × float32_le | suspension_velocity |
| 344 | 8 | 4 × uint16_le | suspension_ride_height |
| 352 | 8 | 4 × uint16_le | air_pressure |

### Engine & Misc (25 bytes)

| Offset | Size | Type | Field |
|---|---|---|---|
| 360 | 4 | float32_le | engine_speed |
| 364 | 4 | float32_le | engine_torque |
| 368 | 2 | 2 × uint8 | wings (front, rear) |
| 370 | 1 | uint8 | handbrake |
| 371 | 1 | uint8 | aero_damage |
| 372 | 1 | uint8 | engine_damage |
| 373 | 4 | uint32_le | joy_pad_0 |
| 377 | 1 | uint8 | d_pad |
| 378 | 160 | 4 × char[40] | tyre_compound (4 strings × 40 chars) |
| 538 | 4 | float32_le | turbo_boost_pressure |
| 542 | 12 | 3 × float32_le | full_position (x, y, z) |
| 554 | 1 | uint8 | brake_bias |
| 555 | 4 | uint32_le | tick_count |

**Total PCARS 2 Car Physics Packet: 559 bytes**

---

## 6. PCARS 2 (Format 2) — Game State Packet (Type 4)

### Base Header (12 bytes) — same as above
Plus:

| Offset | Size | Type | Field |
|---|---|---|---|
| 12 | 2 | uint16_le | build_version |
| 14 | 1 | packed uint8 | game_state (MSB 3 bits) + session_state (LSB 3 bits) |
| 15 | 1 | int8 | ambient_temperature |
| 16 | 1 | int8 | track_temperature |
| 17 | 1 | uint8 | rain_density |
| 18 | 1 | uint8 | snow_density |
| 19 | 1 | int8 | wind_speed |
| 20 | 1 | int8 | wind_direction_x |
| 21 | 1 | int8 | wind_direction_y |

Total: ~22 bytes

---

## 7. PCARS 2 (Format 2) — Timing Packet (Type 3)

### Base Header (12 bytes) — same as above
Plus:

| Offset | Size | Type | Field |
|---|---|---|---|
| 12 | 1 | int8 | num_participants |
| 13 | 4 | uint32_le | participants_changed_timestamp |
| 17 | 4 | float32_le | event_time_remaining |
| 21 | 4 | float32_le | split_time_ahead |
| 25 | 4 | float32_le | split_time_behind |
| 29 | 4 | float32_le | split_time |
| 33 | N/A | 32 × participant_info | participants (32 entries × 32 bytes = 1024 bytes) |
| 1057 | 2 | uint16_le | local_participant_index |
| 1059 | 4 | uint32_le | tick_count |

### V2 Participant Info Entry (32 bytes each)

| Sub-Offset | Size | Type | Field |
|---|---|---|---|
| 0 | 6 | 3 × int16_le | world_position |
| 6 | 6 | 3 × int16_le | orientation |
| 12 | 2 | uint16_le | current_lap_distance |
| 14 | 1 | packed uint8 | is_active (MSB 1 bit) + race_position (7 bits) |
| 15 | 1 | packed uint8 | sector (MSB 4 bits) + ? (LSB 4 bits) |
| 16 | 1 | packed uint8 | highest_flag_colour (MSB 3 bits) + highest_flag_reason (LSB 3 bits) |
| 17 | 1 | packed uint8 | pit_mode (MSB 4 bits) + pit_schedule (LSB 4 bits) |
| 18 | 2 | packed uint16 | car_index (MSB 1 bit = local_player) + value (15 bits) |
| 20 | 1 | packed uint8 | race_state (MSB 1 bit = invalid_lap) + value |
| 21 | 1 | uint8 | current_lap |
| 22 | 4 | float32_le | current_time |
| 26 | 4 | float32_le | current_sector_time |
| 30 | 2 | uint16_le | mp_participant_index |

---

## 8. Enumerations

### Game State
```
0 = GAME_EXITED
1 = GAME_FRONT_END
2 = GAME_INGAME_PLAYING
3 = GAME_INGAME_PAUSED
4 = GAME_INGAME_INMENU_TIME_TICKING (V2 only)
5 = GAME_INGAME_RESTARTING (V2 only)
6 = GAME_INGAME_REPLAY (V2 only)
7 = GAME_FRONT_END_REPLAY (V2 only)
```

### Session State
```
0 = SESSION_INVALID
1 = SESSION_PRACTICE
2 = SESSION_TEST
3 = SESSION_QUALIFY
4 = SESSION_FORMATION_LAP
5 = SESSION_RACE
6 = SESSION_TIME_ATTACK
```

### Race State
```
0 = RACESTATE_INVALID
1 = RACESTATE_NOT_STARTED
2 = RACESTATE_RACING
3 = RACESTATE_FINISHED
4 = RACESTATE_DISQUALIFIED
5 = RACESTATE_RETIRED
6 = RACESTATE_DNF
```

### Flag Colour
```
0 = NONE
1 = GREEN
2 = BLUE
3 = WHITE
4 = YELLOW
5 = DOUBLE_YELLOW
6 = BLACK
7 = CHEQUERED
```

### Pit Mode (V1)
```
0 = PIT_MODE_NONE
1 = PIT_MODE_DRING_INTO_PITS
2 = PIT_MODE_IN_PIT
3 = PIT_MODE_DRING_OUT_OF_PITS
4 = PIT_MODE_IN_GARAGE
```

### Pit Schedule (V2)
```
0 = PIT_SCHEDULE_NONE
1 = PIT_SCHEDULE_PLAYER_REQUESTED
2 = PIT_SCHEDULE_ENGINEER_REQUESTED
3 = PIT_SCHEDULE_DAMAGE_REQUESTED
4 = PIT_SCHEDULE_MANDATORY
5 = PIT_SCHEDULE_DRIVE_THROUGH
6 = PIT_SCHEDULE_STOP_GO
7 = PIT_SCHEDULE_PITSPOT_OCCUPIED
```

### Car Flags (bitmask)
```
bit 0 = CAR_HEADLIGHT
bit 1 = CAR_ENGINE_ACTIVE
bit 2 = CAR_ENGINE_WARNING
bit 3 = CAR_SPEED_LIMITER
bit 4 = CAR_ABS
bit 5 = CAR_HANDBRAKE
bit 6 = CAR_STABILITY
bit 7 = CAR_TRACTION_CONTROL
```

### Crash State
```
0 = CRASH_DAMAGE_NONE
1 = CRASH_DAMAGE_OFFTRACK
2 = CRASH_DAMAGE_LARGE_PROP
3 = CRASH_DAMAGE_SPINNING
4 = CRASH_DAMAGE_ROLLING
```

---

## 9. Key Differences Between PCARS 1 and PCARS 2

| Feature | PCARS 1 | PCARS 2 |
|---|---|---|
| Header | 3 bytes (u16 + packed u8) | 12 bytes (2×u32 + 4×u8) |
| Packet types | 3 | 9 |
| Timing data | In telemetry packet | Separate Timings packet (type 3) |
| Weather data | In telemetry packet | Separate Game State packet (type 4) |
| Participant info | In telemetry packet (56 × 16 bytes) | Separate Participants/Timings packets (32 × 32 bytes) |
| Tyre compound | Not present | 4 × 40-char strings in telemetry |
| Turbo boost pressure | Not present | Present (f32) |
| Full 3D position | Not present | Present (3 × f32) |
| Brake bias | Not present | Present (u8) |
| Tick count | Not present | Present (u32) |
| Handbrake | Not present | Present (u8) |
| Suspension ride height | Not present | Present (4 × u16) |
| Tyre temp L/C/R | Not present | Present (3 × 4 × u16) |
| Snow density | Not present | In Game State packet |
| Tyre slip speed | Present (4 × f32) | Not present |
| Tyre grip | Present (4 × u8) | Not present |
| Tyre lateral stiffness | Present (4 × f32) | Not present |

---

## 10. Rust Implementation Notes

### Detection Strategy
1. Read first 2 bytes as `u16_le` — if **≥ 3** bytes of header, check byte 2 for packed data
2. If packet size ~1367 → PCARS 1 telemetry
3. If packet starts with 12-byte base header → PCARS 2; read `packet_type` at offset 10

### Recommended Port for rusty-telemetry
| Port | Use |
|---|---|
| 5606 | PCARS/PCARS2 primary telemetry |

### Parser Pseudocode
```rust
fn parse_packet(data: &[u8]) -> Result<Packet> {
    if data.len() >= 12 {
        let packet_number = u32_le(data, 0);
        let packet_type = data[10];
        // PCARS 2 format
        match packet_type {
            0 => parse_car_physics(data),
            3 => parse_timings(data),
            4 => parse_game_state(data),
            // ...
        }
    } else if data.len() >= 3 {
        let build_version = u16_le(data, 0);
        let seq_type = data[2];
        let packet_type = seq_type & 0x03;
        // PCARS 1 format
        match packet_type {
            0 => parse_telemetry_v1(data),
            1 => parse_participant_strings(data),
            2 => parse_participant_strings_additional(data),
        }
    }
}
```

---

## 11. Reference Implementation

- **C++ decoder**: `https://github.com/leroythelegend/rough_idea_project_cars_cpp`
- Key files: `inc/packettelemetrydatav1.h`, `inc/packettelemetrydata.h`, `inc/packetbase.h`, `inc/consts.h`
- Source files: `src/packettelemetrydatav1.cpp`, `src/packettelemetrydata.cpp`

id: c6bd2c45938246fa9d61776deae9874b
parent_id: 94aa3283ead4477d8449e324a27eb3d0
created_time: 2026-06-04T07:14:27.324Z
updated_time: 2026-06-06T08:27:31.495Z
is_conflict: 0
latitude: 0.00000000
longitude: 0.00000000
altitude: 0.0000
author: 
source_url: 
is_todo: 0
todo_due: 0
todo_completed: 0
source: joplin-desktop
source_application: net.cozic.joplin-desktop
application_data: 
order: 1780557267324
user_created_time: 2026-06-04T07:14:27.324Z
user_updated_time: 2026-06-06T08:27:31.495Z
encryption_cipher_text: 
encryption_applied: 0
markup_language: 1
is_shared: 0
share_id: 
conflict_original_id: 
master_key_id: 
user_data: 
deleted_time: 0
type_: 1