f1_telemetry_client/f1_2020/
lap.rs

1use crate::f1_2020::car::TOTAL_CARS;
2use crate::f1_2020::header::PacketHeader;
3use async_std::io::{Cursor, Error, ErrorKind};
4use byteorder_async::{LittleEndian, ReaderToByteOrder};
5use derivative::Derivative;
6use std::time::Duration;
7
8const LAP_DATA_MIN_SIZE: usize = 1190;
9
10#[derive(Debug, Eq, PartialEq, Clone, Copy)]
11pub enum PitStatus {
12    None,
13    Pitting,
14    PitArea,
15}
16
17#[derive(Debug, Eq, PartialEq, Clone, Copy)]
18pub enum DriverStatus {
19    Garage,
20    FlyingLap,
21    InLap,
22    OutLap,
23    OnTrack,
24}
25
26#[derive(Debug, Eq, PartialEq, Clone, Copy)]
27pub enum ResultStatus {
28    Invalid,
29    Inactive,
30    Active,
31    Finished,
32    Disqualified,
33    NotClassified,
34    Retired,
35}
36
37#[derive(Debug, PartialEq, Clone, Copy, Derivative)]
38#[derivative(Eq)]
39pub struct LapData {
40    /// Last lap time in seconds
41    pub last_lap_time: Duration,
42    /// Current time around the lap in seconds
43    pub current_lap_time: Duration,
44    /// Sector 1 time in milliseconds
45    pub sector_1_time: Duration,
46    /// Sector 2 time in milliseconds
47    pub sector_2_time: Duration,
48    /// Best lap time of the session in seconds
49    pub best_lap_time: Duration,
50    pub best_lap_num: u8,
51    /// Sector 1 time of best lap in the session in milliseconds
52    pub best_lap_sector_1_time: Duration,
53    /// Sector 2 time of best lap in the session in milliseconds
54    pub best_lap_sector_2_time: Duration,
55    /// Sector 3 time of best lap in the session in milliseconds
56    pub best_lap_sector_3_time: Duration,
57    /// Best overall sector 1 time of the session in milliseconds
58    pub best_overall_sector_1_time: Duration,
59    pub best_overall_sector_1_lap_num: u8,
60    /// Best overall sector 2 time of the session in milliseconds
61    pub best_overall_sector_2_time: Duration,
62    pub best_overall_sector_2_lap_num: u8,
63    /// Best overall sector 3 time of the session in milliseconds
64    pub best_overall_sector_3_time: Duration,
65    pub best_overall_sector_3_lap_num: u8,
66    // #[derivative(Eq="ignore")]
67    pub lap_distance: f32,
68    // #[derivative(Eq="ignore")]
69    pub total_distance: f32,
70    // #[derivative(Eq="ignore")]
71    /// Delta in seconds for safety car
72    pub safety_car_delta: Duration,
73    pub car_position: u8,
74    pub current_lap_num: u8,
75    pub pit_status: PitStatus,
76    pub sector: u8,
77    pub current_lap_invalid: bool,
78    pub penalties: u8,
79    pub grid_position: u8,
80    pub driver_status: DriverStatus,
81    pub result_status: ResultStatus,
82}
83
84#[derive(Debug, Eq, PartialEq, Clone)]
85pub struct PacketLapData {
86    pub header: PacketHeader,
87    pub lap_data: Vec<LapData>,
88}
89
90pub async fn parse_lap_data(
91    cursor: &mut Cursor<Vec<u8>>,
92    header: PacketHeader,
93    size: usize,
94) -> Result<PacketLapData, Error> {
95    ensure_lap_data_size(size)?;
96
97    let mut laps = Vec::with_capacity(TOTAL_CARS);
98    for _ in 0..TOTAL_CARS {
99        let lap = parse_lap(cursor).await?;
100        laps.push(lap);
101    }
102
103    Ok(PacketLapData {
104        header,
105        lap_data: laps,
106    })
107}
108
109async fn parse_lap(cursor: &mut Cursor<Vec<u8>>) -> Result<LapData, Error> {
110    let last_lap_time =
111        Duration::from_secs_f32(cursor.byte_order().read_f32::<LittleEndian>().await?); // in seconds
112    let current_lap_time =
113        Duration::from_secs_f32(cursor.byte_order().read_f32::<LittleEndian>().await?); // in seconds
114    let sector_1_time =
115        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
116    let sector_2_time =
117        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
118    let best_lap_time =
119        Duration::from_secs_f32(cursor.byte_order().read_f32::<LittleEndian>().await?); // in seconds
120    let best_lap_num = cursor.byte_order().read_u8().await?;
121    let best_lap_sector_1_time =
122        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
123    let best_lap_sector_2_time =
124        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
125    let best_lap_sector_3_time =
126        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
127    let best_overall_sector_1_time =
128        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
129    let best_overall_sector_1_lap_num = cursor.byte_order().read_u8().await?;
130    let best_overall_sector_2_time =
131        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
132    let best_overall_sector_2_lap_num = cursor.byte_order().read_u8().await?;
133    let best_overall_sector_3_time =
134        Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); // in ms
135    let best_overall_sector_3_lap_num = cursor.byte_order().read_u8().await?;
136    let lap_distance = cursor.byte_order().read_f32::<LittleEndian>().await?;
137    let total_distance = cursor.byte_order().read_f32::<LittleEndian>().await?;
138    let safety_car_delta =
139        Duration::from_secs_f32(cursor.byte_order().read_f32::<LittleEndian>().await?); // in seconds
140    let car_position = cursor.byte_order().read_u8().await?;
141    let current_lap_num = cursor.byte_order().read_u8().await?;
142    let pit_status = parse_pit_status(cursor).await?;
143    let sector = cursor.byte_order().read_u8().await?;
144    let current_lap_invalid = cursor.byte_order().read_u8().await? == 1;
145    let penalties = cursor.byte_order().read_u8().await?;
146    let grid_position = cursor.byte_order().read_u8().await?;
147    let driver_status = parse_driver_status(cursor).await?;
148    let result_status = parse_result_status(cursor).await?;
149
150    Ok(LapData {
151        last_lap_time,
152        current_lap_time,
153        sector_1_time,
154        sector_2_time,
155        best_lap_time,
156        best_lap_num,
157        best_lap_sector_1_time,
158        best_lap_sector_2_time,
159        best_lap_sector_3_time,
160        best_overall_sector_1_time,
161        best_overall_sector_1_lap_num,
162        best_overall_sector_2_time,
163        best_overall_sector_2_lap_num,
164        best_overall_sector_3_time,
165        best_overall_sector_3_lap_num,
166        lap_distance,
167        total_distance,
168        safety_car_delta,
169        car_position,
170        current_lap_num,
171        pit_status,
172        sector,
173        current_lap_invalid,
174        penalties,
175        grid_position,
176        driver_status,
177        result_status,
178    })
179}
180
181pub async fn parse_pit_status(cursor: &mut Cursor<Vec<u8>>) -> Result<PitStatus, Error> {
182    match cursor.byte_order().read_u8().await? {
183        0 => Ok(PitStatus::None),
184        1 => Ok(PitStatus::Pitting),
185        2 => Ok(PitStatus::PitArea),
186        _ => Err(Error::new(ErrorKind::InvalidData, "Invalid pit status")),
187    }
188}
189
190pub async fn parse_driver_status(cursor: &mut Cursor<Vec<u8>>) -> Result<DriverStatus, Error> {
191    match cursor.byte_order().read_u8().await? {
192        0 => Ok(DriverStatus::Garage),
193        1 => Ok(DriverStatus::FlyingLap),
194        2 => Ok(DriverStatus::InLap),
195        3 => Ok(DriverStatus::OutLap),
196        4 => Ok(DriverStatus::OnTrack),
197        _ => Err(Error::new(ErrorKind::InvalidData, "Invalid driver status")),
198    }
199}
200
201pub async fn parse_result_status(cursor: &mut Cursor<Vec<u8>>) -> Result<ResultStatus, Error> {
202    match cursor.byte_order().read_u8().await? {
203        0 => Ok(ResultStatus::Invalid),
204        1 => Ok(ResultStatus::Inactive),
205        2 => Ok(ResultStatus::Active),
206        3 => Ok(ResultStatus::Finished),
207        4 => Ok(ResultStatus::Disqualified),
208        5 => Ok(ResultStatus::NotClassified),
209        6 => Ok(ResultStatus::Retired),
210        _ => Err(Error::new(ErrorKind::InvalidData, "Invalid result status")),
211    }
212}
213
214fn ensure_lap_data_size(size: usize) -> Result<(), Error> {
215    if size < LAP_DATA_MIN_SIZE {
216        return Err(Error::new(
217            ErrorKind::InvalidData,
218            "Lap data size is too small",
219        ));
220    }
221
222    return Ok(());
223}