f1_api/nineteen/
lap.rs

1//! Decoder for lap data packets sent by F1 2019
2//!
3//! The lap data 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, ErrorKind};
7use std::time::Duration;
8
9use bytes::{Buf, BytesMut};
10
11use crate::nineteen::header::decode_header;
12use crate::packet::ensure_packet_size;
13use crate::packet::lap::{DriverStatus, Lap, LapPacket, PitStatus, ResultStatus, Sector};
14
15/// Size of the lap data packet in bytes
16pub const PACKET_SIZE: usize = 843;
17
18/// Decode a lap data packet sent by F1 2019
19///
20/// F1 2018 and F1 2019 publish the same data in their lap data packets, but with different packet
21/// headers.
22pub fn decode_lap_data(cursor: &mut Cursor<&mut BytesMut>) -> Result<LapPacket, Error> {
23    ensure_packet_size(PACKET_SIZE, cursor)?;
24
25    let header = decode_header(cursor)?;
26    let mut laps = Vec::with_capacity(20);
27
28    for _ in 0..20 {
29        laps.push(Lap::new(
30            Duration::from_secs_f32(cursor.get_f32_le()),
31            Duration::from_secs_f32(cursor.get_f32_le()),
32            Duration::from_secs_f32(cursor.get_f32_le()),
33            Duration::from_secs_f32(cursor.get_f32_le()),
34            Duration::from_secs_f32(cursor.get_f32_le()),
35            cursor.get_f32_le(),
36            cursor.get_f32_le(),
37            Duration::from_secs_f32(cursor.get_f32_le()),
38            cursor.get_u8(),
39            cursor.get_u8(),
40            decode_pit_status(cursor)?,
41            decode_sector(cursor)?,
42            cursor.get_u8() < 1,
43            cursor.get_u8(),
44            cursor.get_u8(),
45            decode_driver_status(cursor)?,
46            decode_result_status(cursor)?,
47        ));
48    }
49
50    Ok(LapPacket::new(header, laps))
51}
52
53fn decode_sector(cursor: &mut Cursor<&mut BytesMut>) -> Result<Sector, Error> {
54    let value = cursor.get_u8();
55
56    match value {
57        0 => Ok(Sector::First),
58        1 => Ok(Sector::Second),
59        2 => Ok(Sector::Third),
60        _ => Err(Error::new(
61            ErrorKind::InvalidData,
62            "Failed to decode sector.",
63        )),
64    }
65}
66
67fn decode_pit_status(cursor: &mut Cursor<&mut BytesMut>) -> Result<PitStatus, Error> {
68    let value = cursor.get_u8();
69
70    match value {
71        0 => Ok(PitStatus::None),
72        1 => Ok(PitStatus::Pitting),
73        2 => Ok(PitStatus::InPits),
74        _ => Err(Error::new(
75            ErrorKind::InvalidData,
76            "Failed to decode pit status.",
77        )),
78    }
79}
80
81fn decode_driver_status(cursor: &mut Cursor<&mut BytesMut>) -> Result<DriverStatus, Error> {
82    let value = cursor.get_u8();
83
84    match value {
85        0 => Ok(DriverStatus::InGarage),
86        1 => Ok(DriverStatus::FlyingLap),
87        2 => Ok(DriverStatus::InLap),
88        3 => Ok(DriverStatus::OutLap),
89        4 => Ok(DriverStatus::OnTrack),
90        _ => Err(Error::new(
91            ErrorKind::InvalidData,
92            "Failed to decode driver status.",
93        )),
94    }
95}
96
97fn decode_result_status(cursor: &mut Cursor<&mut BytesMut>) -> Result<ResultStatus, Error> {
98    let value = cursor.get_u8();
99
100    match value {
101        0 => Ok(ResultStatus::Invalid),
102        1 => Ok(ResultStatus::Inactive),
103        2 => Ok(ResultStatus::Active),
104        3 => Ok(ResultStatus::Finished),
105        4 => Ok(ResultStatus::Disqualified),
106        5 => Ok(ResultStatus::NotClassified),
107        6 => Ok(ResultStatus::Retired),
108        _ => Err(Error::new(
109            ErrorKind::InvalidData,
110            "Failed to decode result status.",
111        )),
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use std::io::Cursor;
118
119    use bytes::{BufMut, BytesMut};
120
121    use crate::nineteen::lap::{decode_lap_data, PACKET_SIZE};
122    use crate::packet::lap::{DriverStatus, PitStatus, ResultStatus, Sector};
123
124    fn put_packet_header(mut bytes: BytesMut) -> BytesMut {
125        bytes.put_u16_le(2019);
126        bytes.put_u8(1);
127        bytes.put_u8(2);
128        bytes.put_u8(3);
129        bytes.put_u8(0);
130        bytes.put_u64_le(u64::max_value());
131        bytes.put_f32_le(1.0);
132        bytes.put_u32_le(u32::max_value());
133        bytes.put_u8(0);
134
135        bytes
136    }
137
138    #[test]
139    fn decode_lap_data_with_error() {
140        let mut bytes = BytesMut::with_capacity(0);
141        let mut cursor = Cursor::new(&mut bytes);
142
143        let packet = decode_lap_data(&mut cursor);
144        assert!(packet.is_err());
145    }
146
147    #[test]
148    fn decode_lap_data_with_success() {
149        let mut bytes = BytesMut::with_capacity(PACKET_SIZE);
150        bytes = put_packet_header(bytes);
151
152        bytes.put_f32_le(62.0);
153        bytes.put_f32_le(60.0);
154        bytes.put_f32_le(58.1);
155        bytes.put_f32_le(21.1);
156        bytes.put_f32_le(19.0);
157        bytes.put_f32_le(543.0);
158        bytes.put_f32_le(2048.4);
159        bytes.put_f32_le(0.0);
160        bytes.put_u8(1);
161        bytes.put_u8(4);
162        bytes.put_u8(0);
163        bytes.put_u8(2);
164        bytes.put_u8(0);
165        bytes.put_u8(0);
166        bytes.put_u8(3);
167        bytes.put_u8(1);
168        bytes.put_u8(2);
169
170        let padding = vec![0u8; 779];
171        bytes.put(padding.as_slice());
172
173        let mut cursor = Cursor::new(&mut bytes);
174
175        let packet = decode_lap_data(&mut cursor).unwrap();
176        let lap = packet.laps()[0];
177
178        assert_eq!(62, lap.last_lap_time().as_secs());
179        assert_eq!(60, lap.current_lap_time().as_secs());
180        assert_eq!(58, lap.best_lap_time().as_secs());
181        assert_eq!(21, lap.sector1_time().as_secs());
182        assert_eq!(19, lap.sector2_time().as_secs());
183        assert_eq!(543, lap.lap_distance() as usize);
184        assert_eq!(2048, lap.total_distance() as usize);
185        assert_eq!(0, lap.safety_car_delta().as_secs());
186        assert_eq!(1, lap.position());
187        assert_eq!(4, lap.current_lap_number());
188        assert_eq!(PitStatus::None, lap.pit_status());
189        assert_eq!(Sector::Third, lap.sector());
190        assert!(lap.is_valid_lap());
191        assert_eq!(0, lap.penalties());
192        assert_eq!(3, lap.grid_position());
193        assert_eq!(DriverStatus::FlyingLap, lap.driver_status());
194        assert_eq!(ResultStatus::Active, lap.result_status())
195    }
196}