feat: add 2022 spec car telemetry packet parser

This commit is contained in:
Maciej Pędzich 2025-02-18 13:01:08 +01:00
parent 06b8bfe133
commit 8ea06e5a53
Signed by: maciejpedzich
GPG Key ID: CE4A303D84882F0D
5 changed files with 364 additions and 6 deletions

127
src/constants/driver_id.rs Normal file
View File

@ -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;

View File

@ -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,
}

View File

@ -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<F1PacketCarSetupsData>,
#[br(if(packet_id == PacketId::CarTelemetry), args(packet_format))]
pub car_telemetry: Option<F1PacketCarTelemetryData>,
}

View File

@ -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]>,
}

View File

@ -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<ParticipantsData>,
}
/// 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<CarSetupData>,
}
/// 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<CarTelemetryData>,
/// 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