B4J Question [Solved] Problem parsing UDP Packets from F1 2018 (PS/4 Game) - Need help

DonManfred

Expert
Licensed User
Longtime User
Hello,

i am parsing UDP-Packets which is send out from the PS/4 Game to my PC. Here a B4J App is capturing the PAckets and i want to analyse the Data coming in.

The Specs are documented here.

The UDP-Packets always have a size of 1367 Bytes

What encoding format is used?
All values are encoded using Little Endian format.

The Pasing is done using RandomAccessFile.

B4X:
Sub UDP_PacketArrived (Packet As UDPPacket)
    pktUDP = pktUDP +1
    Dim raf As RandomAccessFile
    raf.Initialize3(Packet.Data, True) 'change the endianess if the version number is incorrect
    Dim hdr As pktHeader =  ParseHeader(raf)

B4X:
Sub ParseHeader(raf As RandomAccessFile) As pktHeader
    'Log("ParseMessage("&data.Length&")")
    Dim hdr As pktHeader
    hdr.Initialize
    hdr.packetFormat = raf.ReadShort(0)
    hdr.packetVersion = raf.ReadunSignedByte(2)
    hdr.packetId = raf.ReadunSignedByte(3)
    hdr.sessionUID = raf.ReadDouble(4)
    hdr.SessionTime = raf.ReadFloat(12)
    hdr.frameIdentifier = raf.ReadInt(16)
    hdr.PlayerCarIndex = raf.ReadunSignedByte(20)
    Return hdr
End Sub

Parsing the Header does work fine. I can distinguish all the different Packets to further parse the packet using the different "subtypes" of the Packet.
fj958zeqdhf8.png


Most of the PacketTypes i can parse fine. But for the Car Telemetry for ex. it does not work.
Values like Speed, Gear, EngineRPM and EngineTemp gives me unexpected Values.

CarTelemetry #8: UUID:-9223372036854775808: Gear: 70, Speed: 768, EngineRPM: -28669, EngineTemp: -21504

A Hexdump of the CarTelemetry-Packet is like this

E2070106C4879BC94DE4C4F93F360B3D010000001300000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000DA0E00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000AE0D00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000AE0D00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000AE0D00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000DA0E00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000DA0E00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000AE0D00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000DA0E00002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE1000002000200020002000540054005400540054005400540054005A000000AC410000AC410000B8410000B84100000000000000CE10000020002000200020005400540054005400540054005400540059000000AC410000AC410000B8410000B84100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

The Headerpart is the first 21 Bytes.
E2070106C4879BC94DE4C4F93F360B3D0100000013

The Code for Telemetry is like (as of now)
B4X:
Sub parseCarTelemetryData(raf As RandomAccessFile) As List
    Dim telelist As List
    telelist.Initialize
    Dim pos As Int = 21
  
    For i = 0 To 19
        Dim car As CarTelemetry
        car.Initialize
        Private a(2) As Byte
        Private result() As Short
        raf.ReadBytes(a,0,a.Length,pos)' .ReadUnsignedByte(pos)
        'a(1)=raf.ReadUnsignedByte(pos)
        result=ConvertShort(a)
        pos = pos +2
        car.Speed = result(0) 'raf.ReadShort(pos)
        pos = pos +2
        car.throttle = raf.ReadUnSignedByte(pos)
        pos = pos +1
        car.Steer = raf.ReadSignedByte(pos)
        pos = pos +1
        car.Brake = raf.ReadunSignedByte(pos)
        pos = pos +1
        car.Clutch = raf.ReadunSignedByte(pos)
        pos = pos +1
        car.Gear = raf.ReadSignedByte(pos)
        pos = pos +1
        car.engineRPM = raf.ReadShort(pos)
        pos = pos +2
        car.drs = raf.ReadunSignedByte(pos)
        pos = pos +1
        car.revLightsPercent = raf.ReadSignedByte(pos)
        pos = pos +1

        car.brakesTemperature(0) = raf.ReadShort(pos)
        pos = pos +2
        car.brakesTemperature(1) = raf.ReadShort(pos)
        pos = pos +2
        car.brakesTemperature(2) = raf.ReadShort(pos)
        pos = pos +2
        car.brakesTemperature(3) = raf.ReadShort(pos)
        pos = pos +2

        car.tyresSurfaceTemperature (0) = raf.ReadShort(pos)
        pos = pos +2
        car.tyresSurfaceTemperature (1) = raf.ReadShort(pos)
        pos = pos +2
        car.tyresSurfaceTemperature (2) = raf.ReadShort(pos)
        pos = pos +2
        car.tyresSurfaceTemperature (3) = raf.ReadShort(pos)
        pos = pos +2

        car.tyresInnerTemperature(0) = raf.ReadShort(pos)
        pos = pos +2
        car.tyresInnerTemperature(1) = raf.ReadShort(pos)
        pos = pos +2
        car.tyresInnerTemperature(2) = raf.ReadShort(pos)
        pos = pos +2
        car.tyresInnerTemperature(3) = raf.ReadShort(pos)
        pos = pos +2

        car.engineTemperature = raf.ReadShort(pos)
        pos = pos +2

        car.tyresPressure(0) = raf.ReadFloat(pos)
        pos = pos +4
        car.tyresPressure(1) = raf.ReadFloat(pos)
        pos = pos +4
        car.tyresPressure(2) = raf.ReadFloat(pos)
        pos = pos +4
        car.tyresPressure(3) = raf.ReadFloat(pos)
        pos = pos +4
        telelist.Add(car)
    Next
    'Dim tele As pktCarTelemetryData
    'tele.Initialize
    'tele.CarTelemetryList = telelist
    Return telelist
