cm_telemetry/dirt/
rally2.rs

1use crate::{TelemetryEvent, TelemetryPacket};
2use std::error::Error;
3
4use byteorder::{ByteOrder, LittleEndian};
5
6/// DirtRally2 implements the codemasters UDP telemetry protocol for "Dirt Rally 2.0"
7/// see: https://docs.google.com/spreadsheets/d/1eA518KHFowYw7tSMa-NxIFYpiWe5JXgVVQ_IMs7BVW0/edit#gid=0 for details on the specification
8pub struct DirtRally2 {
9    pub car: Car,
10    pub session: Session,
11    pub motion: Motion,
12}
13
14impl TelemetryEvent for DirtRally2 {
15    fn from_packet(packet: &TelemetryPacket) -> Result<DirtRally2, Box<dyn Error>> {
16        if packet.len() < 256 {
17            return Err(Box::from("Packet size is less than 256 bytes, please set extradata=3 on hardware_settings_config.xml"));
18        }
19        Ok(DirtRally2 {
20            car: Car::from_packet(&packet)?,
21            session: Session::from_packet(&packet)?,
22            motion: Motion::from_packet(&packet)?,
23        })
24    }
25}
26
27pub struct Session {
28    pub position: f32,
29    pub location: Coordinate,
30    pub track: Track,
31    pub lap_info: Lap,
32}
33
34pub struct Car {
35    pub speed: f32,
36    pub gear: Gear,
37    pub wheels: (Wheel, Wheel, Wheel, Wheel), // Rear-Left, Rear-Right, Front-Left, Front-Right
38    pub throttle: f32,
39    pub steer: f32,
40    pub brake: f32,
41    pub clutch: f32,
42    pub rpms: f32,
43}
44
45#[derive(Debug)]
46pub enum Gear {
47    Reverse,
48    Neutral,
49    First,
50    Second,
51    Third,
52    Fourth,
53    Fifth,
54    Sixth,
55    Seventh,
56    Eigth,
57    Ninth,
58}
59
60pub struct Motion {
61    pub velocity: Coordinate,
62    pub roll_vector: Coordinate,
63    pub pitch_vector: Coordinate,
64    pub g_force_lateral: f32,
65    pub g_force_longitudinal: f32,
66}
67
68pub struct Wheel {
69    pub suspension_position: f32,
70    pub suspension_velocity: f32,
71    pub wheel_velocity: f32,
72    pub brake_temperature: f32,
73}
74
75pub struct Track {
76    pub time: f32,
77    pub distance: f32,
78    pub length: f32,
79}
80
81pub struct Lap {
82    pub current_lap: f32,
83    pub total_laps: f32,
84    pub last_lap_time: f32,
85    pub current_lap_time: f32,
86    pub current_lap_distance: f32,
87}
88
89type Coordinate = (f32, f32, f32); // x,y,z coordinates
90
91impl Car {
92    fn from_packet(packet: &TelemetryPacket) -> Result<Car, Box<dyn Error>> {
93        Ok(Car {
94            speed: LittleEndian::read_f32(&packet[28..32]),
95            throttle: LittleEndian::read_f32(&packet[116..120]),
96            steer: LittleEndian::read_f32(&packet[120..124]),
97            brake: LittleEndian::read_f32(&packet[124..128]),
98            clutch: LittleEndian::read_f32(&packet[128..132]),
99            rpms: LittleEndian::read_f32(&packet[148..152]),
100            gear: Gear::from_f32(LittleEndian::read_f32(&packet[132..136]))?,
101            wheels: (
102                Wheel {
103                    // Rear-Left
104                    suspension_position: LittleEndian::read_f32(&packet[68..72]),
105                    suspension_velocity: LittleEndian::read_f32(&packet[84..88]),
106                    wheel_velocity: LittleEndian::read_f32(&packet[100..104]),
107                    brake_temperature: LittleEndian::read_f32(&packet[204..208]),
108                },
109                Wheel {
110                    // Rear-Right
111                    suspension_position: LittleEndian::read_f32(&packet[72..76]),
112                    suspension_velocity: LittleEndian::read_f32(&packet[88..92]),
113                    wheel_velocity: LittleEndian::read_f32(&packet[104..108]),
114                    brake_temperature: LittleEndian::read_f32(&packet[208..212]),
115                },
116                Wheel {
117                    // Front-Left
118                    suspension_position: LittleEndian::read_f32(&packet[76..80]),
119                    suspension_velocity: LittleEndian::read_f32(&packet[92..96]),
120                    wheel_velocity: LittleEndian::read_f32(&packet[108..112]),
121                    brake_temperature: LittleEndian::read_f32(&packet[212..216]),
122                },
123                Wheel {
124                    // Front-Right
125                    suspension_position: LittleEndian::read_f32(&packet[80..84]),
126                    suspension_velocity: LittleEndian::read_f32(&packet[96..100]),
127                    wheel_velocity: LittleEndian::read_f32(&packet[112..116]),
128                    brake_temperature: LittleEndian::read_f32(&packet[216..220]),
129                },
130            ),
131        })
132    }
133}
134
135impl Session {
136    fn from_packet(packet: &TelemetryPacket) -> Result<Session, Box<dyn Error>> {
137        Ok(Session {
138            location: (
139                LittleEndian::read_f32(&packet[16..20]),
140                LittleEndian::read_f32(&packet[20..24]),
141                LittleEndian::read_f32(&packet[24..28]),
142            ),
143            position: LittleEndian::read_f32(&packet[156..160]),
144            track: Track::from_packet(&packet)?,
145            lap_info: Lap::from_packet(&packet)?,
146        })
147    }
148}
149
150impl Motion {
151    fn from_packet(packet: &TelemetryPacket) -> Result<Motion, Box<dyn Error>> {
152        Ok(Motion {
153            g_force_lateral: LittleEndian::read_f32(&packet[136..140]),
154            g_force_longitudinal: LittleEndian::read_f32(&packet[140..144]),
155            pitch_vector: (
156                LittleEndian::read_f32(&packet[56..60]),
157                LittleEndian::read_f32(&packet[60..64]),
158                LittleEndian::read_f32(&packet[64..68]),
159            ),
160            roll_vector: (
161                LittleEndian::read_f32(&packet[44..48]),
162                LittleEndian::read_f32(&packet[48..52]),
163                LittleEndian::read_f32(&packet[52..56]),
164            ),
165            velocity: (
166                LittleEndian::read_f32(&packet[32..36]),
167                LittleEndian::read_f32(&packet[36..40]),
168                LittleEndian::read_f32(&packet[40..44]),
169            ),
170        })
171    }
172}
173
174impl Lap {
175    fn from_packet(packet: &TelemetryPacket) -> Result<Lap, Box<dyn Error>> {
176        Ok(Lap {
177            current_lap_time: LittleEndian::read_f32(&packet[4..8]),
178            current_lap_distance: LittleEndian::read_f32(&packet[8..12]),
179            current_lap: LittleEndian::read_f32(&packet[144..148]),
180            total_laps: LittleEndian::read_f32(&packet[240..244]),
181            last_lap_time: LittleEndian::read_f32(&packet[248..252]),
182        })
183    }
184}
185
186impl Track {
187    fn from_packet(packet: &TelemetryPacket) -> Result<Track, Box<dyn Error>> {
188        Ok(Track {
189            distance: LittleEndian::read_f32(&packet[12..16]),
190            time: LittleEndian::read_f32(&packet[0..4]),
191            length: LittleEndian::read_f32(&packet[244..248]),
192        })
193    }
194}
195
196impl Gear {
197    fn from_f32(f: f32) -> Result<Gear, Box<dyn Error>> {
198        if f < 0.0 {
199            return Ok(Gear::Reverse);
200        }
201
202        if f >= 0.0 && f < 1.0 {
203            return Ok(Gear::Neutral);
204        }
205
206        if f >= 1.0 && f < 2.0 {
207            return Ok(Gear::First);
208        }
209
210        if f >= 2.0 && f < 3.0 {
211            return Ok(Gear::Second);
212        }
213
214        if f >= 3.0 && f < 4.0 {
215            return Ok(Gear::Third);
216        }
217
218        if f >= 4.0 && f < 5.0 {
219            return Ok(Gear::Fourth);
220        }
221
222        if f >= 5.0 && f < 6.0 {
223            return Ok(Gear::Fifth);
224        }
225
226        if f >= 6.0 && f < 7.0 {
227            return Ok(Gear::Sixth);
228        }
229
230        if f >= 7.0 && f < 8.0 {
231            return Ok(Gear::Seventh);
232        }
233
234        if f >= 8.0 && f < 9.0 {
235            return Ok(Gear::Eigth);
236        }
237
238        if f >= 9.0 {
239            return Ok(Gear::Ninth);
240        }
241
242        Err(Box::from("unknown gear"))
243    }
244}