f1_telemetry_client/f1_2020/
lap.rs1use 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 pub last_lap_time: Duration,
42 pub current_lap_time: Duration,
44 pub sector_1_time: Duration,
46 pub sector_2_time: Duration,
48 pub best_lap_time: Duration,
50 pub best_lap_num: u8,
51 pub best_lap_sector_1_time: Duration,
53 pub best_lap_sector_2_time: Duration,
55 pub best_lap_sector_3_time: Duration,
57 pub best_overall_sector_1_time: Duration,
59 pub best_overall_sector_1_lap_num: u8,
60 pub best_overall_sector_2_time: Duration,
62 pub best_overall_sector_2_lap_num: u8,
63 pub best_overall_sector_3_time: Duration,
65 pub best_overall_sector_3_lap_num: u8,
66 pub lap_distance: f32,
68 pub total_distance: f32,
70 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?); let current_lap_time =
113 Duration::from_secs_f32(cursor.byte_order().read_f32::<LittleEndian>().await?); let sector_1_time =
115 Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); let sector_2_time =
117 Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); let best_lap_time =
119 Duration::from_secs_f32(cursor.byte_order().read_f32::<LittleEndian>().await?); 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); let best_lap_sector_2_time =
124 Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); let best_lap_sector_3_time =
126 Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); let best_overall_sector_1_time =
128 Duration::from_millis(cursor.byte_order().read_u16::<LittleEndian>().await? as u64); 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); 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); 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?); 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}