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;
14
15pub enum F1_2020 {
18 Motion(Motion),
19 Session(Session),
20 LapData(LapData),
21 Event(Event),
22 Participants(Participants),
23 CarSetup(CarSetup),
24 CarTelemetry(CarTelemetry),
25 CarStatus(CarStatus),
26 FinalClassification(FinalClassification),
27 LobbyInfo(LobbyInfo),
28}
29
30#[derive(Debug, Default, BinRead)]
31pub struct Header {
32 pub packet_format: u16,
33 pub game_major_version: u8,
34 pub game_minor_version: u8,
35 pub packet_version: u8,
36 pub packet_id: u8,
37 pub session_uid: u64,
38 pub session_time: f32,
39 pub frame_identifier: u32,
40 pub player_car_index: u8,
41 pub secondary_player_car_index: u8,
42}
43
44#[derive(Debug, BinRead)]
45pub struct Motion {
46 pub header: Header,
47 #[br(count = 22)]
48 pub car_motion_data: Vec<CarMotionData>,
49 pub suspension_position: WheelValue<f32>,
50 pub suspension_velocity: WheelValue<f32>,
51 pub suspension_acceleration: WheelValue<f32>,
52 pub wheel_speed: WheelValue<f32>,
53 pub wheel_slip: WheelValue<f32>,
54 pub local_velocity: Coordinates<f32>,
55 pub angular_velocity: Coordinates<f32>,
56 pub angular_acceleration: Coordinates<f32>,
57 pub front_wheel_angle: f32,
58}
59
60player_data!(Motion, CarMotionData, car_motion_data);
61
62#[derive(Debug, Default, BinRead)]
63pub struct CarMotionData {
64 pub world_position: Coordinates<f32>,
65 pub world_velocity: Coordinates<f32>,
66 pub world_forward_dir: Coordinates<i16>,
67 pub world_right_dir: Coordinates<i16>,
68 pub g_force_lateral: f32,
69 pub g_force_longitudinal: f32,
70 pub g_force_vertical: f32,
71 pub yaw: f32,
72 pub pitch: f32,
73 pub roll: f32,
74}
75
76#[derive(Debug, BinRead)]
77pub struct Session {
78 pub header: Header,
79 pub weather: Weather,
80 pub track_temperature: i8,
81 pub air_temperature: i8,
82 pub total_laps: i8,
83 pub track_length: i16,
84 pub session_type: SessionType,
85 pub track: Track,
86 pub formula: Formula,
87 pub session_time_left: u16,
88 pub session_duration: u16,
89 pub pit_speed_limit: u8,
90 pub game_paused: u8,
91 pub is_spectating: u8,
92 pub spectator_car_index: u8,
93 pub sli_pro_native_support: u8,
94 pub number_of_marshal_zones: u8,
95 pub marshal_zones: [MarshalZone; 21],
96 pub safety_car_status: SafetyCarStatus,
97 #[br(map = |x: u8| x > 0)]
98 pub network_game: bool,
99 pub number_of_weather_forecast_samples: u8,
100 pub weather_forecast_samples: [WeatherForecastSample; 20],
101}
102
103impl Session {
104 pub fn current_weather_forecast_sample(&self) -> &WeatherForecastSample {
105 let mut current_weather_forecast_sample_index =
106 self.number_of_weather_forecast_samples as usize;
107 if current_weather_forecast_sample_index > 0 {
108 current_weather_forecast_sample_index -= 1;
109 }
110 &self.weather_forecast_samples[current_weather_forecast_sample_index]
111 }
112}
113
114#[derive(Debug, Default, TryFromPrimitive)]
115#[repr(u8)]
116pub enum Weather {
117 Clear,
118 LigthCloud,
119 Overcast,
120 LightRain,
121 HeavyRain,
122 Storm,
123 #[default]
124 Unknown = 255,
125}
126
127binread_enum!(Weather, u8);
128
129#[derive(Debug, Default, TryFromPrimitive)]
130#[repr(i8)]
131pub enum Track {
132 #[default]
133 Unknown = -1,
134 Melbourne,
135 PaulRicard,
136 Shanghai,
137 Sakhir,
138 Catalunya,
139 Monaco,
140 Montreal,
141 Silverstone,
142 Hockenheim,
143 Hungaroring,
144 Spa,
145 Monza,
146 Singapore,
147 Suzuka,
148 AbuDahbi,
149 Texas,
150 Brazil,
151 Austria,
152 Sochi,
153 Mexico,
154 Baku,
155 SakhirShort,
156 SilverstoneShort,
157 TexasShort,
158 SuzukaShort,
159 Hanoi,
160 Zandvoort,
161}
162
163binread_enum!(Track, i8);
164
165#[derive(Debug, Default, TryFromPrimitive)]
166#[repr(u8)]
167pub enum Formula {
168 F1Modern,
169 F1Classic,
170 F2,
171 F1Generic,
172 #[default]
173 Unknown = 255,
174}
175
176binread_enum!(Formula, u8);
177
178#[derive(Debug, Default, TryFromPrimitive)]
179#[repr(u8)]
180pub enum SafetyCarStatus {
181 NoSafetyCar,
182 FullSafetyCar,
183 VirtualSafetyCar,
184 #[default]
185 Unknown = 255,
186}
187
188binread_enum!(SafetyCarStatus, u8);
189
190#[derive(Debug, Default, BinRead)]
191pub struct MarshalZone {
192 pub zone_start: f32,
193 pub zone_flag: ZoneFlag,
194}
195
196#[derive(Debug, Default, TryFromPrimitive)]
197#[repr(i8)]
198pub enum ZoneFlag {
199 #[default]
200 Unknown = -1,
201 None,
202 Green,
203 Blue,
204 Yellow,
205 Red,
206}
207
208binread_enum!(ZoneFlag, i8);
209
210#[derive(Debug, Default, BinRead)]
211pub struct WeatherForecastSample {
212 pub session_type: SessionType,
213 pub time_offset: u8,
214 pub weather: Weather,
215 pub track_temperature: i8,
216 pub air_temperature: i8,
217}
218
219#[derive(Debug, Default, TryFromPrimitive)]
220#[repr(u8)]
221pub enum SessionType {
222 #[default]
223 Unknown,
224 Practice1,
225 Practice2,
226 Practice3,
227 ShortPractice,
228 Qualifier1,
229 Qualifier2,
230 Qualifier3,
231 ShortQualifier,
232 OSQ,
233 Race,
234 Formula2Race,
235 TimeTrial,
236}
237
238binread_enum!(SessionType, u8);
239
240#[derive(Debug, BinRead)]
241pub struct LapData {
242 pub header: Header,
243 #[br(count = 22)]
244 pub laps: Vec<Lap>,
245}
246
247player_data!(LapData, Lap, laps);
248
249#[derive(Debug, Default, BinRead)]
250pub struct Lap {
251 pub last_lap_time: f32,
252 pub current_lap_time: f32,
253 pub sector_time_ms: (u16, u16), pub best_lap_time: f32,
255 pub best_lap_number: u8,
256 pub best_lap_sector_time: (u16, u16, u16), pub best_overall_sector_time: (
258 BestOverallSectorTime,
259 BestOverallSectorTime,
260 BestOverallSectorTime,
261 ), pub lap_distance: f32,
263 pub total_distance: f32,
264 pub safety_car_delta: f32,
265 pub car_position: u8,
266 pub current_lap_number: u8,
267 pub pit_status: PitStatus,
268 pub sector: Sector,
269 #[br(map = |x: u8| x > 0)]
270 pub current_lap_invalid: bool,
271 pub penalties: u8,
272 pub grid_position: u8,
273 pub driver_status: DriverStatus,
274 pub result_status: ResultStatus,
275}
276
277#[derive(Debug, Default, BinRead)]
278pub struct BestLapSectorTime {
279 pub sector1: u16,
280 pub sector2: u16,
281 pub sector3: u16,
282}
283
284#[derive(Debug, Default, BinRead)]
285pub struct BestOverallSectorTime {
286 pub sector_time: u16,
287 pub lap_number: u8,
288}
289
290#[derive(Debug, Default, TryFromPrimitive)]
291#[repr(u8)]
292pub enum PitStatus {
293 None,
294 Pitting,
295 InPitArea,
296 #[default]
297 Unknown = 255,
298}
299
300binread_enum!(PitStatus, u8);
301
302#[derive(Debug, Default, TryFromPrimitive)]
303#[repr(u8)]
304pub enum Sector {
305 Sector1,
306 Sector2,
307 Sector3,
308 #[default]
309 Unknown = 255,
310}
311
312binread_enum!(Sector, u8);
313
314#[derive(Debug, Default, TryFromPrimitive)]
315#[repr(u8)]
316pub enum DriverStatus {
317 InGarage,
318 FlyingLap,
319 InLap,
320 OutLap,
321 InTrack,
322 #[default]
323 Unknown = 255,
324}
325
326binread_enum!(DriverStatus, u8);
327
328#[derive(Debug, Default, TryFromPrimitive)]
329#[repr(u8)]
330pub enum ResultStatus {
331 Invalid,
332 Inactive,
333 Active,
334 Finished,
335 Disqualified,
336 NotClassified,
337 Retired,
338 MechanicalFailure,
339 #[default]
340 Unknown = 255,
341}
342
343binread_enum!(ResultStatus, u8);
344
345#[derive(Debug)]
346pub struct Event {
347 pub header: Header,
348 pub event_data_details: EventDataDetail,
349}
350
351impl binread::BinRead for Event {
354 type Args = ();
355 fn read_options<R: binread::io::Read + binread::io::Seek>(
356 reader: &mut R,
357 options: &binread::ReadOptions,
358 args: Self::Args,
359 ) -> binread::BinResult<Self> {
360 let header = Header::read_options(reader, options, args)?; let event_code_bytes = <[u8; 4]>::read_options(reader, options, args)?;
364 let event_code = std::str::from_utf8(&event_code_bytes).unwrap_or("UNKW");
365
366 let event_data_details = match event_code {
367 "SSTA" => EventDataDetail::SessionStarted,
368 "SEND" => EventDataDetail::SessionEnded,
369 "FTLP" => {
370 let idx = <u8>::read_options(reader, options, args)?;
371 let time = <f32>::read_options(reader, options, args)?;
372 EventDataDetail::FastestLap(idx, time)
373 }
374 "RTMT" => {
375 let idx = <u8>::read_options(reader, options, args)?;
376 EventDataDetail::Retirement(idx)
377 }
378 "DRSE" => EventDataDetail::DRSEnabled,
379 "DRSD" => EventDataDetail::DRSDisabled,
380 "TMPT" => {
381 let idx = <u8>::read_options(reader, options, args)?;
382 EventDataDetail::TeamMateInPits(idx)
383 }
384 "CHQF" => EventDataDetail::ChequeredFlag,
385 "RCWN" => {
386 let idx = <u8>::read_options(reader, options, args)?;
387 EventDataDetail::RaceWinner(idx)
388 }
389 "PENA" => {
390 let detail = PenaltyEventDetail::read_options(reader, options, args)?;
391 EventDataDetail::Penalty(detail)
392 }
393 "SPTP" => {
394 let idx = <u8>::read_options(reader, options, args)?;
395 let speed = <f32>::read_options(reader, options, args)?;
396 EventDataDetail::SpeedTrap(idx, speed)
397 }
398 _ => EventDataDetail::Unknown,
399 };
400
401 Ok(Event {
402 header,
403 event_data_details,
404 })
405 }
406}
407
408#[derive(Debug)]
409pub enum EventDataDetail {
410 SessionStarted,
411 SessionEnded,
412 FastestLap(u8, f32), Retirement(u8), DRSEnabled,
415 DRSDisabled,
416 TeamMateInPits(u8), ChequeredFlag,
418 RaceWinner(u8), Penalty(PenaltyEventDetail),
420 SpeedTrap(u8, f32), Unknown, }
423
424#[derive(Debug, Default, BinRead)]
425pub struct PenaltyEventDetail {
426 pub penalty_type: PenaltyType,
427 pub infrigement_type: InfringementType,
428 pub vehicle_index: u8,
429 pub other_vehicle_index: u8,
430 pub time: u8,
431 pub lap_number: u8,
432 pub places_gained: u8,
433}
434
435#[derive(Debug, Default, TryFromPrimitive)]
436#[repr(u8)]
437pub enum PenaltyType {
438 DriveThrough,
439 StopGo,
440 GridPenalty,
441 PenaltyReminder,
442 TimePenalty,
443 Warning,
444 Disqualified,
445 RemovedFromFormationLap,
446 ParkedTooLongTimer,
447 TyreRegulations,
448 ThisLapInvalidated,
449 ThisAndNextLapInvalidated,
450 ThisLapInvalidatedWithNoReason,
451 ThisAndNextLapInvalidatedWithNoReason,
452 ThisAndPreviousLapInvalidated,
453 ThisAndPreviousLapInvalidatedWithNoReason,
454 Retired,
455 BlackFlagTimer,
456 #[default]
457 Unknown = 255,
458}
459
460binread_enum!(PenaltyType, u8);
461
462#[derive(Debug, Default, TryFromPrimitive)]
463#[repr(u8)]
464pub enum InfringementType {
465 BlockingBySlowDriving,
466 BlockingByWrongWayDriving,
467 ReversingOffTheStartLine,
468 BigCollision,
469 SmallCollision,
470 CollisionFailedToHandBackPositionSingle,
471 CollisionFailedToHandBackPositionMultiple,
472 CornerCuttingGainedTime,
473 CornerCuttingOvertakeSingle,
474 CornerCuttingOvertakeMultiple,
475 CrossedPitExitLane,
476 IgnoringBlueFlags,
477 IgnoringYellowFlags,
478 IgnoringDriveThrough,
479 TooManyDriveThroughs,
480 DriveThroughReminderServeWithinNLaps,
481 DriveThroughReminderServeThisLap,
482 PitLaneSpeeding,
483 ParkedForTooLong,
484 IgnoringTyreRegulations,
485 TooManyPenalties,
486 MultipleWarnings,
487 ApproachingDisqualification,
488 TyreRegulationsSelectSingle,
489 TyreRegulationsSelectMultiple,
490 LapInvalidatedCornerCutting,
491 LapInvalidatedRunningWide,
492 CornerCuttingRanWideGainedTimeMinor,
493 CornerCuttingRanWideGainedTimeSignificant,
494 CornerCuttingRanWideGainedTimeExtreme,
495 LapInvalidatedWallRiding,
496 LapInvalidatedFlashbackUsed,
497 LapInvalidatedResetToTrack,
498 BlockingThePitlane,
499 JumpStart,
500 SafetyCarToCarCollision,
501 SafetyCarIllegalOvertake,
502 SafetyCarExceedingAllowedPace,
503 VirtualSafetyCarExceedingAllowedPace,
504 FormationLapBelowAllowedSpeed,
505 RetiredMechanicalFailure,
506 RetiredTerminallyDamaged,
507 SafetyCarFallingTooFarBack,
508 BlackFlagTimer,
509 UnservedStopGoPenalty,
510 UnservedDriveThroughPenalty,
511 EngineComponentChange,
512 GearboxChange,
513 LeagueGridPenalty,
514 RetryPenalty,
515 IllegalTimeGain,
516 MandatoryPitstop,
517 #[default]
518 Unknown = 255,
519}
520
521binread_enum!(InfringementType, u8);
522
523#[derive(Debug, BinRead)]
524pub struct Participants {
525 pub header: Header,
526 pub num_active_cars: u8,
527 #[br(count = 22)]
528 pub participants_data: Vec<ParticipantsData>,
529}
530
531player_data!(Participants, ParticipantsData, participants_data);
532
533#[derive(Debug, Default, BinRead)]
534pub struct ParticipantsData {
535 #[br(map = |x: u8| x > 0)]
536 pub ai_controlled: bool,
537 pub driver: Driver,
538 pub team: Team,
539 pub race_number: u8,
540 pub nationality: Nationality,
541 #[br(parse_with = participant_name_parser)]
542 pub name: String,
543 #[br(map = |x: u8| x > 1)]
544 pub your_telemetry_restricted: bool,
545}
546
547fn participant_name_parser<R: binread::io::Read + binread::io::Seek>(
548 reader: &mut R,
549 _: &binread::ReadOptions,
550 _: (),
551) -> binread::BinResult<String> {
552 let mut bytes: [u8; 48] = [0; 48]; reader.read_exact(&mut bytes)?;
554
555 let driver_name = std::str::from_utf8(&bytes)
556 .unwrap_or("UNKW")
557 .trim_matches(char::from(0)); Ok(String::from(driver_name))
560}
561
562#[derive(Debug, Default, TryFromPrimitive)]
563#[repr(u8)]
564pub enum Driver {
565 CarlosSainz,
566 DaniilKvyat,
567 DanielRicciardo,
568 KimiRaikkonen = 6, LewisHamilton,
570 MaxVerstappen = 9,
571 NicoHulkenburg,
572 KevinMagnussen,
573 RomainGrosjean,
574 SebastianVettel,
575 SergioPerez,
576 ValtteriBottas,
577 EstebanOcon = 17,
578 LanceStroll = 19,
579 ArronBarnes,
580 MartinGiles,
581 AlexMurray,
582 LucasRoth,
583 IgorCorreia,
584 SophieLevasseur,
585 JonasSchiffer,
586 AlainForest,
587 JayLetourneau,
588 EstoSaari,
589 YasarAtiyeh,
590 CallistoCalabresi,
591 NaotaIzumi,
592 HowardClarke,
593 WilheimKaufmann,
594 MarieLaursen,
595 FlavioNieves,
596 PeterBelousovm,
597 KlimekMichalski,
598 SantiagoMoreno,
599 BenjaminCoppens,
600 NoahVisser,
601 GertWaldmuller,
602 JulianQuesada,
603 DanielJones,
604 ArtemMarkelov,
605 TadasukeMakino,
606 SeanGelael,
607 NyckDeVries,
608 JackAitken,
609 GeorgeRussell,
610 MaximilianGunther,
611 NireiFukuzumi,
612 LucaGhiotto,
613 LandoNorris,
614 SergioSetteCamara = 55, LouisDeletraz, AntonioFuoco,
617 CharlesLeclerc,
618 PierreGasly,
619 AlexanderAlbon = 62,
620 NicholasLatifi,
621 DorianBoccolacci,
622 NikoKari,
623 RobertoMerhi,
624 ArjunMaini,
625 AlessioLorandi,
626 RubenMeijer,
627 RashidNair,
628 JackTremblay,
629 AntonioGiovinazzi = 74,
630 RobertKubica,
631 NobuharuMatsushita = 78,
632 NikitaMazepin,
633 GuanyaZhou,
634 MickSchumacher,
635 CallumIlott,
636 JuanManuel,
637 Correa,
638 JordanKing,
639 MahaveerRaghunathan,
640 TatianaCalderon,
641 AnthoineHubert,
642 GuilianoAlesi,
643 RalphBoschung,
644 MyDriver = 100,
645 #[default]
646 Unknown = 255, }
648
649binread_enum!(Driver, u8);
650
651#[derive(Debug, Default, TryFromPrimitive)]
652#[repr(u8)]
653pub enum Team {
654 Mercedes,
655 Ferrari,
656 RedBullRacing,
657 Williams,
658 RacingPoint,
659 Renault,
660 AlphaTauri,
661 Haas,
662 McLaren,
663 AlfaRomeo,
664 McLaren1988,
665 McLaren1991,
666 Williams1992,
667 Ferrari1995,
668 Williams1996,
669 McLaren1998,
670 Ferrari2002,
671 Ferrari2004,
672 Renault2006,
673 Ferrari2007,
674 McLaren2008,
675 RedBull2010,
676 Ferrari1976,
677 ARTGrandPrix,
678 CamposVexatecRacing,
679 Carlin,
680 CharouzRacingSystem,
681 DAMS,
682 RussianTime,
683 MPMotorsport,
684 Pertamina,
685 McLaren1990,
686 Trident,
687 BWTArden,
688 McLaren1976,
689 Lotus1972,
690 Ferrari1979,
691 McLaren1982,
692 Williams2003,
693 Brawn2009,
694 Lotus1978,
695 F1GenericCar,
696 ArtGP19,
697 Campos19,
698 Carlin19,
699 SauberJuniorCharouz19,
700 Dams19,
701 UniVirtuosi19,
702 MPMotorsport19,
703 Prema19,
704 Trident19,
705 Arden19,
706 Benetton1994,
707 Benetton1995,
708 Ferrari2000,
709 Jordan1991,
710 Ferrari1990 = 63,
711 McLaren2010,
712 Ferrari2010,
713 #[default]
714 Unknown = 254,
715 MyTeam = 255,
716}
717
718binread_enum!(Team, u8);
719
720#[derive(Debug, Default, TryFromPrimitive)]
721#[repr(u8)]
722pub enum Nationality {
723 #[default]
724 Unknown,
725 American,
726 Argentinean,
727 Australian,
728 Austrian,
729 Azerbaijani,
730 Bahraini,
731 Belgian,
732 Bolivian,
733 Brazilian,
734 British,
735 Bulgarian,
736 Cameroonian,
737 Canadian,
738 Chilean,
739 Chinese,
740 Colombian,
741 CostaRican,
742 Croatian,
743 Cypriot,
744 Czech,
745 Danish,
746 Dutch,
747 Ecuadorian,
748 English,
749 Emirian,
750 Estonian,
751 Finnish,
752 French,
753 German,
754 Ghanaian,
755 Greek,
756 Guatemalan,
757 Honduran,
758 HongKonger,
759 Hungarian,
760 Icelander,
761 Indian,
762 Indonesian,
763 Irish,
764 Israeli,
765 Italian,
766 Jamaican,
767 Japanese,
768 Jordanian,
769 Kuwaiti,
770 Latvian,
771 Lebanese,
772 Lithuanian,
773 Luxembourger,
774 Malaysian,
775 Maltese,
776 Mexican,
777 Monegasque,
778 NewZealander,
779 Nicaraguan,
780 NorthKorean,
781 NorthernIrish,
782 Norwegian,
783 Omani,
784 Pakistani,
785 Panamanian,
786 Paraguayan,
787 Peruvian,
788 Polish,
789 Portuguese,
790 Qatari,
791 Romanian,
792 Russian,
793 Salvadoran,
794 Saudi,
795 Scottish,
796 Serbian,
797 Singaporean,
798 Slovakian,
799 Slovenian,
800 SouthKorean,
801 SouthAfrican,
802 Spanish,
803 Swedish,
804 Swiss,
805 Thai,
806 Turkish,
807 Uruguayan,
808 Ukrainian,
809 Venezuelan,
810 Welsh,
811 Barbadian,
812 Vietnamese,
813}
814
815binread_enum!(Nationality, u8);
816
817#[derive(Debug, BinRead)]
818pub struct CarSetup {
819 pub header: Header,
820 #[br(count = 22)]
821 pub car_setup_data: Vec<CarSetupData>,
822}
823
824#[derive(Debug, Default, BinRead)]
825pub struct CarSetupData {
826 pub wing: FrontRearValue<u8>,
827 pub on_throttle: u8,
828 pub off_throttle: u8,
829 pub camber: FrontRearValue<f32>,
830 pub toe: FrontRearValue<f32>,
831 pub suspension: FrontRearValue<u8>,
832 pub anti_roll_bar: FrontRearValue<u8>,
833 pub suspension_height: FrontRearValue<u8>,
834 pub brake_pressure: u8,
835 pub brake_bias: u8,
836 pub type_pressure: WheelValue<f32>,
837 pub ballast: u8,
838 pub fuel_load: f32,
839}
840
841player_data!(CarSetup, CarSetupData, car_setup_data);
842
843#[derive(Debug, BinRead)]
844pub struct CarTelemetry {
845 pub header: Header,
846 #[br(count = 22)]
847 pub car_telemetry_data: Vec<CarTelemetryData>,
848 pub button_status: u32,
849 pub mfd_panel: MFDPanel,
850 pub mfd_panel_secondary_player: MFDPanel,
851 #[br(map = |x: i8| if x == 0 { Gear::Unknown } else { Gear::try_from(x).unwrap() })]
852 pub suggested_gear: Gear,
853}
854
855player_data!(CarTelemetry, CarTelemetryData, car_telemetry_data);
856
857#[derive(Debug, Default, BinRead)]
858pub struct CarTelemetryData {
859 pub speed: u16,
860 pub throttle: f32,
861 pub steer: f32,
862 pub brake: f32,
863 pub clutch: u8,
864 #[br(map = |x: i8| Gear::try_from(x).unwrap())]
865 pub gear: Gear,
866 pub engine_rpm: u16,
867 #[br(map = |x: u8| x > 0)]
868 pub drs: bool,
869 pub rev_lights_percent: u8,
870 pub brake_temp: WheelValue<u16>,
871 pub tyres_surface_temp: WheelValue<u8>,
872 pub tyres_inner_temp: WheelValue<u8>,
873 pub engine_temp: u16,
874 pub tyres_pressure: WheelValue<f32>,
875 #[br(parse_with = surface_type_parser)]
876 pub surface_type: WheelValue<Surface>,
877}
878
879fn surface_type_parser<R: binread::io::Read + binread::io::Seek>(
880 reader: &mut R,
881 _: &binread::ReadOptions,
882 _: (),
883) -> binread::BinResult<WheelValue<Surface>> {
884 let mut bytes: [u8; 4] = [0; 4];
885 reader.read_exact(&mut bytes)?;
886
887 Ok(WheelValue::<Surface> {
888 rear_left: Surface::try_from(bytes[0]).unwrap_or(Surface::Unknown),
889 rear_right: Surface::try_from(bytes[1]).unwrap_or(Surface::Unknown),
890 front_left: Surface::try_from(bytes[2]).unwrap_or(Surface::Unknown),
891 front_right: Surface::try_from(bytes[3]).unwrap_or(Surface::Unknown),
892 })
893}
894
895#[derive(Debug, Default, TryFromPrimitive)]
896#[repr(i8)]
897pub enum Gear {
898 Reverse = -1,
899 Neutral,
900 First,
901 Second,
902 Third,
903 Fourth,
904 Fifth,
905 Sixth,
906 Seventh,
907 Eigth,
908 #[default]
909 Unknown = 127,
910}
911
912binread_enum!(Gear, i8);
913
914#[derive(Debug, Default, TryFromPrimitive)]
915#[repr(u8)]
916pub enum Surface {
917 Tarmac,
918 RumbleStrip,
919 Concrete,
920 Rock,
921 Gravel,
922 Mud,
923 Sand,
924 Grass,
925 Water,
926 Cobblestone,
927 Metal,
928 Ridged,
929 #[default]
930 Unknown = 255,
931}
932
933binread_enum!(Surface, u8);
934
935#[derive(Debug, Default, TryFromPrimitive)]
936#[repr(u8)]
937pub enum MFDPanel {
938 CarSetup,
939 Pits,
940 Damage,
941 Engine,
942 Temperatures,
943 #[default]
944 Unknown,
945 Closed = 255,
946}
947
948binread_enum!(MFDPanel, u8);
949
950#[derive(Debug, BinRead)]
951pub struct CarStatus {
952 pub header: Header,
953 #[br(count = 22)]
954 pub car_status_data: Vec<CarStatusData>,
955}
956
957player_data!(CarStatus, CarStatusData, car_status_data);
958
959#[derive(Debug, Default, BinRead)]
960pub struct CarStatusData {
961 pub traction_control: u8,
962 #[br(map = |x: u8| x > 0)]
963 pub anti_lock_brakes: bool,
964 pub fuel_mix: FuelMix,
965 pub front_brake_bias: u8,
966 #[br(map = |x: u8| x > 0)]
967 pub pit_limiter_status: bool,
968 pub fuel_in_tank: f32,
969 pub fuel_capacity: f32,
970 pub fuel_remaining_laps: f32,
971 pub max_rpm: u16,
972 pub idle_rpm: u16,
973 pub max_gears: u8,
974 pub drs_allowed: DRSAllowed,
975 #[br(map = |x: u16| if x > 0 { DRSActivationDistance::Distance(x) } else { DRSActivationDistance::NotAvailable })]
976 pub drs_activation_distance: DRSActivationDistance,
977 pub tyres_wear: WheelValue<u8>,
978 pub tyres_compound: TyreCompound,
979 pub tyres_visual: TyreVisual,
980 pub tyres_ages_lap: u8,
981 pub tyres_damage: WheelValue<u8>,
982 pub wing_damage: WingValue<u8>,
983 #[br(map = |x: u8| x > 0)]
984 pub drs_fault: bool,
985 pub engine_damage: u8,
986 pub gearbox_damage: u8,
987 pub vehicle_fia_flag: FiaFlag,
988 pub ers_data: ERS,
989}
990
991#[derive(Debug, Default, TryFromPrimitive)]
992#[repr(u8)]
993pub enum FuelMix {
994 Lean,
995 Standard,
996 Rich,
997 Max,
998 #[default]
999 Unknown,
1000}
1001
1002binread_enum!(FuelMix, u8);
1003
1004#[derive(Debug, Default, TryFromPrimitive)]
1005#[repr(u8)]
1006pub enum DRSAllowed {
1007 NotAllowed,
1008 Allowed,
1009 #[default]
1010 Unknown,
1011}
1012
1013binread_enum!(DRSAllowed, u8);
1014
1015#[derive(Debug, Default)]
1016#[repr(u16)]
1017pub enum DRSActivationDistance {
1018 #[default]
1019 NotAvailable,
1020 Distance(u16),
1021}
1022
1023#[derive(Debug, Default, TryFromPrimitive)]
1024#[repr(u8)]
1025pub enum TyreCompound {
1026 Inter = 7,
1027 Wet,
1028 F1ClassicDry,
1029 F1ClassicWet,
1030 F2SuperSoft,
1031 F2Soft,
1032 F2Medium,
1033 F2Hard,
1034 F2Wet,
1035 C5,
1036 C4,
1037 C3,
1038 C2,
1039 C1,
1040 #[default]
1041 Unknown,
1042}
1043
1044binread_enum!(TyreCompound, u8);
1045
1046#[derive(Debug, Default, TryFromPrimitive)]
1047#[repr(u8)]
1048pub enum TyreVisual {
1049 Inter = 7,
1050 Wet = 8,
1051 Soft = 16,
1052 Medium = 17,
1053 Hard = 18,
1054 #[default]
1055 Unknown = 255,
1056}
1057
1058binread_enum!(TyreVisual, u8);
1059
1060#[derive(Debug, Default, TryFromPrimitive)]
1061#[repr(i8)]
1062pub enum FiaFlag {
1063 #[default]
1064 Unknown = -1,
1065 None,
1066 Green,
1067 Blue,
1068 Yellow,
1069 Red,
1070}
1071
1072binread_enum!(FiaFlag, i8);
1073
1074#[derive(Debug, Default, BinRead)]
1075pub struct ERS {
1076 pub stored_energy: f32,
1077 pub deploy_mode: ERSDeployMode,
1078 pub harvested_this_lap_mguk: f32,
1079 pub harvested_this_lap_mguh: f32,
1080 pub deployed_this_lap: f32,
1081}
1082
1083#[derive(Debug, Default, TryFromPrimitive)]
1084#[repr(u8)]
1085pub enum ERSDeployMode {
1086 None,
1087 Medium,
1088 Overtake,
1089 Hotlap,
1090 #[default]
1091 Unknown = 255,
1092}
1093
1094binread_enum!(ERSDeployMode, u8);
1095
1096#[derive(Debug, BinRead)]
1097pub struct FinalClassification {
1098 pub header: Header,
1099 pub number_of_cars: u8,
1100 #[br(count = 22)]
1101 pub final_classification_data: Vec<FinalClassificationData>,
1102}
1103
1104player_data!(
1105 FinalClassification,
1106 FinalClassificationData,
1107 final_classification_data
1108);
1109
1110#[derive(Debug, Default, BinRead)]
1111pub struct FinalClassificationData {
1112 pub position: u8,
1113 pub number_of_laps: u8,
1114 pub grid_position: u8,
1115 pub points: u8,
1116 pub number_of_pit_stops: u8,
1117 pub result_status: ResultStatus,
1118 pub best_lap_time: f32,
1119 pub total_race_time: f64,
1120 pub penalties_time: u8,
1121 pub number_of_penalties: u8,
1122 pub number_of_tyre_stints: u8,
1123 #[br(count = 8)]
1124 pub tyre_stints_actual: Vec<TyreCompound>,
1125 #[br(count = 8)]
1126 pub tyre_stints_visual: Vec<TyreVisual>,
1127}
1128
1129#[derive(Debug, BinRead)]
1130pub struct LobbyInfo {
1131 pub header: Header,
1132 pub number_of_players: u8,
1133 #[br(count = 22)]
1134 pub lobby_players: Vec<LobbyInfoData>,
1135}
1136
1137player_data!(LobbyInfo, LobbyInfoData, lobby_players);
1138
1139impl LobbyInfo {
1140 pub fn players(self) -> Vec<LobbyInfoData> {
1141 let number_of_players = self.number_of_players as usize;
1142 self.lobby_players
1143 .into_iter()
1144 .take(number_of_players)
1145 .collect()
1146 }
1147}
1148
1149#[derive(Debug, Default, BinRead)]
1150pub struct LobbyInfoData {
1151 #[br(map = |x: u8| x > 0)]
1152 pub ai_controlled: bool,
1153 pub team: Team,
1154 pub nationality: Nationality,
1155 #[br(parse_with = participant_name_parser)]
1156 pub name: String,
1157 pub status: LobbyStatus,
1158}
1159
1160#[derive(Debug, Default, TryFromPrimitive)]
1161#[repr(u8)]
1162pub enum LobbyStatus {
1163 NotReady,
1164 Ready,
1165 Spectating,
1166 #[default]
1167 Unknown,
1168}
1169
1170binread_enum!(LobbyStatus, u8);
1171
1172impl TelemetryEvent for F1_2020 {
1173 fn from_packet(packet: &TelemetryPacket) -> Result<F1_2020, Box<dyn Error>> {
1174 if packet.len() < 24 {
1175 return Err(Box::from("Packet is too small to contain a header"));
1176 }
1177
1178 let packet_id = packet[5]; let mut reader = Cursor::new(packet);
1180 match packet_id {
1181 0 => {
1182 let data: Motion = reader.read_le()?;
1183 Ok(F1_2020::Motion(data))
1184 }
1185 1 => {
1186 let data: Session = reader.read_le()?;
1187 Ok(F1_2020::Session(data))
1188 }
1189 2 => {
1190 let data: LapData = reader.read_le()?;
1191 Ok(F1_2020::LapData(data))
1192 }
1193 3 => {
1194 let data: Event = reader.read_le()?;
1195 Ok(F1_2020::Event(data))
1196 }
1197 4 => {
1198 let data: Participants = reader.read_le()?;
1199 Ok(F1_2020::Participants(data))
1200 }
1201 5 => {
1202 let data: CarSetup = reader.read_le()?;
1203 Ok(F1_2020::CarSetup(data))
1204 }
1205 6 => {
1206 let data: CarTelemetry = reader.read_le()?;
1207 Ok(F1_2020::CarTelemetry(data))
1208 }
1209 7 => {
1210 let data: CarStatus = reader.read_le()?;
1211 Ok(F1_2020::CarStatus(data))
1212 }
1213 8 => {
1214 let data: FinalClassification = reader.read_le()?;
1215 Ok(F1_2020::FinalClassification(data))
1216 }
1217 9 => {
1218 let data: LobbyInfo = reader.read_le()?;
1219 Ok(F1_2020::LobbyInfo(data))
1220 }
1221 id => Err(Box::from(format!("Unknown packet type: {}", id))),
1222 }
1223 }
1224}