From 6e98400f160421f44f47effeeaa97e9d909d14d7 Mon Sep 17 00:00:00 2001 From: PrimeGoose <64712362+PrimeGoose@users.noreply.github.com> Date: Sun, 12 Jun 2022 19:14:16 +0100 Subject: [PATCH] car telemetry --- .prettierrc.js | 2 +- src/F1_22_UDP.ts | 41 +++++++----- src/constants/index.ts | 1 + src/parsers/CarTelemetry/CarTelemetry.spec.md | 42 ++++++++++++ src/parsers/CarTelemetry/parsers/index.ts | 67 +++++++++++++++++++ src/parsers/CarTelemetry/types/index.d.ts | 29 ++++++++ src/parsers/Event/parsers/index.ts | 27 ++------ src/parsers/PacketHeader/parser/index.ts | 12 +--- 8 files changed, 172 insertions(+), 49 deletions(-) create mode 100644 src/parsers/CarTelemetry/CarTelemetry.spec.md create mode 100644 src/parsers/CarTelemetry/parsers/index.ts create mode 100644 src/parsers/CarTelemetry/types/index.d.ts diff --git a/.prettierrc.js b/.prettierrc.js index 6fa78e8..3ffedc5 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,4 +1,4 @@ module.exports = { ...require('gts/.prettierrc.json'), - printWidth: 120 + printWidth: 280 } diff --git a/src/F1_22_UDP.ts b/src/F1_22_UDP.ts index e32e854..dff1a69 100644 --- a/src/F1_22_UDP.ts +++ b/src/F1_22_UDP.ts @@ -1,4 +1,4 @@ -import {createSocket, Socket, RemoteInfo} from 'node:dgram'; +import {createSocket,Socket,RemoteInfo} from 'node:dgram'; import {EventEmitter} from 'node:stream'; import {PacketMotionDataParser} from './parsers/Motion/parsers'; import {PacketSessionDataParser} from './parsers/Session/parsers'; @@ -6,6 +6,8 @@ import {packetSize} from './constants'; import {PacketLapDataParser} from './parsers/LapData/parsers'; import {PacketEventDataParser} from './parsers/Event/parsers'; import {PacketParticipantsParser} from './parsers/Participants/parsers'; +import {PacketCarSetupDataParser} from './parsers/CarSetup/parsers'; +import {PacketCarTelemetryDataParser} from './parsers/CarTelemetry/parsers'; export class F122UDP extends EventEmitter { private socket: Socket; @@ -17,18 +19,18 @@ export class F122UDP extends EventEmitter { // create socket start() { // if socket is not created, create it - if (!this.socket) { + if(!this.socket) { this.socket = createSocket('udp4'); } - this.socket.bind({port: 20777, address: '192.168.88.200'}); + this.socket.bind({port: 20777,address: '192.168.88.200'}); console.log('start'); - this.socket.on('listening', (): void => { - console.log('F122UDP listening on: ', this.socket.address().address, ':', this.socket.address().port); - this.socket.on('message', (msg: Buffer, rinfo: RemoteInfo): void => { - switch (rinfo.size) { + this.socket.on('listening',(): void => { + console.log('F122UDP listening on: ',this.socket.address().address,':',this.socket.address().port); + this.socket.on('message',(msg: Buffer,rinfo: RemoteInfo): void => { + switch(rinfo.size) { case packetSize.Motion: { const {data} = new PacketMotionDataParser(msg); - this.emit('motion', data); + this.emit('motion',data); // console.log(motionDataPacket); break; } @@ -36,37 +38,46 @@ export class F122UDP extends EventEmitter { { console.log('Session'); const {data} = new PacketSessionDataParser(msg); - this.emit('session', data); + this.emit('session',data); // console.log(data); } break; case packetSize.LapData: { const {data} = new PacketLapDataParser(msg); - this.emit('lap', data); + this.emit('lap',data); // console.log(data); break; } case packetSize.Event: { const {data} = new PacketEventDataParser(msg); - this.emit('event', data); + this.emit('event',data); break; } case packetSize.Participants: { console.log('Participants'); const {data} = new PacketParticipantsParser(msg); - this.emit('participants', data); + this.emit('participants',data); // console.log(data); break; } - case packetSize.CarSetups: + case packetSize.CarSetups: { // console.log("CarSetups"); + const {data} = new PacketCarSetupDataParser(msg,false) + this.emit('carSetups',data); + break; - case packetSize.CarTelemetry: + } + case packetSize.CarTelemetry:{ // console.log("CarTelemetry"); + const {data} = new PacketCarTelemetryDataParser(msg,false) + this.emit('carTelemetry',data); + console.log(data); + break; + } case packetSize.CarStatus: // console.log("CarStatus"); break; @@ -96,7 +107,7 @@ export class F122UDP extends EventEmitter { } // process exit on ctrl+c -process.on('SIGINT', () => { +process.on('SIGINT',() => { console.log('SIGINT'); // process.exit(1); }); diff --git a/src/constants/index.ts b/src/constants/index.ts index e739c62..e13f827 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -23,6 +23,7 @@ export enum packetSize { CarSetups = 1102, CarTelemetry = 1347, CarStatus = 1058, + Finallassification = 1015, LobbyInfo = 1191, CarDamage = 882, SessionHistory = 1155, diff --git a/src/parsers/CarTelemetry/CarTelemetry.spec.md b/src/parsers/CarTelemetry/CarTelemetry.spec.md new file mode 100644 index 0000000..e741448 --- /dev/null +++ b/src/parsers/CarTelemetry/CarTelemetry.spec.md @@ -0,0 +1,42 @@ +Car Telemetry Packet + +This packet details telemetry for all the cars in the race. It details various values that would be recorded on the car such as speed, throttle application, DRS etc. Note that the rev light configurations are presented separately as well and will mimic real life driver preferences. + +Frequency: Rate as specified in menus +Size: 1347 bytes +Version: 1 + +struct CarTelemetryData +{ + uint16 m_speed; // Speed of car in kilometres per hour + float m_throttle; // Amount of throttle applied (0.0 to 1.0) + float m_steer; // Steering (-1.0 (full lock left) to 1.0 (full lock right)) + float m_brake; // Amount of brake applied (0.0 to 1.0) + uint8 m_clutch; // Amount of clutch applied (0 to 100) + int8 m_gear; // Gear selected (1-8, N=0, R=-1) + uint16 m_engineRPM; // Engine RPM + uint8 m_drs; // 0 = off, 1 = on + uint8 m_revLightsPercent; // Rev lights indicator (percentage) + uint16 m_revLightsBitValue; // Rev lights (bit 0 = leftmost LED, bit 14 = rightmost LED) + uint16 m_brakesTemperature[4]; // Brakes temperature (celsius) + uint8 m_tyresSurfaceTemperature[4]; // Tyres surface temperature (celsius) + uint8 m_tyresInnerTemperature[4]; // Tyres inner temperature (celsius) + uint16 m_engineTemperature; // Engine temperature (celsius) + float m_tyresPressure[4]; // Tyres pressure (PSI) + uint8 m_surfaceType[4]; // Driving surface, see appendices +}; + +struct PacketCarTelemetryData +{ + PacketHeader m_header; // Header + + CarTelemetryData m_carTelemetryData[22]; + + uint8 m_mfdPanelIndex; // Index of MFD panel open - 255 = MFD closed + // Single player, race – 0 = Car setup, 1 = Pits + // 2 = Damage, 3 = Engine, 4 = Temperatures + // May vary depending on game mode + uint8 m_mfdPanelIndexSecondaryPlayer; // See above + int8 m_suggestedGear; // Suggested gear for the player (1-8) + // 0 if no gear suggested +}; \ No newline at end of file diff --git a/src/parsers/CarTelemetry/parsers/index.ts b/src/parsers/CarTelemetry/parsers/index.ts new file mode 100644 index 0000000..6792a0c --- /dev/null +++ b/src/parsers/CarTelemetry/parsers/index.ts @@ -0,0 +1,67 @@ +import {Parser} from 'binary-parser'; +import {F1Parser} from '../../f1.parser'; + +export class CarTelemetryDataParser extends F1Parser { + constructor() { + super(); + this.uint16le('m_speed') + .floatle('m_throttle') + .floatle('m_steer') + .floatle('m_brake') + .uint8('m_clutch') + .int8('m_gear') + .uint16le('m_engineRPM') + .uint8('m_drs') + .uint8('m_revLightsPercent') + .uint16le('m_revLightsBitValue') + .array('m_brakesTemperature', { + length: 4, + type: new Parser().uint16le(''), + }) + .array('m_tyresSurfaceTemperature', { + length: 4, + type: new Parser().uint8(''), + }) + .array('m_tyresInnerTemperature', { + length: 4, + type: new Parser().uint8(''), + }) + .uint16le('m_engineTemperature') + + .array('m_tyresPressure', { + length: 4, + type: new Parser().floatle(''), + }) + .array('m_surfaceType', { + length: 4, + type: new Parser().uint8(''), + }); + } +} + +import {PacketHeaderParser} from '../../PacketHeader/parser'; +import {PacketCarTelemetryData} from '../types'; + +export class PacketCarTelemetryDataParser extends F1Parser { + data: PacketCarTelemetryData; + + constructor(buffer: Buffer, bigintEnabled: boolean) { + super(); + + this.endianess('little') + .nest('m_header', { + type: new PacketHeaderParser(bigintEnabled), + }) + + .array('m_carTelemetryData', { + length: 22, + type: new CarTelemetryDataParser(), + }) + + .uint8('m_mfdPanelIndex') + .uint8('m_mfdPanelIndexSecondaryPlayer') + .int8('m_suggestedGear'); + + this.data = this.fromBuffer(buffer) as PacketCarTelemetryData; + } +} diff --git a/src/parsers/CarTelemetry/types/index.d.ts b/src/parsers/CarTelemetry/types/index.d.ts new file mode 100644 index 0000000..5fb7971 --- /dev/null +++ b/src/parsers/CarTelemetry/types/index.d.ts @@ -0,0 +1,29 @@ +import {PacketHeader} from '@Type/PacketHeader'; + +export interface CarTelemetryData { + /*uint16*/ m_speed: number; + /*float*/ m_throttle: number; + /*float*/ m_steer: number; + /*float*/ m_brake: number; + /*uint8*/ m_clutch: number; + /*int8*/ m_gear: number; + /*uint16*/ m_engineRPM: number; + /*uint8*/ m_drs: number; + /*uint8*/ m_revLightsPercent: number; + /*uint16*/ m_revLightsBitValue: number; + /*uint16*/ m_brakesTemperature: [number, number, number, number]; + /*uint8*/ m_tyresSurfaceTemperature: [number, number, number, number]; + /*uint8*/ m_tyresInnerTemperature: [number, number, number, number]; + /*uint16*/ m_engineTemperature: number; + /*float*/ m_tyresPressure: [number, number, number, number]; + /*uint8*/ m_surfaceType: [number, number, number, number]; +} + +export interface PacketCarTelemetryData { + m_header: PacketHeader; + m_buttonStatus: number; + m_carTelemetryData: CarTelemetryData[]; + m_mfdPanelIndex: number; + m_mfdPanelIndexSecondaryPlayer: number; + m_suggestedGear: number; +} diff --git a/src/parsers/Event/parsers/index.ts b/src/parsers/Event/parsers/index.ts index ff8a895..e515e45 100644 --- a/src/parsers/Event/parsers/index.ts +++ b/src/parsers/Event/parsers/index.ts @@ -57,27 +57,14 @@ export class PenaltyParser extends F1Parser { constructor() { super(); - this.endianess('little') - .uint8('penaltyType') - .uint8('infringementType') - .uint8('vehicleIdx') - .uint8('otherVehicleIdx') - .uint8('time') - .uint8('lapNum') - .uint8('placesGained'); + this.endianess('little').uint8('penaltyType').uint8('infringementType').uint8('vehicleIdx').uint8('otherVehicleIdx').uint8('time').uint8('lapNum').uint8('placesGained'); } } export class SpeedTrapParser extends F1Parser { constructor() { super(); - this.endianess('little') - .uint8('vehicleIdx') - .floatle('speed') - .uint8('isOverallFastestInSession') - .uint8('isDriverFastestInSession') - .uint8('fastestVehicleIdxInSession') - .floatle('fastestSpeedInSession'); + this.endianess('little').uint8('vehicleIdx').floatle('speed').uint8('isOverallFastestInSession').uint8('isDriverFastestInSession').uint8('fastestVehicleIdxInSession').floatle('fastestSpeedInSession'); } } @@ -169,10 +156,7 @@ export class PacketEventDataParser extends F1Parser { constructor(buffer: Buffer) { super(); - this.endianess('little') - .nest('m_header', {type: new PacketHeaderParser()}) - .string('m_eventStringCode', {length: 4}) - .unpack2021Format(buffer); + this.endianess('little').nest('m_header', {type: new PacketHeaderParser()}).string('m_eventStringCode', {length: 4}).unpack2021Format(buffer); this.data = this.fromBuffer(buffer) as PacketEventData; } @@ -208,10 +192,7 @@ export class PacketEventDataParser extends F1Parser { }; getEventStringCode = (buffer: Buffer) => { - const headerParser = new Parser() - .endianess('little') - .nest('m_header', {type: new PacketHeaderParser()}) - .string('m_eventStringCode', {length: 4}); + const headerParser = new Parser().endianess('little').nest('m_header', {type: new PacketHeaderParser()}).string('m_eventStringCode', {length: 4}); const {m_eventStringCode} = headerParser.parse(buffer); return m_eventStringCode; }; diff --git a/src/parsers/PacketHeader/parser/index.ts b/src/parsers/PacketHeader/parser/index.ts index fbfbc7a..04a8afc 100644 --- a/src/parsers/PacketHeader/parser/index.ts +++ b/src/parsers/PacketHeader/parser/index.ts @@ -3,21 +3,13 @@ import {F1Parser} from '../../f1.parser'; export class PacketHeaderParser extends F1Parser { constructor(bigintEnabled = false) { super(); - this.endianess('little') - .uint16le('m_packetFormat') - .uint8('m_gameMajorVersion') - .uint8('m_gameMinorVersion') - .uint8('m_packetVersion') - .uint8('m_packetId'); + this.endianess('little').uint16le('m_packetFormat').uint8('m_gameMajorVersion').uint8('m_gameMinorVersion').uint8('m_packetVersion').uint8('m_packetId'); if (bigintEnabled) { this.uint64('m_sessionUID'); } else { this.skip(8); } - this.floatle('m_sessionTime') - .uint32le('m_frameIdentifier') - .uint8('m_playerCarIndex') - .uint8('m_secondaryPlayerCarIndex'); + this.floatle('m_sessionTime').uint32le('m_frameIdentifier').uint8('m_playerCarIndex').uint8('m_secondaryPlayerCarIndex'); } }