For context: I'm trying to adjust the f1_22_telemetry code to the new F1 23 UDP Socket (my repo).
Here is the Documentation by EA: https://answers.ea.com/t5/General-Discussion/F1-23-UDP-Specification/td-p/12632888?attachment-id=704910
Some packets appear to be working fine, but others show weird/wrong values after being converted to a dictionary.
I took Chris Hannam's Code and changed the classes for the Packets with the information in the EA documentation. So the logic should be the same and worked fine with the F1 22 Socket.
Example: PacketSessionData
My Class:
class PacketSessionData(Packet):
_fields_ = [
("header", PacketHeader),
("weather", ctypes.c_uint8),
("trackTemperature", ctypes.c_int8),
("airTemperature", ctypes.c_int8),
("totalLaps", ctypes.c_uint8),
("trackLength", ctypes.c_uint16),
("sessionType", ctypes.c_uint8),
("trackId", ctypes.c_int8),
("formula", ctypes.c_uint8),
("sessionTimeLeft", ctypes.c_uint16),
("sessionDuration", ctypes.c_uint16),
("pitSpeedLimit", ctypes.c_uint8),
("gamePaused", ctypes.c_uint8),
("isSpectating", ctypes.c_uint8),
("spectatorCarIndex", ctypes.c_uint8),
("sliProNativeSupport", ctypes.c_uint8),
("numMarshalZones", ctypes.c_uint8),
("marshalZones", MarshalZone * 21),
("safetyCarStatus", ctypes.c_uint8),
("networkGame", ctypes.c_uint8),
("numWeatherForecastSamples", ctypes.c_uint8),
("forecastAccuracy", ctypes.c_uint8),
("aiDifficulty", ctypes.c_uint8),
("seasonLinkIdentifier", ctypes.c_uint32),
("weekendLinkIdentifier", ctypes.c_uint32),
("sessionLinkIdentifier", ctypes.c_uint32),
("pitStopWindowIdealLap", ctypes.c_uint8),
("pitStopWindowLatestLap", ctypes.c_uint8),
("pitStopRejoinPosition", ctypes.c_uint8),
("steeringAssist", ctypes.c_uint8),
("brakingAssist", ctypes.c_uint8),
("gearboxAssist", ctypes.c_uint8),
("pitAssist", ctypes.c_uint8),
("pitReleaseAssist", ctypes.c_uint8),
("ERSAssist", ctypes.c_uint8),
("DRSAssist", ctypes.c_uint8),
("dynamicRacingLine", ctypes.c_uint8),
("dynamicRacingLineType", ctypes.c_uint8),
("gameMode", ctypes.c_uint8),
("ruleSet", ctypes.c_uint8),
("timeOfDay", ctypes.c_uint32),
("sessionLength", ctypes.c_uint8),
("speedUnitsLeadPlayer", ctypes.c_uint8),
("speedUnitsSecondaryPlayer", ctypes.c_uint8),
("numSafetyCarPeriods", ctypes.c_uint8),
("numRedFlagPeriods", ctypes.c_uint8),
]
The Documentation:
struct PacketSessionData
{
PacketHeader m_header; // Header
uint8 m_weather; // Weather - 0 = clear, 1 = light cloud, 2 = overcast
// 3 = light rain, 4 = heavy rain, 5 = storm
int8 m_trackTemperature; // Track temp. in degrees celsius
int8 m_airTemperature; // Air temp. in degrees celsius
uint8 m_totalLaps; // Total number of laps in this race
uint16 m_trackLength; // Track length in metres
uint8 m_sessionType; // 0 = unknown, 1 = P1, 2 = P2, 3 = P3, 4 = Short P
// 5 = Q1, 6 = Q2, 7 = Q3, 8 = Short Q, 9 = OSQ
// 10 = R, 11 = R2, 12 = R3, 13 = Time Trial
int8 m_trackId; // -1 for unknown, see appendix
uint8 m_formula; // Formula, 0 = F1 Modern, 1 = F1 Classic, 2 = F2,
// 3 = F1 Generic, 4 = Beta, 5 = Supercars
// 6 = Esports, 7 = F2 2021
uint16 m_sessionTimeLeft; // Time left in session in seconds
uint16 m_sessionDuration; // Session duration in seconds
uint8 m_pitSpeedLimit; // Pit speed limit in kilometres per hour
uint8 m_gamePaused; // Whether the game is paused – network game only
uint8 m_isSpectating; // Whether the player is spectating
uint8 m_spectatorCarIndex; // Index of the car being spectated
uint8 m_sliProNativeSupport; // SLI Pro support, 0 = inactive, 1 = active
uint8 m_numMarshalZones; // Number of marshal zones to follow
MarshalZone m_marshalZones[21]; // List of marshal zones – max 21
uint8 m_safetyCarStatus; // 0 = no safety car, 1 = full
// 2 = virtual, 3 = formation lap
uint8 m_networkGame; // 0 = offline, 1 = online
uint8 m_numWeatherForecastSamples; // Number of weather samples to follow
WeatherForecastSample m_weatherForecastSamples[56]; // Array of weather forecast samples
uint8 m_forecastAccuracy; // 0 = Perfect, 1 = Approximate
uint8 m_aiDifficulty; // AI Difficulty rating – 0-110
uint32 m_seasonLinkIdentifier; // Identifier for season - persists across saves
uint32 m_weekendLinkIdentifier; // Identifier for weekend - persists across saves
uint32 m_sessionLinkIdentifier; // Identifier for session - persists across saves
uint8 m_pitStopWindowIdealLap; // Ideal lap to pit on for current strategy (player)
uint8 m_pitStopWindowLatestLap; // Latest lap to pit on for current strategy (player)
uint8 m_pitStopRejoinPosition; // Predicted position to rejoin at (player)
uint8 m_steeringAssist; // 0 = off, 1 = on
uint8 m_brakingAssist; // 0 = off, 1 = low, 2 = medium, 3 = high
uint8 m_gearboxAssist; // 1 = manual, 2 = manual & suggested gear, 3 = auto
uint8 m_pitAssist; // 0 = off, 1 = on
uint8 m_pitReleaseAssist; // 0 = off, 1 = on
uint8 m_ERSAssist; // 0 = off, 1 = on
uint8 m_DRSAssist; // 0 = off, 1 = on
uint8 m_dynamicRacingLine; // 0 = off, 1 = corners only, 2 = full
uint8 m_dynamicRacingLineType; // 0 = 2D, 1 = 3D
uint8 m_gameMode; // Game mode id - see appendix
uint8 m_ruleSet; // Ruleset - see appendix
uint32 m_timeOfDay; // Local time of day - minutes since midnight
uint8 m_sessionLength; // 0 = None, 2 = Very Short, 3 = Short, 4 = Medium
// 5 = Medium Long, 6 = Long, 7 = Full
uint8 m_speedUnitsLeadPlayer; // 0 = MPH, 1 = KPH
uint8 m_temperatureUnitsLeadPlayer; // 0 = Celsius, 1 = Fahrenheit
uint8 m_speedUnitsSecondaryPlayer; // 0 = MPH, 1 = KPH
uint8 m_temperatureUnitsSecondaryPlayer; // 0 = Celsius, 1 = Fahrenheit
uint8 m_numSafetyCarPeriods; // Number of safety cars called during session
uint8 m_numVirtualSafetyCarPeriods; // Number of virtual safety cars called
uint8 m_numRedFlagPeriods; // Number of red flags called during session
};
When I receive a SessionData-Packet, there are values that should be impossible to get according to the documentation.
e.g.:
gearBoxAssist: 33
pitReleaseAssist: 27
So I assume something goes wrong during translating the bytes to the dictionary.
From the documentation:
Packet Types
[...] Please note that all values are encoded using Little Endian format. All data is packed.
Session Packet
[...] Size: 644 bytes
Here's a complete definition that matches the documented structure size of 644 bytes.
The problems were:
PacketSessionData
were missing.LittleEndianStructure
is used in the off-chance portability is needed.
import ctypes as ct
class PacketHeader(ct.LittleEndianStructure):
_pack_ = 1
_fields_ = (('m_packetFormat', ct.c_uint16),
('m_gameYear', ct.c_uint8),
('m_gameMajorVersion', ct.c_uint8),
('m_gameMinorVersion', ct.c_uint8),
('m_packetVersion', ct.c_uint8),
('m_packetId', ct.c_uint8),
('m_sessionUID', ct.c_uint64),
('m_sessionTime', ct.c_float),
('m_frameIdentifier', ct.c_uint32),
('m_overallFrameIdentifier', ct.c_uint32),
('m_playerCarIndex', ct.c_uint8),
('m_secondaryPlayerCarIndex', ct.c_uint8))
class MarshalZone(ct.LittleEndianStructure):
_pack_ = 1
_fields_ = (('m_zoneStart', ct.c_float),
('m_zoneFlag', ct.c_int8))
class WeatherForecastSample(ct.LittleEndianStructure):
_pack_ = 1
_fields_ = (('m_sessionType', ct.c_uint8),
('m_timeOffset', ct.c_uint8),
('m_weather', ct.c_uint8),
('m_trackTemperature', ct.c_int8),
('m_trackTemperatureChange', ct.c_int8),
('m_airTemperature', ct.c_int8),
('m_airTemperatureChange', ct.c_int8),
('m_rainPercentage', ct.c_uint8))
class PacketSessionData(ct.LittleEndianStructure):
_pack_ = 1
_fields_ = (('m_header', PacketHeader),
('m_weather', ct.c_uint8),
('m_trackTemperature', ct.c_int8),
('m_airTemperature', ct.c_int8),
('m_totalLaps', ct.c_uint8),
('m_trackLength', ct.c_uint16),
('m_sessionType', ct.c_uint8),
('m_trackId', ct.c_int8),
('m_formula', ct.c_uint8),
('m_sessionTimeLeft', ct.c_uint16),
('m_sessionDuration', ct.c_uint16),
('m_pitSpeedLimit', ct.c_uint8),
('m_gamePaused', ct.c_uint8),
('m_isSpectating', ct.c_uint8),
('m_spectatorCarIndex', ct.c_uint8),
('m_sliProNativeSupport', ct.c_uint8),
('m_numMarshalZones', ct.c_uint8),
('m_marshalZones', MarshalZone * 21),
('m_safetyCarStatus', ct.c_uint8),
('m_networkGame', ct.c_uint8),
('m_numWeatherForecastSamples', ct.c_uint8),
('m_weatherForecastSamples', WeatherForecastSample * 56), # missing
('m_forecastAccuracy', ct.c_uint8),
('m_aiDifficulty', ct.c_uint8),
('m_seasonLinkIdentifier', ct.c_uint32),
('m_weekendLinkIdentifier', ct.c_uint32),
('m_sessionLinkIdentifier', ct.c_uint32),
('m_pitStopWindowIdealLap', ct.c_uint8),
('m_pitStopWindowLatestLap', ct.c_uint8),
('m_pitStopRejoinPosition', ct.c_uint8),
('m_steeringAssist', ct.c_uint8),
('m_brakingAssist', ct.c_uint8),
('m_gearboxAssist', ct.c_uint8),
('m_pitAssist', ct.c_uint8),
('m_pitReleaseAssist', ct.c_uint8),
('m_ERSAssist', ct.c_uint8),
('m_DRSAssist', ct.c_uint8),
('m_dynamicRacingLine', ct.c_uint8),
('m_dynamicRacingLineType', ct.c_uint8),
('m_gameMode', ct.c_uint8),
('m_ruleSet', ct.c_uint8),
('m_timeOfDay', ct.c_uint32),
('m_sessionLength', ct.c_uint8),
('m_speedUnitsLeadPlayer', ct.c_uint8),
('m_temperatureUnitsLeadPlayer', ct.c_uint8), # missing
('m_speedUnitsSecondaryPlayer', ct.c_uint8),
('m_temperatureUnitsSecondaryPlayer', ct.c_uint8), # missing
('m_numSafetyCarPeriods', ct.c_uint8),
('m_numVirtualSafetyCarPeriods', ct.c_uint8), # missing
('m_numRedFlagPeriods', ct.c_uint8))
assert ct.sizeof(PacketSessionData) == 644 # for verification