End Sub

I started using
B4X:
car.Speed = raf.ReadShort(pos)
but it does not give me the expected results. So i then tried to find another way to parse
uint16, uint8, int8 and Float Values

I a using Types to parse the Packets into the different types of Data.

B4X:
    Type pktHeader (packetFormat As Short, packetVersion As Byte, packetId As Short, _
     sessionUID As Long, SessionTime As Float, frameIdentifier As Int, PlayerCarIndex As Short)

    Type MarshalZone(ZoneStart As Float, ZoneFlag As Short)

    Type pktSession(Weather As Short, TrackTemperature As Short, AirTemperature As Short, TotalLaps As Short, TrackLength As Short, SessionType As Short, TrackID As Short, Era As Short, SessionTimeLeft As Double, SessionDuration As Double, PitSpeedLimit As Short, GamePaused As Short, IsSpectating As Short, SpectatorCarIndex As Short, sliProNativeSupport As Short, NumMarshalZones As Short, MarshalZones(21) As MarshalZone,safetyCarStatus As Short, NetworkGame As Short)
    Type pktEventData(Name As String)
   
    Type pktLapData(lastLapTime As Float, currentLapTime As Float, bestLapTime As Float, sector1Time As Float, sector2Time As Float, lapDistance As Float, totalDistance As Float, safetyCarDelta As Float, carPosition As Int, currentLapNum As Int, PitStatus As Int, sector As Int, currentLapInvalid As Int, penalties As Int, gridPosition As Int, driverStatus As Int, ResultStatus As Int)

    Type pktParticipant(AIControlled As Int, DriverID As Int, TeamID As Int, raceNumber As Int, Nationality As Short, Name As String)
    Type pktParticipantData(numCars As Short, DriverList As List)

    Type pktMotionData(CarMotionList As List, suspensionPosition(4) As Float, suspensionVelocity(4) As Float, suspensionAcceleration(4) As Float, wheelSpeed(4) As Float, wheelSlip(4) As Float, localVelocityX As Float, localVelocityY As Float, localVelocityZ As Float, angularVelocityX As Float, angularVelocityY As Float, angularVelocityZ As Float, angularAccelerationX As Float, angularAccelerationY As Float, angularAccelerationZ As Float, frontWheelsAngle As Float)
   
    Type CarMotion(worldPositionX As Float, worldPositionY As Float, worldPositionZ As Float, worldVelocityX As Float, worldVelocityY As Float, worldVelocityZ As Float, worldForwardDirX As Float, worldForwardDirY As Float, worldForwardDirZ As Float, worldRightDirX As Float, worldRightDirY As Float, worldRightDirZ As Float, gForceLateral As Float, gForceLongitudinal As Float, gForceVertical As Float, yaw As Float, Pitch As Float, Roll As Float)

    Type pktCarTelemetryData(CarTelemetryList As List)
    Type CarTelemetry(Speed As Short, throttle As Short, Steer As Short, Brake As Short, Clutch As Short, Gear As Short, engineRPM As Short, drs As Short, revLightsPercent As Short, brakesTemperature(4) As Short, tyresSurfaceTemperature(4) As Short, tyresInnerTemperature(4) As Short, engineTemperature As Short, tyresPressure(4) As Short)

    Type CarSetup(frontWing As Int, rearWing As Int, onThrottle As Int, offThrottle As Int, frontCamber As Float, rearCamber As Float, frontToe As Float, rearToe As Float, frontSuspension As Int, rearSuspension As Int, frontAntiRollBar As Int, rearAntiRollBar As Int, frontSuspensionHeight As Int, rearSuspensionHeight As Int, brakePressure As Int, brakeBias As Int, frontTyrePressure As Float, rearTyrePressure As Float, ballast As Int, fuelLoad As Float, tyresWear(4) As Short)

    Type CarStatus(tractionControl As Short, antiLockBrakes As Short, fuelMix As Short, frontBrakeBias As Short, pitLimiterStatus As Short, fuelInTank As Float, fuelCapacity As Float, maxRPM As Short, idleRPM As Short, maxGears As Short, drsAllowed As Int, TyreCompound As Int, tyresWear(4) As Short, tyresDamage(4) As Short, frontLeftWingDamage As Short, frontRightWingDamage As Short, rearWingDamage As Short, engineDamage As Short, gearBoxDamage As Short, exhaustDamage As Short, vehicleFiaFlags As Short, ersStoreEnergy As Float, ersDeployMode As Short, ersHarvestedThisLapMGUK As Float, ersHarvestedThisLapMGUH As Float, ersDeployedThisLap As Float)


