1use std::convert::TryFrom;
2use std::error::Error;
3use std::io::Cursor;
4
5use crate::{
6 TelemetryEvent,
7 TelemetryPacket,
8 f1::util::*,
9 f1::macros::*,
10};
11
12use binread::{BinRead, BinReaderExt};
13use num_enum::TryFromPrimitive;
14use bitflags::bitflags;
15
16pub enum F1_2022 {
21 Motion(Motion),
22 Session(Session),
23 LapData(LapData),
24 Event(Event),
25 Participants(Participants),
26 CarSetup(CarSetup),
27 CarTelemetry(CarTelemetry),
28 CarStatus(CarStatus),
29 FinalClassification(FinalClassification),
30 LobbyInfo(LobbyInfo),
31 CarDamage(CarDamage),
32 SessionHistory(SessionHistory),
33}
34
35#[derive(Debug, Default, BinRead)]
37pub struct Header
38{
39 pub packet_format: u16, pub game_major_version: u8, pub game_minor_version: u8, pub packet_version: u8, pub packet_id: u8, pub session_uid: u64, pub session_time: f32, pub frame_identifier: u32, pub player_car_index: u8, pub secondary_player_car_index: u8, }
51
52#[derive(Debug, BinRead)]
54pub struct Motion {
55 pub header: Header,
56
57 #[br(count = 22)]
58 pub car_motion_data: Vec<CarMotionData>, pub suspension_position: WheelValue<f32>, pub suspension_velocity: WheelValue<f32>, pub suspension_acceleration: WheelValue<f32>, pub wheel_speed: WheelValue<f32>, pub wheel_slip: WheelValue<f32>, pub local_velocity: Coordinates<f32>, pub angular_velocity: Coordinates<f32>, pub angular_acceleration: Coordinates<f32>, pub front_wheel_angle: f32, }
71
72player_data!(Motion, CarMotionData, car_motion_data);
73
74#[derive(Debug, Default, BinRead)]
75pub struct CarMotionData {
76 pub world_position: Coordinates<f32>, pub world_velocity: Coordinates<f32>, pub world_forward_dir: Coordinates<i16>, pub world_right_dir: Coordinates<i16>, pub g_force_lateral: f32, pub g_force_longitudinal: f32, pub g_force_vertical: f32, pub yaw: f32, pub pitch: f32, pub roll: f32, }
87
88#[derive(Debug, BinRead)]
90pub struct Session {
91 pub header: Header,
92 pub weather: Weather, pub track_temperature: i8, pub air_temperature: i8, pub total_laps: u8, pub track_length: u16, pub session_type: SessionType, pub track: Track, pub formula: Formula, pub session_time_left: u16, pub session_duration: u16, pub pit_speed_limit: u8, pub game_paused: u8, pub is_spectating: u8, pub spectator_car_index: u8, pub sli_pro_native_support: u8, pub number_of_marshal_zones: u8, #[br(count = 21)]
114 pub marshal_zones: Vec<MarshalZone>, pub safety_car_status: SafetyCarStatus, #[br(map = |x: u8| x > 0)]
118 pub network_game: bool, pub number_of_weather_forecast_samples: u8, #[br(count = 56)] pub weather_forecast_samples: Vec<WeatherForecastSample>, pub forecast_accuracy: ForecastAccuracy, pub ai_difficulty: u8, pub season_link_identifier: u32, pub weekend_link_identifier: u32, pub session_link_identifier: u32, pub pit_stop_window_ideal_lap: u8, pub pit_stop_window_latest_lap: u8, pub pit_stop_rejoin_position: u8, #[br(map = |x: u8| x > 0)]
131 pub steering_assist: bool, pub braking_assist: BrakingAssist, pub gearbox_assist: GearboxAssist, #[br(map = |x: u8| x > 0)]
135 pub pit_assist: bool, #[br(map = |x: u8| x > 0)]
137 pub pit_release_assist: bool, #[br(map = |x: u8| x > 0)]
139 pub ers_assist: bool, #[br(map = |x: u8| x > 0)]
141 pub drs_assist: bool, pub dynamic_racing_line: RacingLine, pub dynamic_racing_line_type: RacingLineType, pub game_mode: GameMode, pub rule_set: RuleSet, pub time_of_day: u32, pub session_length: SessionLength, }
150
151#[derive(Debug, Default, TryFromPrimitive)]
152#[repr(u8)]
153pub enum Weather {
154 #[default]
155 Clear,
156 LigthCloud,
157 Overcast,
158 LightRain,
159 HeavyRain,
160 Storm,
161 Unknown = 255,
162}
163
164binread_enum!(Weather, u8);
165
166#[derive(Debug, Default, TryFromPrimitive)]
167#[repr(u8)]
168pub enum SessionType {
169 #[default]
170 Unknown,
171 Practice1,
172 Practice2,
173 Practice3,
174 ShortPractice,
175 Qualifier1,
176 Qualifier2,
177 Qualifier3,
178 ShortQualifier,
179 OSQ,
180 Race,
181 Formula2Race,
182 R3,
183 TimeTrial,
184}
185
186binread_enum!(SessionType, u8);
187
188
189#[derive(Debug, Default, TryFromPrimitive)]
190#[repr(i8)]
191pub enum Track {
192 #[default]
193 Unknown = -1,
194 Melbourne,
195 PaulRicard,
196 Shanghai,
197 Sakhir,
198 Catalunya,
199 Monaco,
200 Montreal,
201 Silverstone,
202 Hockenheim,
203 Hungaroring,
204 Spa,
205 Monza,
206 Singapore,
207 Suzuka,
208 AbuDahbi,
209 Texas,
210 Brazil,
211 Austria,
212 Sochi,
213 Mexico,
214 Baku,
215 SakhirShort,
216 SilverstoneShort,
217 TexasShort,
218 SuzukaShort,
219 Hanoi,
220 Zandvoort,
221 Imola,
222 Portimao,
223 Jeddah,
224 Miami,
225}
226
227binread_enum!(Track, i8);
228
229#[derive(Debug, Default, TryFromPrimitive)]
230#[repr(u8)]
231pub enum Formula {
232 #[default]
233 F1Modern,
234 F1Classic,
235 F2,
236 F1Generic,
237 Beta,
238 Supercars,
239 Esports,
240 Unknown = 255,
241}
242
243binread_enum!(Formula, u8);
244
245
246#[derive(Debug, Default, BinRead)]
247pub struct MarshalZone {
248 pub zone_start: f32, pub zone_flag: ZoneFlag, }
251
252#[derive(Debug, Default, TryFromPrimitive)]
253#[repr(i8)]
254pub enum ZoneFlag {
255 #[default]
256 Unknown = -1,
257 None,
258 Green,
259 Blue,
260 Yellow,
261 Red,
262}
263
264binread_enum!(ZoneFlag, i8);
265
266#[derive(Debug, Default, TryFromPrimitive)]
267#[repr(u8)]
268pub enum SafetyCarStatus {
269 #[default]
270 NoSafetyCar,
271 FullSafetyCar,
272 VirtualSafetyCar,
273 FormationLap,
274 Unknown = 255,
275}
276
277binread_enum!(SafetyCarStatus, u8);
278
279#[derive(Debug, Default, BinRead)]
280pub struct WeatherForecastSample {
281 pub session_type: SessionType, pub time_offset: u8, pub weather: Weather, pub track_temperature: i8, pub track_temperature_change: WeatherTemperatureTrend, pub air_temperature: i8, pub air_temperature_change: WeatherTemperatureTrend, pub rain_percentage: u8, }
293
294#[derive(Debug, Default, TryFromPrimitive)]
295#[repr(i8)]
296pub enum WeatherTemperatureTrend {
297 #[default]
298 Unknown = -1,
299 Up,
300 Down,
301 NoChange,
302}
303
304binread_enum!(WeatherTemperatureTrend, i8);
305
306#[derive(Debug, Default, TryFromPrimitive)]
307#[repr(u8)]
308pub enum ForecastAccuracy {
309 #[default]
310 Perfect,
311 Approximate,
312 Unknown = 255,
313}
314
315binread_enum!(ForecastAccuracy, u8);
316
317#[derive(Debug, Default, TryFromPrimitive)]
318#[repr(u8)]
319pub enum BrakingAssist {
320 #[default]
321 Off,
322 Low,
323 Medium,
324 High,
325 Unknown = 255,
326}
327
328binread_enum!(BrakingAssist, u8);
329
330#[derive(Debug, Default, TryFromPrimitive)]
331#[repr(u8)]
332pub enum GearboxAssist {
333 #[default]
334 Manual = 1,
335 ManualAndSuggest,
336 Auto,
337 Unknown = 255,
338}
339
340binread_enum!(GearboxAssist, u8);
341
342#[derive(Debug, Default, TryFromPrimitive)]
343#[repr(u8)]
344pub enum RacingLine {
345 #[default]
346 Off,
347 CornersOnly,
348 Full,
349 Unknown = 255,
350}
351
352binread_enum!(RacingLine, u8);
353
354#[derive(Debug, Default, TryFromPrimitive)]
355#[repr(u8)]
356pub enum RacingLineType {
357 #[default]
358 TwoD,
359 ThreeD,
360 Unknown = 255,
361}
362
363binread_enum!(RacingLineType, u8);
364
365#[derive(Debug, Default, TryFromPrimitive)]
366#[repr(u8)]
367pub enum GameMode {
368 #[default]
369 EventMode,
370 GrandPrix = 3,
371 TimeTrial = 5,
372 Splitscreen,
373 OnlineCustom,
374 OnlineLeague,
375 CareerInvitational = 11,
376 ChampionshipInvitational,
377 Championship,
378 OnlineChampionship,
379 OnlineWeeklyEvent,
380 Career22 = 19,
381 Career22Online,
382 Benchmark = 127,
383 Unknown = 255,
384}
385
386binread_enum!(GameMode, u8);
387
388#[derive(Debug, Default, TryFromPrimitive)]
389#[repr(u8)]
390pub enum RuleSet {
391 #[default]
392 PracticeAndQualifying,
393 Race,
394 TimeTrial,
395 TimeAttack = 4,
396 CheckpointChallenge = 6,
397 Autocross = 8,
398 Drift,
399 AverageSpeedZone,
400 RivalDuel,
401 Unknown = 255,
402}
403
404binread_enum!(RuleSet, u8);
405
406#[derive(Debug, Default, TryFromPrimitive)]
407#[repr(u8)]
408pub enum SessionLength {
409 #[default]
410 None,
411 VeryShort = 2,
412 Short,
413 Medium,
414 MediumLong,
415 Long,
416 Full,
417 Unknown = 255,
418}
419
420binread_enum!(SessionLength, u8);
421
422#[derive(Debug, BinRead)]
424pub struct LapData {
425 pub header: Header,
426 #[br(count = 22)]
427 pub laps: Vec<Lap>, pub time_trial_pb_car_idx: u8, pub time_trial_rival_car_idx: u8, }
431
432player_data!(LapData, Lap, laps);
433
434#[derive(Debug, Default, BinRead)]
435pub struct Lap {
436 pub last_lap_time_ms: u32, pub current_lap_time_ms: u32, pub sector_time_ms: (u16, u16), pub lap_distance: f32, pub total_distance: f32, pub safety_car_delta: f32, pub car_position: u8, pub current_lap_number: u8, pub pit_status: PitStatus, pub num_pit_stops: u8, pub sector: Sector, #[br(map = |x: u8| x > 0)]
450 pub current_lap_invalid: bool, pub penalties: u8, pub warnings: u8, pub num_unserved_drive_through_penalties: u8, pub num_unserved_stop_go_penalties: u8, pub grid_position: u8, pub driver_status: DriverStatus, pub result_status: ResultStatus, #[br(map = |x: u8| x > 0)]
462 pub pit_lane_timer_active: bool, pub pit_lane_time_in_lane_ms: u16, pub pit_stop_timer_ms: u16, pub pit_stop_should_serve_penalty: u8, }
467
468
469
470#[derive(Debug, Default, TryFromPrimitive)]
471#[repr(u8)]
472pub enum PitStatus {
473 #[default]
474 None,
475 Pitting,
476 InPitArea,
477 Unknown = 255,
478}
479
480binread_enum!(PitStatus, u8);
481
482#[derive(Debug, Default, TryFromPrimitive)]
483#[repr(u8)]
484pub enum Sector {
485 Sector1,
486 Sector2,
487 Sector3,
488 #[default]
489 Unknown = 255,
490}
491
492binread_enum!(Sector, u8);
493
494#[derive(Debug, Default, TryFromPrimitive)]
495#[repr(u8)]
496pub enum DriverStatus {
497 InGarage,
498 FlyingLap,
499 InLap,
500 OutLap,
501 OnTrack,
502 #[default]
503 Unknown = 255,
504}
505
506binread_enum!(DriverStatus, u8);
507
508#[derive(Debug, Default, TryFromPrimitive)]
509#[repr(u8)]
510pub enum ResultStatus {
511 Invalid,
512 Inactive,
513 Active,
514 Finished,
515 DidNotFinished,
516 Disqualified,
517 NotClassified,
518 Retired,
519 #[default]
520 Unknown = 255,
521}
522
523binread_enum!(ResultStatus, u8);
524
525#[derive(Debug)]
527pub struct Event {
528 pub header: Header,
529 pub event_data_details: EventDataDetail, }
532
533impl binread::BinRead for Event {
536 type Args = ();
537 fn read_options<R: binread::io::Read + binread::io::Seek>(
538 reader: &mut R,
539 options: &binread::ReadOptions,
540 args: Self::Args,
541 ) -> binread::BinResult<Self> {
542 let header = Header::read_options(reader, options, args)?; let event_code_bytes = <[u8; 4]>::read_options(reader, options, args)?;
546 let event_code = std::str::from_utf8(&event_code_bytes).unwrap_or("UNKW");
547
548 let event_data_details = match event_code {
549 "SSTA" => EventDataDetail::SessionStarted,
550 "SEND" => EventDataDetail::SessionEnded,
551 "FTLP" => {
552 let idx = <u8>::read_options(reader, options, args)?;
553 let time = <f32>::read_options(reader, options, args)?;
554 EventDataDetail::FastestLap(idx, time)
555 }
556 "RTMT" => {
557 let idx = <u8>::read_options(reader, options, args)?;
558 EventDataDetail::Retirement(idx)
559 }
560 "DRSE" => EventDataDetail::DRSEnabled,
561 "DRSD" => EventDataDetail::DRSDisabled,
562 "TMPT" => {
563 let idx = <u8>::read_options(reader, options, args)?;
564 EventDataDetail::TeamMateInPits(idx)
565 }
566 "CHQF" => EventDataDetail::ChequeredFlag,
567 "RCWN" => {
568 let idx = <u8>::read_options(reader, options, args)?;
569 EventDataDetail::RaceWinner(idx)
570 }
571 "PENA" => {
572 let detail = PenaltyEventDetail::read_options(reader, options, args)?;
573 EventDataDetail::Penalty(detail)
574 }
575 "SPTP" => {
576 let detail = SpeedTrapDetail::read_options(reader, options, args)?;
577 EventDataDetail::SpeedTrap(detail)
578 }
579 "STLG" => {
580 let num_lights = <u8>::read_options(reader, options, args)?;
581 EventDataDetail::StartLights(num_lights)
582 }
583 "LGOT" => {
584 EventDataDetail::LightsOut
585 }
586 "DTSV" => {
587 let idx = <u8>::read_options(reader, options, args)?;
588 EventDataDetail::DriveThroughServed(idx)
589 }
590 "SGSV" => {
591 let idx = <u8>::read_options(reader, options, args)?;
592 EventDataDetail::StopGoServed(idx)
593 }
594 "FLBK" => {
595 let flashback_frame_identifier = <u32>::read_options(reader, options, args)?;
596 let flashback_session_time = <f32>::read_options(reader, options, args)?;
597 EventDataDetail::Flashback(flashback_frame_identifier, flashback_session_time)
598 }
599 "BUTN" => {
600 let button_status = ButtonFlags::from_bits(<u32>::read_options(reader, options, args)?).unwrap_or_default();
601 EventDataDetail::ButtonStatus(button_status)
602 }
603 _ => EventDataDetail::Unknown,
604 };
605
606 Ok(Event {
607 header,
608 event_data_details,
609 })
610 }
611}
612
613#[derive(Debug)]
614pub enum EventDataDetail {
615 SessionStarted,
616 SessionEnded,
617 FastestLap(u8, f32), Retirement(u8), DRSEnabled,
621 DRSDisabled,
622 TeamMateInPits(u8), ChequeredFlag,
624 RaceWinner(u8), Penalty(PenaltyEventDetail),
626 SpeedTrap(SpeedTrapDetail),
627 StartLights(u8), LightsOut,
629 DriveThroughServed(u8), StopGoServed(u8), Flashback(u32, f32), ButtonStatus(ButtonFlags), Unknown, }
637
638bitflags! {
639 pub struct ButtonFlags: u32 {
640 const CROSS_OR_A = 0x00000001;
641 const TRIANGLE_OR_Y = 0x00000002;
642 const CIRCLE_OR_B = 0x00000004;
643 const SQUARE_OR_X = 0x00000008;
644 const D_PAD_LEFT = 0x00000010;
645 const D_PAD_RIGHT = 0x00000020;
646 const D_PAD_UP = 0x00000040;
647 const D_PAD_DOWN = 0x00000080;
648 const OPTIONS_OR_MENU = 0x00000100;
649 const L1_OR_LB = 0x00000200;
650 const R1_OR_RB = 0x00000400;
651 const L2_OR_LT = 0x00000800;
652 const R2_OR_RT = 0x00001000;
653 const LEFT_STICK_CLICK = 0x00002000;
654 const RIGHT_STICK_CLICK = 0x00004000;
655 const RIGHT_STICK_LEFT = 0x00008000;
656 const RIGHT_STICK_RIGHT = 0x00010000;
657 const RIGHT_STICK_UP = 0x00020000;
658 const RIGHT_STICK_DOWN = 0x00040000;
659 const SPECIAL = 0x00080000;
660 const UDP_ACTION_1 = 0x00100000;
661 const UDP_ACTION_2 = 0x00200000;
662 const UDP_ACTION_3 = 0x00400000;
663 const UDP_ACTION_4 = 0x00800000;
664 const UDP_ACTION_5 = 0x01000000;
665 const UDP_ACTION_6 = 0x02000000;
666 const UDP_ACTION_7 = 0x04000000;
667 const UDP_ACTION_8 = 0x08000000;
668 const UDP_ACTION_9 = 0x10000000;
669 const UDP_ACTION_10 = 0x20000000;
670 const UDP_ACTION_11 = 0x40000000;
671 const UDP_ACTION_12 = 0x80000000;
672 }
673}
674
675impl Default for ButtonFlags {
676 fn default() -> Self {
677 ButtonFlags::empty()
678 }
679}
680
681#[derive(Debug, Default, BinRead)]
682pub struct PenaltyEventDetail {
683 pub penalty_type: PenaltyType, pub infrigement_type: InfringementType, pub vehicle_index: u8, pub other_vehicle_index: u8, pub time: u8, pub lap_number: u8, pub places_gained: u8, }
691
692#[derive(Debug, Default, TryFromPrimitive)]
693#[repr(u8)]
694pub enum PenaltyType {
695 DriveThrough,
696 StopGo,
697 GridPenalty,
698 PenaltyReminder,
699 TimePenalty,
700 Warning,
701 Disqualified,
702 RemovedFromFormationLap,
703 ParkedTooLongTimer,
704 TyreRegulations,
705 ThisLapInvalidated,
706 ThisAndNextLapInvalidated,
707 ThisLapInvalidatedWithNoReason,
708 ThisAndNextLapInvalidatedWithNoReason,
709 ThisAndPreviousLapInvalidated,
710 ThisAndPreviousLapInvalidatedWithNoReason,
711 Retired,
712 BlackFlagTimer,
713 #[default]
714 Unknown = 255,
715}
716
717binread_enum!(PenaltyType, u8);
718
719#[derive(Debug, Default, TryFromPrimitive)]
720#[repr(u8)]
721pub enum InfringementType {
722 BlockingBySlowDriving,
723 BlockingByWrongWayDriving,
724 ReversingOffTheStartLine,
725 BigCollision,
726 SmallCollision,
727 CollisionFailedToHandBackPositionSingle,
728 CollisionFailedToHandBackPositionMultiple,
729 CornerCuttingGainedTime,
730 CornerCuttingOvertakeSingle,
731 CornerCuttingOvertakeMultiple,
732 CrossedPitExitLane,
733 IgnoringBlueFlags,
734 IgnoringYellowFlags,
735 IgnoringDriveThrough,
736 TooManyDriveThroughs,
737 DriveThroughReminderServeWithinNLaps,
738 DriveThroughReminderServeThisLap,
739 PitLaneSpeeding,
740 ParkedForTooLong,
741 IgnoringTyreRegulations,
742 TooManyPenalties,
743 MultipleWarnings,
744 ApproachingDisqualification,
745 TyreRegulationsSelectSingle,
746 TyreRegulationsSelectMultiple,
747 LapInvalidatedCornerCutting,
748 LapInvalidatedRunningWide,
749 CornerCuttingRanWideGainedTimeMinor,
750 CornerCuttingRanWideGainedTimeSignificant,
751 CornerCuttingRanWideGainedTimeExtreme,
752 LapInvalidatedWallRiding,
753 LapInvalidatedFlashbackUsed,
754 LapInvalidatedResetToTrack,
755 BlockingThePitlane,
756 JumpStart,
757 SafetyCarToCarCollision,
758 SafetyCarIllegalOvertake,
759 SafetyCarExceedingAllowedPace,
760 VirtualSafetyCarExceedingAllowedPace,
761 FormationLapBelowAllowedSpeed,
762 FormationLapParking,
763 RetiredMechanicalFailure,
764 RetiredTerminallyDamaged,
765 SafetyCarFallingTooFarBack,
766 BlackFlagTimer,
767 UnservedStopGoPenalty,
768 UnservedDriveThroughPenalty,
769 EngineComponentChange,
770 GearboxChange,
771 ParcFermeChange,
772 LeagueGridPenalty,
773 RetryPenalty,
774 IllegalTimeGain,
775 MandatoryPitstop,
776 AttributeAssigned,
777 #[default]
778 Unknown = 255,
779}
780
781binread_enum!(InfringementType, u8);
782
783#[derive(Debug, Default, BinRead)]
784pub struct SpeedTrapDetail {
785 pub vehicle_index: u8, pub speed: f32, #[br(map = |x: u8| x > 0)]
788 pub is_overall_fastest_in_session: bool, #[br(map = |x: u8| x > 0)]
790 pub is_driver_fastest_in_session: bool, pub fastest_vehicle_index_in_session: u8, pub fastest_speed_in_session: f32, }
796
797#[derive(Debug, BinRead)]
799pub struct Participants {
800 pub header: Header,
801 pub num_active_cars: u8, #[br(count = 22)]
804 pub participants_data: Vec<ParticipantsData>,
805}
806
807player_data!(Participants, ParticipantsData, participants_data);
808
809#[derive(Debug, Default, BinRead)]
810pub struct ParticipantsData {
811 #[br(map = |x: u8| x > 0)]
812 pub ai_controlled: bool, pub driver: Driver, pub network_id: u8, pub team: Team, #[br(map = |x: u8| x > 1)]
817 pub my_team: bool, pub race_number: u8, pub nationality: Nationality, #[br(parse_with = participant_name_parser)]
821 pub name: String, #[br(map = |x: u8| x > 1)]
824 pub your_telemetry_public: bool, }
826
827fn participant_name_parser<R: binread::io::Read + binread::io::Seek>(
828 reader: &mut R,
829 _: &binread::ReadOptions,
830 _: (),
831) -> binread::BinResult<String> {
832 let mut bytes: [u8; 48] = [0; 48]; reader.read_exact(&mut bytes)?;
834
835 let driver_name = std::str::from_utf8(&bytes)
836 .unwrap_or("UNKW")
837 .trim_matches(char::from(0)); Ok(String::from(driver_name))
840}
841
842
843#[derive(Debug, Default, TryFromPrimitive)]
844#[repr(u8)]
845pub enum Driver {
846 CarlosSainz,
847 DaniilKvyat,
848 DanielRicciardo,
849 FernandoAlonso,
850 FelipeMassa,
851 KimiRaikkonen = 6,
852 LewisHamilton,
853 MaxVerstappen = 9,
854 NicoHulkenburg,
855 KevinMagnussen,
856 RomainGrosjean,
857 SebastianVettel,
858 SergioPerez,
859 ValtteriBottas,
860 EstebanOcon = 17,
861 LanceStroll = 19,
862 ArronBarnes,
863 MartinGiles,
864 AlexMurray,
865 LucasRoth,
866 IgorCorreia,
867 SophieLevasseur,
868 JonasSchiffer,
869 AlainForest,
870 JayLetourneau,
871 EstoSaari,
872 YasarAtiyeh,
873 CallistoCalabresi,
874 NaotaIzum,
875 HowardClarke,
876 WilheimKaufmann,
877 MarieLaursen,
878 FlavioNieves,
879 PeterBelousov,
880 KlimekMichalski,
881 SantiagoMoreno,
882 BenjaminCoppens,
883 NoahVisser,
884 GertWaldmuller,
885 JulianQuesada,
886 DanielJones,
887 ArtemMarkelov,
888 TadasukeMakino,
889 SeanGelael,
890 NyckDeVries,
891 JackAitken,
892 GeorgeRussell,
893 MaximilianGunther,
894 NireiFukuzumi,
895 LucaGhiotto,
896 LandoNorris,
897 SergioSetteCamara,
898 LouisDeletraz,
899 AntonioFuoco,
900 CharlesLeclerc,
901 PierreGasly,
902 AlexanderAlbon = 62,
903 NicholasLatifi,
904 DorianBoccolacci,
905 NikoKari,
906 RobertoMerhi,
907 ArjunMaini,
908 AlessioLorandi,
909 RubenMeijer,
910 RashidNair,
911 JackTremblay,
912 DevonButler,
913 LukasWeber,
914 AntonioGiovinazzi,
915 RobertKubica,
916 AlainProst,
917 AyrtonSenna,
918 NobuharuMatsushita,
919 NikitaMazepin,
920 GuanyaZhou,
921 MickSchumacher,
922 CallumIlott,
923 JuanManuelCorrea,
924 JordanKing,
925 MahaveerRaghunathan,
926 TatianaCalderon,
927 AnthoineHubert,
928 GuilianoAlesi,
929 RalphBoschung,
930 MichaelSchumacher,
931 DanTicktum,
932 MarcusArmstrong,
933 ChristianLundgaard,
934 YukiTsunoda,
935 JehanDaruvala,
936 GulhermeSamaia,
937 PedroPiquet,
938 FelipeDrugovich,
939 RobertSchwartzman,
940 RoyNissany,
941 MarinoSato,
942 AidanJackson,
943 CasperAkkerman,
944 JensonButton = 109,
945 DavidCoulthard,
946 NicoRosberg,
947 OscarPiastri,
948 LiamLawson,
949 JuriVips,
950 TheoPourchaire,
951 RichardVerschoor,
952 LirimZendeli,
953 DavidBeckmann,
954 AlessioDeledda = 121,
955 BentViscaal,
956 EnzoFittipaldi,
957 MarkWebber = 125,
958 JacquesVilleneuve,
959 JakeHughes,
960 FrederikVesti,
961 OlliCaldwell,
962 LoganSargeant,
963 CemBolukbasi,
964 AyumaIwasa,
965 ClementNovolak,
966 DennisHauger,
967 CalanWilliams,
968 JackDoohan,
969 AmauryCordeel,
970 MikaHakkinen,
971
972 #[default]
973 Unknown,
974 Human = 255, }
976
977binread_enum!(Driver, u8);
978
979#[derive(Debug, Default, TryFromPrimitive)]
980#[repr(u8)]
981pub enum Team {
982 Mercedes,
983 Ferrari,
984 RedBullRacing,
985 Williams,
986 AstonMartin,
987 Alpine,
988 AlphaTauri,
989 Haas,
990 McLaren,
991 AlfaRomeo,
992 Mercedes2020 = 85,
993 Ferrari2020,
994 RedBull2020,
995 Williams2020,
996 RacingPoint2020,
997 Renault2020,
998 AlphaTauri2020,
999 Haas2020,
1000 McLaren2020,
1001 AlfaRomeo2020,
1002 AstonMartinDB11V12,
1003 AstonMartinVantageF1Edition,
1004 AstonMartinVantageSafetyCar,
1005 FerrariF8Tributo,
1006 FerrariRoma,
1007 McLaren720S,
1008 McLarenArtura,
1009 MercedesAMGGTBlackSeriesSafetyCar,
1010 MercedesAMGGTRPro,
1011 F1CustomTeam,
1012 Prema2021,
1013 UniVirtuosi2021,
1014 Carlin2021,
1015 Hitech2021,
1016 ArtGP2021,
1017 MPMotorsport2021,
1018 Charouz2021,
1019 Dams2021,
1020 Campos2021,
1021 BWT2021,
1022 Trident2021,
1023 MercedesAMGGTBlackSeries,
1024 Prema2022,
1025 Virtuosi2022,
1026 Carlin2022,
1027 Hitech2022,
1028 ArtGP2022,
1029 MPMotorsport2022,
1030 Charouz2022,
1031 Dams2022,
1032 Campos2022,
1033 VanAmersfoortRacing2022,
1034 Trident2022,
1035 #[default]
1036 Unknown = 255,
1037}
1038
1039binread_enum!(Team, u8);
1040
1041#[derive(Debug, Default, TryFromPrimitive)]
1042#[repr(u8)]
1043pub enum Nationality {
1044 #[default]
1045 Unknown,
1046 American,
1047 Argentinean,
1048 Australian,
1049 Austrian,
1050 Azerbaijani,
1051 Bahraini,
1052 Belgian,
1053 Bolivian,
1054 Brazilian,
1055 British,
1056 Bulgarian,
1057 Cameroonian,
1058 Canadian,
1059 Chilean,
1060 Chinese,
1061 Colombian,
1062 CostaRican,
1063 Croatian,
1064 Cypriot,
1065 Czech,
1066 Danish,
1067 Dutch,
1068 Ecuadorian,
1069 English,
1070 Emirian,
1071 Estonian,
1072 Finnish,
1073 French,
1074 German,
1075 Ghanaian,
1076 Greek,
1077 Guatemalan,
1078 Honduran,
1079 HongKonger,
1080 Hungarian,
1081 Icelander,
1082 Indian,
1083 Indonesian,
1084 Irish,
1085 Israeli,
1086 Italian,
1087 Jamaican,
1088 Japanese,
1089 Jordanian,
1090 Kuwaiti,
1091 Latvian,
1092 Lebanese,
1093 Lithuanian,
1094 Luxembourger,
1095 Malaysian,
1096 Maltese,
1097 Mexican,
1098 Monegasque,
1099 NewZealander,
1100 Nicaraguan,
1101 NorthernIrish,
1102 Norwegian,
1103 Omani,
1104 Pakistani,
1105 Panamanian,
1106 Paraguayan,
1107 Peruvian,
1108 Polish,
1109 Portuguese,
1110 Qatari,
1111 Romanian,
1112 Russian,
1113 Salvadoran,
1114 Saudi,
1115 Scottish,
1116 Serbian,
1117 Singaporean,
1118 Slovakian,
1119 Slovenian,
1120 SouthKorean,
1121 SouthAfrican,
1122 Spanish,
1123 Swedish,
1124 Swiss,
1125 Thai,
1126 Turkish,
1127 Uruguayan,
1128 Ukrainian,
1129 Venezuelan,
1130 Barbadian,
1131 Welsh,
1132 Vietnamese,
1133}
1134
1135binread_enum!(Nationality, u8);
1136
1137#[derive(Debug, BinRead)]
1139pub struct CarSetup {
1140 pub header: Header,
1141 #[br(count = 22)]
1142 pub car_setup_data: Vec<CarSetupData>,
1143}
1144
1145player_data!(CarSetup, CarSetupData, car_setup_data);
1146
1147#[derive(Debug, Default, BinRead)]
1148pub struct CarSetupData {
1149 pub wing: FrontRearValue<u8>, pub on_throttle: u8, pub off_throttle: u8, pub camber: FrontRearValue<f32>, pub toe: FrontRearValue<f32>, pub suspension: FrontRearValue<u8>, pub anti_roll_bar: FrontRearValue<u8>, pub suspension_height: FrontRearValue<u8>, pub brake_pressure: u8, pub brake_bias: u8, pub type_pressure: WheelValue<f32>, pub ballast: u8, pub fuel_load: f32, }
1163
1164#[derive(Debug, BinRead)]
1166pub struct CarTelemetry {
1167 pub header: Header,
1168 #[br(count = 22)]
1169 pub car_telemetry_data: Vec<CarTelemetryData>,
1170 pub mfd_panel: MFDPanel, pub mfd_panel_secondary_player: MFDPanel, #[br(map = |x: i8| if x == 0 { Gear::Unknown } else { Gear::try_from(x).unwrap() })]
1176 pub suggested_gear: Gear, }
1179
1180player_data!(CarTelemetry, CarTelemetryData, car_telemetry_data);
1181
1182#[derive(Debug, Default, BinRead)]
1183pub struct CarTelemetryData {
1184 pub speed: u16, pub throttle: f32, pub steer: f32, pub brake: f32, pub clutch: u8, #[br(map = |x: i8| Gear::try_from(x).unwrap())]
1190 pub gear: Gear, pub engine_rpm: u16, #[br(map = |x: u8| x > 0)]
1193 pub drs: bool, pub rev_lights_percent: u8, pub rev_lights_bit_value: u16, pub brake_temp: WheelValue<u16>, pub tyres_surface_temp: WheelValue<u8>, pub tyres_inner_temp: WheelValue<u8>, pub engine_temp: u16, pub tyres_pressure: WheelValue<f32>, #[br(parse_with = surface_type_parser)]
1202 pub surface_type: WheelValue<Surface>, }
1204
1205#[derive(Debug, Default, TryFromPrimitive)]
1206#[repr(i8)]
1207pub enum Gear {
1208 Reverse = -1,
1209 Neutral,
1210 First,
1211 Second,
1212 Third,
1213 Fourth,
1214 Fifth,
1215 Sixth,
1216 Seventh,
1217 Eigth,
1218 #[default]
1219 Unknown = 127,
1220}
1221
1222binread_enum!(Gear, i8);
1223
1224#[derive(Debug, Default, TryFromPrimitive)]
1225#[repr(u8)]
1226pub enum Surface {
1227 Tarmac,
1228 RumbleStrip,
1229 Concrete,
1230 Rock,
1231 Gravel,
1232 Mud,
1233 Sand,
1234 Grass,
1235 Water,
1236 Cobblestone,
1237 Metal,
1238 Ridged,
1239 #[default]
1240 Unknown = 255,
1241}
1242
1243binread_enum!(Surface, u8);
1244
1245fn surface_type_parser<R: binread::io::Read + binread::io::Seek>(
1246 reader: &mut R,
1247 _: &binread::ReadOptions,
1248 _: (),
1249) -> binread::BinResult<WheelValue<Surface>> {
1250 let mut bytes: [u8; 4] = [0; 4];
1251 reader.read_exact(&mut bytes)?;
1252
1253 Ok(WheelValue::<Surface> {
1254 rear_left: Surface::try_from(bytes[0]).unwrap_or(Surface::Unknown),
1255 rear_right: Surface::try_from(bytes[1]).unwrap_or(Surface::Unknown),
1256 front_left: Surface::try_from(bytes[2]).unwrap_or(Surface::Unknown),
1257 front_right: Surface::try_from(bytes[3]).unwrap_or(Surface::Unknown),
1258 })
1259}
1260
1261#[derive(Debug, Default, TryFromPrimitive)]
1262#[repr(u8)]
1263pub enum MFDPanel {
1264 CarSetup,
1265 Pits,
1266 Damage,
1267 Engine,
1268 Temperatures,
1269 #[default]
1270 Unknown = 128,
1271 Closed = 255,
1272}
1273
1274binread_enum!(MFDPanel, u8);
1275
1276#[derive(Debug, BinRead)]
1280pub struct CarStatus {
1281 pub header: Header,
1282 #[br(count = 22)]
1283 pub car_status_data: Vec<CarStatusData>,
1284}
1285
1286player_data!(CarStatus, CarStatusData, car_status_data);
1287
1288#[derive(Debug, Default, BinRead)]
1289pub struct CarStatusData {
1290 pub traction_control: u8, #[br(map = |x: u8| x > 0)]
1292 pub anti_lock_brakes: bool, pub fuel_mix: FuelMix, pub front_brake_bias: u8, #[br(map = |x: u8| x > 0)]
1296 pub pit_limiter_status: bool, pub fuel_in_tank: f32, pub fuel_capacity: f32, pub fuel_remaining_laps: f32, pub max_rpm: u16, pub idle_rpm: u16, pub max_gears: u8, #[br(map = |x: u8| x > 0)]
1304 pub drs_allowed: bool, #[br(map = |x: u16| if x > 0 { DRSActivationDistance::Distance(x) } else { DRSActivationDistance::NotAvailable })]
1306 pub drs_activation_distance: DRSActivationDistance, pub tyres_compound: TyreCompound, pub tyres_visual: TyreVisual, pub tyres_ages_lap: u8, pub vehicle_fia_flag: FiaFlag, pub ers_data: ERS, pub network_paused: u8, }
1324
1325#[derive(Debug, Default, TryFromPrimitive)]
1326#[repr(u8)]
1327pub enum FuelMix {
1328 Lean,
1329 Standard,
1330 Rich,
1331 Max,
1332 #[default]
1333 Unknown,
1334}
1335
1336binread_enum!(FuelMix, u8);
1337
1338#[derive(Debug, Default)]
1339#[repr(u16)]
1340pub enum DRSActivationDistance {
1341 #[default]
1342 NotAvailable,
1343 Distance(u16),
1344}
1345
1346#[derive(Debug, Default, TryFromPrimitive)]
1347#[repr(u8)]
1348pub enum TyreCompound {
1349 Inter = 7,
1350 Wet,
1351 F1ClassicDry,
1352 F1ClassicWet,
1353 F2SuperSoft,
1354 F2Soft,
1355 F2Medium,
1356 F2Hard,
1357 F2Wet,
1358 C5,
1359 C4,
1360 C3,
1361 C2,
1362 C1,
1363 #[default]
1364 Unknown,
1365}
1366
1367binread_enum!(TyreCompound, u8);
1368
1369#[derive(Debug, Default, TryFromPrimitive)]
1370#[repr(u8)]
1371pub enum TyreVisual {
1372 Inter = 7,
1373 Wet,
1374 ClassicDry = 9,
1375 ClassicWet,
1376 F2Wet = 15,
1377 Soft,
1378 Medium,
1379 Hard,
1380 F2SuperSoft,
1381 F2Soft,
1382 F2Medium,
1383 F2Hard,
1384 #[default]
1385 Unknown = 255,
1386}
1387
1388binread_enum!(TyreVisual, u8);
1389
1390#[derive(Debug, Default, TryFromPrimitive)]
1391#[repr(i8)]
1392pub enum FiaFlag {
1393 #[default]
1394 Unknown = -1,
1395 None,
1396 Green,
1397 Blue,
1398 Yellow,
1399 Red,
1400}
1401
1402binread_enum!(FiaFlag, i8);
1403
1404#[derive(Debug, Default, BinRead)]
1405pub struct ERS {
1406 pub stored_energy: f32, pub deploy_mode: ERSDeployMode, pub harvested_this_lap_mguk: f32, pub harvested_this_lap_mguh: f32, pub deployed_this_lap: f32, }
1413
1414#[derive(Debug, Default, TryFromPrimitive)]
1415#[repr(u8)]
1416pub enum ERSDeployMode {
1417 None,
1418 Medium,
1419 Hotlap,
1420 Overtake,
1421 #[default]
1422 Unknown = 255,
1423}
1424
1425binread_enum!(ERSDeployMode, u8);
1426
1427#[derive(Debug, BinRead)]
1429pub struct FinalClassification {
1430 pub header: Header,
1431 pub number_of_cars: u8, #[br(count = 22)]
1433 pub final_classification_data: Vec<FinalClassificationData>,
1434}
1435
1436player_data!(FinalClassification, FinalClassificationData, final_classification_data);
1437
1438#[derive(Debug, Default, BinRead)]
1439pub struct FinalClassificationData {
1440 pub position: u8, pub number_of_laps: u8, pub grid_position: u8, pub points: u8, pub number_of_pit_stops: u8, pub result_status: ResultStatus, pub best_lap_time_ms: u32, pub total_race_time: f64, pub penalties_time_s: u8, pub number_of_penalties: u8, pub number_of_tyre_stints: u8, #[br(count = 8)]
1454 pub tyre_stints_actual: Vec<TyreCompound>, #[br(count = 8)]
1456 pub tyre_stints_visual: Vec<TyreVisual>, #[br(count = 8)]
1458 pub tyre_stints_end_laps: Vec<u8>, }
1460
1461#[derive(Debug, BinRead)]
1463pub struct LobbyInfo {
1464 pub header: Header,
1465 pub number_of_players: u8, #[br(count = 22)]
1467 pub lobby_players: Vec<LobbyInfoData>,
1468}
1469
1470player_data!(LobbyInfo, LobbyInfoData, lobby_players);
1471
1472impl LobbyInfo {
1473 pub fn players(self) -> Vec<LobbyInfoData> {
1474 let number_of_players = self.number_of_players as usize;
1475 self.lobby_players
1476 .into_iter()
1477 .take(number_of_players)
1478 .collect()
1479 }
1480}
1481
1482#[derive(Debug, Default, BinRead)]
1483pub struct LobbyInfoData {
1484 #[br(map = |x: u8| x > 0)]
1485 pub ai_controlled: bool, pub team: Team, pub nationality: Nationality, #[br(parse_with = participant_name_parser)]
1489 pub name: String, pub car_number: u8, pub status: LobbyStatus, }
1494
1495#[derive(Debug, Default, TryFromPrimitive)]
1496#[repr(u8)]
1497pub enum LobbyStatus {
1498 NotReady,
1499 Ready,
1500 Spectating,
1501 #[default]
1502 Unknown,
1503}
1504
1505binread_enum!(LobbyStatus, u8);
1506
1507#[derive(Debug, BinRead)]
1509pub struct CarDamage {
1510 pub header: Header,
1511 #[br(count = 22)]
1512 pub car_damage_data: Vec<CarDamageData>,
1513}
1514
1515player_data!(CarDamage, CarDamageData, car_damage_data);
1516
1517#[derive(Debug, Default, BinRead)]
1518pub struct CarDamageData
1519{
1520 pub tyres_wear: WheelValue<u8>, pub tyres_damage: WheelValue<u8>, pub brakes_damage: WheelValue<u8>, pub wing_damage: WingValue<u8>, pub floor_damage: u8, pub diffuser_damage: u8, pub sidepod_damage: u8, #[br(map = |x: u8| x > 0)]
1528 pub drs_fault: bool, #[br(map = |x: u8| x > 0)]
1530 pub ers_fault: bool, pub gear_box_damage: u8, pub engine_damage: u8, pub engine_mguh_wear: u8, pub engine_es_wear: u8, pub engine_ce_wear: u8, pub engine_ice_wear: u8, pub engine_mguk_wear: u8, pub engine_tc_wear: u8, #[br(map = |x: u8| x > 0)]
1540 pub engine_blown: bool, #[br(map = |x: u8| x > 0)]
1542 pub engine_seized: bool, }
1544
1545#[derive(Debug, BinRead)]
1547pub struct SessionHistory
1548{
1549 pub header: Header, pub car_index: u8, pub num_laps: u8, pub num_tyre_stints: u8, pub best_lap_time_lap_num: u8, pub best_sector1_lap_num: u8, pub best_sector2_lap_num: u8, pub best_sector3_lap_num: u8, #[br(count = 100)]
1558 pub lap_history_data: Vec<LapHistoryData>, #[br(count = 8)]
1560 pub tyre_stints_history_data: Vec<TyreStintHistoryData>,
1561}
1562
1563#[derive(Debug, Default, BinRead)]
1564pub struct LapHistoryData
1565{
1566 pub lap_time_ms: u32, pub sector_times_ms: (u16, u16, u16), #[br(parse_with = lap_valid_flags_aprser)]
1570 pub lap_valid_bit_flags: LapValidFlags, }
1573
1574bitflags! {
1575 pub struct LapValidFlags: u8 {
1576 const LAP_VALID = 0x01;
1577 const SECTOR_1_VALID = 0x02;
1578 const SECTOR_2_VALID = 0x04;
1579 const SECTOR_3_VALID = 0x08;
1580 }
1581}
1582
1583impl Default for LapValidFlags {
1584 fn default() -> Self {
1585 LapValidFlags::empty()
1586 }
1587}
1588
1589fn lap_valid_flags_aprser<R: binread::io::Read + binread::io::Seek>(
1590 reader: &mut R,
1591 _: &binread::ReadOptions,
1592 _: (),
1593) -> binread::BinResult<LapValidFlags> {
1594 let mut bytes: [u8; 1] = [0; 1];
1595 reader.read_exact(&mut bytes)?;
1596
1597 Ok(LapValidFlags::from_bits(bytes[0]).unwrap_or_default())
1598}
1599
1600#[derive(Debug, Default, BinRead)]
1601pub struct TyreStintHistoryData
1602{
1603 pub end_lap: u8, pub tyre_actual_compound: TyreCompound, pub tyre_visual_compound: TyreVisual, }
1607
1608impl TelemetryEvent for F1_2022 {
1610 fn from_packet(packet: &TelemetryPacket) -> Result<F1_2022, Box<dyn Error>> {
1611 if packet.len() < 24 {
1612 return Err(Box::from("Packet is too small to contain a header"));
1613 }
1614
1615 let packet_id = packet[5]; let mut reader = Cursor::new(packet);
1617 match packet_id {
1618 0 => {
1619 let data: Motion = reader.read_le()?;
1620 Ok(F1_2022::Motion(data))
1621 }
1622 1 => {
1623 let data: Session = reader.read_le()?;
1624 Ok(F1_2022::Session(data))
1625 }
1626 2 => {
1627 let data: LapData = reader.read_le()?;
1628 Ok(F1_2022::LapData(data))
1629 }
1630 3 => {
1631 let data: Event = reader.read_le()?;
1632 Ok(F1_2022::Event(data))
1633 }
1634 4 => {
1635 let data: Participants = reader.read_le()?;
1636 Ok(F1_2022::Participants(data))
1637 }
1638 5 => {
1639 let data: CarSetup = reader.read_le()?;
1640 Ok(F1_2022::CarSetup(data))
1641 }
1642 6 => {
1643 let data: CarTelemetry = reader.read_le()?;
1644 Ok(F1_2022::CarTelemetry(data))
1645 }
1646 7 => {
1647 let data: CarStatus = reader.read_le()?;
1648 Ok(F1_2022::CarStatus(data))
1649 }
1650 8 => {
1651 let data: FinalClassification = reader.read_le()?;
1652 Ok(F1_2022::FinalClassification(data))
1653 }
1654 9 => {
1655 let data: LobbyInfo = reader.read_le()?;
1656 Ok(F1_2022::LobbyInfo(data))
1657 }
1658 10 => {
1659 let data: CarDamage = reader.read_le()?;
1660 Ok(F1_2022::CarDamage(data))
1661 }
1662 11 => {
1663 let data: SessionHistory = reader.read_le()?;
1664 Ok(F1_2022::SessionHistory(data))
1665 }
1666 id => Err(Box::from(format!("Unknown packet type: {}", id))),
1667 }
1668 }
1669}