diff --git a/src/constants/driver_id.rs b/src/constants/driver_id.rs new file mode 100644 index 0000000..045d4e1 --- /dev/null +++ b/src/constants/driver_id.rs @@ -0,0 +1,127 @@ +pub const CARLOS_SAINZ: u8 = 0; +pub const DANILL_KVYAT: u8 = 1; +pub const DANIEL_RICCIARDO: u8 = 2; +pub const FERNANDO_ALONSO: u8 = 3; +pub const FELIPE_MASSA: u8 = 4; +pub const KIMI_RAIKKONEN: u8 = 6; +pub const LEWIS_HAMILTON: u8 = 7; +pub const MARCUS_ERICSSON: u8 = 8; +pub const MAX_VERSTAPPEN: u8 = 9; +pub const NICO_HULKENBERG: u8 = 10; +pub const KEVIN_MAGNUSSEN: u8 = 11; +pub const ROMAIN_GROSJEAN: u8 = 12; +pub const SEBASTIAN_VETTEL: u8 = 13; +pub const SERGIO_PEREZ: u8 = 14; +pub const VALTTERI_BOTTAS: u8 = 15; +pub const ESTEBAN_OCON: u8 = 17; +pub const STOFFEL_VANDOORNE: u8 = 18; +pub const LANCE_STROLL: u8 = 19; +pub const ARRON_BARNES: u8 = 20; +pub const MARTIN_GILES: u8 = 21; +pub const ALEX_MURRAY: u8 = 22; +pub const LUCAS_ROTH: u8 = 23; +pub const IGOR_CORREIA: u8 = 24; +pub const SOPHIE_LEVASSEUR: u8 = 25; +pub const JONAS_SCHIFFER: u8 = 26; +pub const ALAIN_FORREST: u8 = 27; +pub const JAY_LETOURNEAU: u8 = 28; +pub const ESTO_SAARI: u8 = 29; +pub const YASAR_ATIEH: u8 = 30; +pub const CALLISTO_CALABRESI: u8 = 31; +pub const NAOTA_IZUMI: u8 = 32; +pub const HOWARD_CLARKE: u8 = 33; +pub const WILHELM_KAUFMANN: u8 = 34; +pub const MARIE_LAURSEN: u8 = 35; +pub const FLAVIO_NIEVES: u8 = 36; +pub const PETER_BELOUSOV: u8 = 37; +pub const KLIMEK_MICHALSKI: u8 = 38; +pub const SANTIAGO_MORENO: u8 = 39; +pub const BENJAMIN_COPPENS: u8 = 40; +pub const NOAH_VISSER: u8 = 41; +pub const GERT_WALDMULLER: u8 = 42; +pub const JULIAN_QUESADA: u8 = 43; +pub const DANIEL_JONES: u8 = 44; +pub const ARTEM_MARKELOV: u8 = 45; +pub const TADASUKE_MAKINO: u8 = 46; +pub const SEAN_GELAEL: u8 = 47; +pub const NYCK_DE_VRIES: u8 = 48; +pub const JACK_AITKEN: u8 = 49; +pub const GEORGE_RUSSELL: u8 = 50; +pub const MAXIMILIAN_GUNTHER: u8 = 51; +pub const NIREI_FUKUZUMI: u8 = 52; +pub const LUCA_GHIOTTO: u8 = 53; +pub const LANDO_NORRIS: u8 = 54; +pub const SERGIO_SETTE_CAMARA: u8 = 55; +pub const LOUIS_DELETRAZ: u8 = 56; +pub const ANTONIO_FUOCCO: u8 = 57; +pub const CHARLES_LECLERC: u8 = 58; +pub const PIERRE_GASLY: u8 = 59; +pub const BRENDON_HARTLEY: u8 = 60; +pub const SERGEY_SIROTKIN: u8 = 61; +pub const ALEXANDER_ALBON: u8 = 62; +pub const NICHOLAS_LATIFI: u8 = 63; +pub const DORIAN_BOCCOLACCI: u8 = 64; +pub const NIKO_KARI: u8 = 65; +pub const ROBERTO_MEHRI: u8 = 66; +pub const ARJUN_MAINI: u8 = 67; +pub const ALESSIO_LORANDI: u8 = 68; +pub const RUBEN_MEIJER: u8 = 69; +pub const RASHID_NAIR: u8 = 70; +pub const JACK_TREMBLAY: u8 = 71; +pub const ANTONIO_GIOVINAZZI: u8 = 74; +pub const ROBERT_KUBICA: u8 = 75; +pub const ALAIN_PROST: u8 = 76; +pub const AYRTON_SENNA: u8 = 77; +pub const NOBUHARU_MATSUSHITA: u8 = 78; +pub const NIKITA_MAZEPIN: u8 = 79; +pub const GUANYU_ZHOU: u8 = 80; +pub const MICK_SCHUMACHER: u8 = 81; +pub const CALLUM_ILOTT: u8 = 82; +pub const JUAN_MANUEL_CORREA: u8 = 83; +pub const JORDAN_KING: u8 = 84; +pub const MAHAVEER_RAGUNATHAN: u8 = 85; +pub const TATIANA_CALDERON: u8 = 86; +pub const ANTHOINE_HUBERT: u8 = 87; +pub const GUILIANO_ALESI: u8 = 88; +pub const RALPH_BOSCHUNG: u8 = 89; +pub const MICHAEL_SCHUMACHER: u8 = 90; +pub const DAN_TICKTUM: u8 = 91; +pub const MARCUS_ARMSTRONG: u8 = 92; +pub const CHRISTIAN_LUNDGAARD: u8 = 93; +pub const YUKI_TSUNODA: u8 = 94; +pub const JEHAN_DARUVALA: u8 = 95; +pub const GULHERME_SAMAIA: u8 = 96; +pub const PEDRO_PIQUET: u8 = 97; +pub const FELIPE_DRUGOVICH: u8 = 98; +pub const ROBERT_SCHWARTZMAN: u8 = 99; +pub const ROY_NISSANY: u8 = 100; +pub const MARINO_SATO: u8 = 101; +pub const AIDEN_JACKSON: u8 = 102; +pub const CASPER_AKKERMAN: u8 = 103; +pub const JENSON_BUTTON: u8 = 109; +pub const DAVID_COULTHARD: u8 = 110; +pub const NICO_ROSBERG: u8 = 111; +pub const OSCAR_PIASTRI: u8 = 112; +pub const LIAM_LAWSON: u8 = 113; +pub const JURI_VIPS: u8 = 114; +pub const THEO_POURCHAIRE: u8 = 115; +pub const RICHARD_VERSCHOOR: u8 = 116; +pub const LIRIM_ZENDELI: u8 = 117; +pub const DAVID_BECKMANN: u8 = 118; +pub const ALESSIO_DELEDDA: u8 = 121; +pub const BENT_VISCAAL: u8 = 122; +pub const ENZO_FITTIPALDI: u8 = 123; +pub const MARK_WEBBER: u8 = 125; +pub const JACQUES_VILLENEUVE: u8 = 126; +pub const JAKE_HUGHES: u8 = 127; +pub const FREDERIK_VESTI: u8 = 128; +pub const OLLI_CALDWELL: u8 = 129; +pub const LOGAN_SARGEANT: u8 = 130; +pub const CEM_BOLUKBASI: u8 = 131; +pub const AYUMU_IWASA: u8 = 132; +pub const CLEMENT_NOVALAK: u8 = 133; +pub const DENNIS_HAUGER: u8 = 134; +pub const CALAN_WILLIAMS: u8 = 135; +pub const JACK_DOOHAN: u8 = 136; +pub const AMAURY_CORDEEL: u8 = 137; +pub const MIKA_HAKKINEN: u8 = 138; diff --git a/src/constants/mod.rs b/src/constants/mod.rs index e8a79dc..78b5862 100644 --- a/src/constants/mod.rs +++ b/src/constants/mod.rs @@ -1,4 +1,5 @@ pub mod wheel_index; +pub mod driver_id; use binrw::BinRead; use bitflags::bitflags; @@ -881,3 +882,104 @@ pub enum YourTelemetry { Restricted = 0, Public = 1, } + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum Surface { + Tarmac = 0, + RumbleStrip = 1, + Concrete = 2, + Rock = 3, + Gravel = 4, + Mud = 5, + Sand = 6, + Grass = 7, + Water = 8, + Cobblestone = 9, + Metal = 10, + Ridged = 11, +} + +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + Ord, + PartialOrd, + Hash, + Serialize, + Deserialize, +)] +pub struct RevLights(u16); + +bitflags! { + impl RevLights: u16 { + /// 1st left (1st leftmost) LED. Has a value of `0x0001`. + const LEFT_1 = 0x0001; + /// 2nd left (2nd leftmost) LED. Has a value of `0x0002`. + const LEFT_2 = 0x0002; + /// 3rd left (3rd leftmost) LED. Has a value of `0x0004`. + const LEFT_3 = 0x0004; + /// 4th left (4th leftmost) LED. Has a value of `0x0008`. + const LEFT_4 = 0x0008; + /// 5th left (5th leftmost) LED. Has a value of `0x0010`. + const LEFT_5 = 0x0010; + /// 1st middle (6th leftmost) LED. Has a value of `0x0020`. + const MIDDLE_1 = 0x0020; + /// 2nd middle (7th leftmost) LED. Has a value of `0x0040`. + const MIDDLE_2 = 0x0040; + /// 3rd middle (8th leftmost) LED. Has a value of `0x0080`. + const MIDDLE_3 = 0x0080; + /// 4th middle (9th leftmost) LED . Has a value of `0x0100`. + const MIDDLE_4 = 0x0100; + /// 5th middle (10th leftmost) LED . Has a value of `0x0200`. + const MIDDLE_5 = 0x0200; + /// 1st right (11th leftmost) LED. Has a value of `0x0400`. + const RIGHT_1 = 0x0400; + /// 2nd right (12th leftmost) LED. Has a value of `0x0800`. + const RIGHT_2 = 0x0800; + /// 3rd right (13th leftmost) LED. Has a value of `0x1000`. + const RIGHT_3 = 0x1000; + /// 4th right (14th leftmost) LED. Has a value of `0x2000`. + const RIGHT_4 = 0x2000; + /// 5th right (15th leftmost) LED. Has a value of `0x4000`. + const RIGHT_5 = 0x4000; + } +} + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum MfdPanelIndex { + CarSetup = 0, + Pits = 1, + Damage = 2, + Engine = 3, + Temperatures = 4, + Closed = 255, +} diff --git a/src/lib.rs b/src/lib.rs index 6be16b8..504d338 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,11 @@ pub mod constants; pub mod packets; use crate::constants::PacketId; -use crate::packets::{F1PacketCarSetupsData, F1PacketEventData, F1PacketLapData, F1PacketMotionData, F1PacketParticipantsData, F1PacketSessionData}; +use crate::packets::{ + F1PacketCarSetupsData, F1PacketCarTelemetryData, F1PacketEventData, + F1PacketLapData, F1PacketMotionData, F1PacketParticipantsData, + F1PacketSessionData, +}; use binrw::io::Cursor; use binrw::{BinRead, BinReaderExt, BinResult}; @@ -87,4 +91,6 @@ pub struct F1PacketBody { /// Car setups for each vehicle in the session. #[br(if(packet_id == PacketId::CarSetups), args(packet_format))] pub car_setups: Option, + #[br(if(packet_id == PacketId::CarTelemetry), args(packet_format))] + pub car_telemetry: Option, } diff --git a/src/packets/car_telemetry.rs b/src/packets/car_telemetry.rs new file mode 100644 index 0000000..65d3c1f --- /dev/null +++ b/src/packets/car_telemetry.rs @@ -0,0 +1,90 @@ +use super::u8_to_bool; +use crate::constants::{RevLights, Surface}; + +use binrw::BinRead; +use serde::{Deserialize, Serialize}; + +#[non_exhaustive] +#[derive( + BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize, +)] +#[br( + little, + import(_packet_format: u16), + assert( + (0.0..=1.0).contains(&throttle), + "Car telemetry entry has an invalid throttle value: {}", + throttle + ), + assert( + (-1.0..=1.0).contains(&steer), + "Car telemetry entry has an invalid steering lock value: {}", + steer + ), + assert( + (0.0..=1.0).contains(&brake), + "Car telemetry entry has an invalid brake value: {}", + brake + ), + assert( + (0..=100).contains(&clutch), + "Car telemetry entry has an invalid clutch value: {}", + clutch + ), + assert( + (-1..=8).contains(&gear), + "Car telemetry entry has an invalid gear value: {}", + gear + ), + assert( + (0..=100).contains(&rev_lights_percent), + "Car telemetry entry has an invalid rev lights percentage: {}", + rev_lights_percent + ), +)] +pub struct CarTelemetryData { + /// Speed of the car in kilometres per hour. + pub speed: u16, + /// Amount of throttle applied. Value in range `(0.0..=1.0)`. + pub throttle: f32, + /// Steering lock. Value in range `(-1.0..=1.0)`. + pub steer: f32, + /// Amount of brake applied. Value in range `(0.0..=1.0)`. + pub brake: f32, + /// Amount of clutch applied. Value in range `(0..=100)`. + pub clutch: u8, + /// Selected gear. Neutral = 0, reverse = -1. + pub gear: i8, + /// Engine RPM. + pub engine_rpm: u16, + /// Whether DRS is enabled. + #[br(map(u8_to_bool))] + pub drs_enabled: bool, + /// Rev lights indicator (percentage). + pub rev_lights_percent: u8, + /// Bitmap of active rev lights. + #[br(map(|bits: u16| RevLights::from_bits_truncate(bits)))] + pub rev_lights_bit_value: RevLights, + /// Brake temperatures in degrees Celsius. + /// See [`wheel_index`](mod@crate::constants::wheel_index) + /// for wheel order. + pub brakes_temperature: [u16; 4], + /// Tyres' surface temperature in degrees Celsius. + /// See [`wheel_index`](mod@crate::constants::wheel_index) + /// for wheel order. + pub tyres_surface_temperature: [u8; 4], + /// Tyres' inner temperature in degrees Celsius. + /// See [`wheel_index`](mod@crate::constants::wheel_index) + /// for wheel order. + pub tyres_inner_temperature: [u8; 4], + /// Engine's temperature in degrees Celsius + pub engine_temperature: u16, + /// Tyres' pressue temperature in degrees Celsius. + /// See [`wheel_index`](mod@crate::constants::wheel_index) + /// for wheel order. + pub tyres_pressure: [f32; 4], + /// Driving surface of each tyre. + /// See [`wheel_index`](mod@crate::constants::wheel_index) + /// for wheel order. + pub surface_type: Option<[Surface; 4]>, +} diff --git a/src/packets/mod.rs b/src/packets/mod.rs index df9b856..ca0d2f7 100644 --- a/src/packets/mod.rs +++ b/src/packets/mod.rs @@ -1,15 +1,16 @@ +pub mod car_setups; +pub mod car_telemetry; pub mod event; pub mod lap_data; pub mod motion; pub mod participants; pub mod session; -mod car_setups; use crate::constants::{ BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy, - Formula, GameMode, GearboxAssist, Ruleset, SafetyCarStatus, SessionLength, - SessionType, TrackId, Weather, MAX_AI_DIFFICULTY, MAX_NUM_CARS, - MAX_NUM_MARSHAL_ZONES, MAX_NUM_WEATHER_FORECAST_SAMPLES, + Formula, GameMode, GearboxAssist, MfdPanelIndex, Ruleset, SafetyCarStatus, + SessionLength, SessionType, TrackId, Weather, MAX_AI_DIFFICULTY, + MAX_NUM_CARS, MAX_NUM_MARSHAL_ZONES, MAX_NUM_WEATHER_FORECAST_SAMPLES, }; use crate::packets::event::EventDataDetails; use crate::packets::lap_data::LapData; @@ -18,6 +19,7 @@ use crate::packets::participants::ParticipantsData; use crate::packets::session::{MarshalZone, WeatherForecastSample}; use crate::packets::car_setups::CarSetupData; +use crate::packets::car_telemetry::CarTelemetryData; use binrw::BinRead; use serde::{Deserialize, Serialize}; use std::string::FromUtf8Error; @@ -228,9 +230,10 @@ pub struct F1PacketParticipantsData { pub participants: Vec, } -/// Packet detailing car setups for cars in the race. +/// Car setups for all cars in the race. /// In multiplayer games, other player cars will appear as blank. /// You will only be able to see your car setup and AI cars. +#[non_exhaustive] #[derive( BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, )] @@ -242,6 +245,36 @@ pub struct F1PacketCarSetupsData { pub car_setups: Vec, } +/// Telemetry (such as speed, DRS, throttle application, etc.) +/// for all cars in the race. +#[derive( + BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, +)] +#[br( + little, + import(packet_format: u16), + assert( + (-1..=8).contains(&suggested_gear), + "Car telemetry entry has an invalid suggested gear value: {}", + suggested_gear + ), +)] +pub struct F1PacketCarTelemetryData { + /// Telemetry data for all cars on track. + /// Should have a size of 22 + #[br( + count(MAX_NUM_CARS), + args{ inner: (packet_format,) } + )] + pub car_telemetry_data: Vec, + /// Index of currently open MFD panel. + pub mfd_panel_index: MfdPanelIndex, + /// See [`mfd_panel_index`](field@F1PacketCarTelemetryData::mfd_panel_index) + pub mfd_panel_index_secondary_player: MfdPanelIndex, + /// Suggested gear (0 if no gear suggested). + pub suggested_gear: i8, +} + /// Extended motion data for player's car. Available as a: /// - part of [`F1PacketMotionData`] in the 2022 format /// - standalone packet from the 2023 format onwards