Is there anyone who might want to help with the parsing?

Any suggestion/tips are highly welcome! :)

PD: Even if this thread is about the PS/4 Game. It will work with the PC-Edition of the game too.
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
Working are for example are
Header,

LapData
LapData Driver #0: UUID:-9223372036854775808: CurrTime: 26.590979, BestLapTime: 0.0, LapDist: 1106.0923, TotalDist: 1106.0923, CarPosition: 15 CurrLapNum 1, Sector: 0, Sec1Time: 0.0, Sec2Time: 0.0, Penalties: 0


I´m unsure about
CarMotion
B4X:
CarMotion Car #0: X:-730.3564: Y:3.071277, Z:-390.42322, Pitch: 0.0066893375
CarTelemetry
CarTelemetry #0: UUID:-9223372036854775808: Gear: 35, Speed: 74, EngineRPM: 0, EngineTemp: 0
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi Don,
according to this document an uint16 (Mathlab) should be an unsigned 16 bit value (0..65535) so a java short will just fall ..short eheh
I didn't check what raf.<type> returns so I may be wrong but applying the above to
car.engineRPM = raf.ReadShort(pos)
if a short is returned where an unsigned 16bit value is expected may result in those "wrong" readings.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
should be an unsigned 16 bit value (0..65535) so a java short will just fall
Ok, make sense. This seems to apply to the Speed also. I tried to read the Value another way in the code to get the Speed.
uint16 m_speed; // Speed of car in kilometres per hour

B4X:
       Private a(2) As Byte
       Private result() As Short
       raf.ReadBytes(a,0,a.Length,pos)' .ReadUnsignedByte(pos)
       'a(1)=raf.ReadUnsignedByte(pos)
       result=ConvertShort(a)


Sub ConvertShort (barray() As Byte) As Short()
    Private bc As ByteConverter
    Private shorts() As Short
    bc.LittleEndian = True
    shorts=bc.ShortsFromBytes(barray)
    Return shorts
End Sub
but this also fails.

How would i parse the value correctly? Maybe using the Hex-Code or by building the value itself using the single bytes
 
Upvote 0

udg

Expert
Licensed User
Longtime User
I am rushing to work but I'll give it a try later in the day (using your published data)
 
Upvote 0
Top