f1_api/nineteen/
motion.rs

1//! Decoder for motion packets sent by F1 2019
2//!
3//! The motion packets by F1 2018 and F1 2019 differ only in their packet headers, the rest of the
4//! packet format is identical.
5
6use std::io::{Cursor, Error};
7
8use bytes::{Buf, BytesMut};
9
10use crate::nineteen::header::decode_header;
11use crate::packet::ensure_packet_size;
12use crate::packet::motion::{Motion, MotionPacket};
13use crate::types::{CornerProperty, Property3D};
14
15/// Size of the motion packet in bytes
16pub const PACKET_SIZE: usize = 1343;
17
18/// Decode a motion packet sent by F1 2019
19///
20/// F1 2018 and F1 2019 publish the same data in their motion packets, but with different packet
21/// headers.
22pub fn decode_motion(cursor: &mut Cursor<&mut BytesMut>) -> Result<MotionPacket, Error> {
23    ensure_packet_size(PACKET_SIZE, cursor)?;
24
25    let header = decode_header(cursor)?;
26    let mut cars = Vec::with_capacity(20);
27
28    for _ in 0..20 {
29        cars.push(Motion::new(
30            decode_position(cursor),
31            decode_velocity(cursor),
32            decode_forward_direction(cursor),
33            decode_right_direction(cursor),
34            decode_g_force(cursor),
35            cursor.get_f32_le(),
36            cursor.get_f32_le(),
37            cursor.get_f32_le(),
38        ))
39    }
40
41    Ok(MotionPacket::new(
42        header,
43        cars,
44        decode_suspension_position(cursor),
45        decode_suspension_velocity(cursor),
46        decode_suspension_acceleration(cursor),
47        decode_wheel_speed(cursor),
48        decode_wheel_slip(cursor),
49        decode_local_velocity(cursor),
50        decode_angular_velocity(cursor),
51        decode_angular_acceleration(cursor),
52        cursor.get_f32_le(),
53    ))
54}
55
56/// Decode position of the car
57fn decode_position(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<f32> {
58    Property3D::new(
59        cursor.get_f32_le(),
60        cursor.get_f32_le(),
61        cursor.get_f32_le(),
62    )
63}
64
65/// Decode velocity of the car
66fn decode_velocity(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<f32> {
67    Property3D::new(
68        cursor.get_f32_le(),
69        cursor.get_f32_le(),
70        cursor.get_f32_le(),
71    )
72}
73
74/// Decode forward direction of the car
75fn decode_forward_direction(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<i16> {
76    Property3D::new(
77        cursor.get_i16_le(),
78        cursor.get_i16_le(),
79        cursor.get_i16_le(),
80    )
81}
82
83/// Decode right direction of the car
84fn decode_right_direction(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<i16> {
85    Property3D::new(
86        cursor.get_i16_le(),
87        cursor.get_i16_le(),
88        cursor.get_i16_le(),
89    )
90}
91
92/// Decode G forces on the car
93fn decode_g_force(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<f32> {
94    Property3D::new(
95        cursor.get_f32_le(),
96        cursor.get_f32_le(),
97        cursor.get_f32_le(),
98    )
99}
100
101/// Decode suspension position of the player's car
102fn decode_suspension_position(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<f32> {
103    CornerProperty::new(
104        cursor.get_f32_le(),
105        cursor.get_f32_le(),
106        cursor.get_f32_le(),
107        cursor.get_f32_le(),
108    )
109}
110
111/// Decode suspension velocity of the player's car
112fn decode_suspension_velocity(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<f32> {
113    CornerProperty::new(
114        cursor.get_f32_le(),
115        cursor.get_f32_le(),
116        cursor.get_f32_le(),
117        cursor.get_f32_le(),
118    )
119}
120
121/// Decode suspension acceleration of the player's car
122fn decode_suspension_acceleration(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<f32> {
123    CornerProperty::new(
124        cursor.get_f32_le(),
125        cursor.get_f32_le(),
126        cursor.get_f32_le(),
127        cursor.get_f32_le(),
128    )
129}
130
131/// Decode the wheel speed of the player's car
132fn decode_wheel_speed(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<f32> {
133    CornerProperty::new(
134        cursor.get_f32_le(),
135        cursor.get_f32_le(),
136        cursor.get_f32_le(),
137        cursor.get_f32_le(),
138    )
139}
140
141/// Decode the wheel slip of the player's car
142fn decode_wheel_slip(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<f32> {
143    CornerProperty::new(
144        cursor.get_f32_le(),
145        cursor.get_f32_le(),
146        cursor.get_f32_le(),
147        cursor.get_f32_le(),
148    )
149}
150
151/// Decode the local velocity of the player's car
152fn decode_local_velocity(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<f32> {
153    Property3D::new(
154        cursor.get_f32_le(),
155        cursor.get_f32_le(),
156        cursor.get_f32_le(),
157    )
158}
159
160/// Decode the angular velocity of the player's car
161fn decode_angular_velocity(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<f32> {
162    Property3D::new(
163        cursor.get_f32_le(),
164        cursor.get_f32_le(),
165        cursor.get_f32_le(),
166    )
167}
168/// Decode the angular acceleration of the player's car
169fn decode_angular_acceleration(cursor: &mut Cursor<&mut BytesMut>) -> Property3D<f32> {
170    Property3D::new(
171        cursor.get_f32_le(),
172        cursor.get_f32_le(),
173        cursor.get_f32_le(),
174    )
175}
176
177#[cfg(test)]
178mod tests {
179    use std::io::Cursor;
180
181    use assert_approx_eq::assert_approx_eq;
182    use bytes::{BufMut, BytesMut};
183
184    use crate::nineteen::motion::{decode_motion, PACKET_SIZE};
185
186    fn put_packet_header(mut bytes: BytesMut) -> BytesMut {
187        bytes.put_u16_le(2019);
188        bytes.put_u8(1);
189        bytes.put_u8(2);
190        bytes.put_u8(3);
191        bytes.put_u8(0);
192        bytes.put_u64_le(u64::max_value());
193        bytes.put_f32_le(1.0);
194        bytes.put_u32_le(u32::max_value());
195        bytes.put_u8(0);
196
197        bytes
198    }
199
200    #[test]
201    fn decode_motion_with_error() {
202        let mut bytes = BytesMut::with_capacity(0);
203        let mut cursor = Cursor::new(&mut bytes);
204
205        let packet = decode_motion(&mut cursor);
206        assert!(packet.is_err());
207    }
208
209    #[test]
210    fn decode_motion_with_success() {
211        let mut bytes = BytesMut::with_capacity(PACKET_SIZE);
212        bytes = put_packet_header(bytes);
213
214        bytes.put_f32_le(1.0);
215        bytes.put_f32_le(2.0);
216        bytes.put_f32_le(3.0);
217        bytes.put_f32_le(4.0);
218        bytes.put_f32_le(5.0);
219        bytes.put_f32_le(6.0);
220        bytes.put_i16_le(7);
221        bytes.put_i16_le(8);
222        bytes.put_i16_le(9);
223        bytes.put_i16_le(10);
224        bytes.put_i16_le(11);
225        bytes.put_i16_le(12);
226        bytes.put_f32_le(13.0);
227        bytes.put_f32_le(14.0);
228        bytes.put_f32_le(15.0);
229        bytes.put_f32_le(16.0);
230        bytes.put_f32_le(17.0);
231        bytes.put_f32_le(18.0);
232
233        let padding = vec![0u8; 1140];
234        bytes.put(padding.as_slice());
235
236        bytes.put_f32_le(19.0);
237        bytes.put_f32_le(20.0);
238        bytes.put_f32_le(21.0);
239        bytes.put_f32_le(22.0);
240        bytes.put_f32_le(23.0);
241        bytes.put_f32_le(24.0);
242        bytes.put_f32_le(25.0);
243        bytes.put_f32_le(26.0);
244        bytes.put_f32_le(27.0);
245        bytes.put_f32_le(28.0);
246        bytes.put_f32_le(29.0);
247        bytes.put_f32_le(30.0);
248        bytes.put_f32_le(31.0);
249        bytes.put_f32_le(32.0);
250        bytes.put_f32_le(33.0);
251        bytes.put_f32_le(34.0);
252        bytes.put_f32_le(35.0);
253        bytes.put_f32_le(36.0);
254        bytes.put_f32_le(37.0);
255        bytes.put_f32_le(38.0);
256        bytes.put_f32_le(39.0);
257        bytes.put_f32_le(40.0);
258        bytes.put_f32_le(41.0);
259        bytes.put_f32_le(42.0);
260        bytes.put_f32_le(43.0);
261        bytes.put_f32_le(44.0);
262        bytes.put_f32_le(45.0);
263        bytes.put_f32_le(46.0);
264        bytes.put_f32_le(47.0);
265        bytes.put_f32_le(48.0);
266
267        let mut cursor = Cursor::new(&mut bytes);
268        let packet = decode_motion(&mut cursor).unwrap();
269
270        let motion = packet.cars()[0];
271        assert_approx_eq!(1.0, motion.position().x());
272        assert_approx_eq!(4.0, motion.velocity().x());
273        assert_eq!(7, motion.forward_direction().x());
274        assert_eq!(10, motion.right_direction().x());
275        assert_approx_eq!(13.0, motion.g_force().x());
276        assert_approx_eq!(16.0, motion.yaw());
277        assert_approx_eq!(17.0, motion.pitch());
278        assert_approx_eq!(18.0, motion.roll());
279        assert_approx_eq!(19.0, packet.suspension_position().front_left());
280        assert_approx_eq!(23.0, packet.suspension_velocity().front_left());
281        assert_approx_eq!(27.0, packet.suspension_acceleration().front_left());
282        assert_approx_eq!(31.0, packet.wheel_speed().front_left());
283        assert_approx_eq!(35.0, packet.wheel_slip().front_left());
284        assert_approx_eq!(39.0, packet.local_velocity().x());
285        assert_approx_eq!(42.0, packet.angular_velocity().x());
286        assert_approx_eq!(45.0, packet.angular_acceleration().x());
287        assert_approx_eq!(48.0, packet.front_wheels_angle());
288    }
289}