#telemetry #session #interface #setup #live #data #connection

iracing

Rust interface for Live Telemetry, Session Data, and Setup Files for iRacing

13 unstable releases (3 breaking)

0.4.1 Dec 24, 2020
0.4.0 Apr 12, 2020
0.3.0 Apr 3, 2020
0.2.8 Mar 26, 2020
0.1.2 Mar 13, 2020

#245 in Games

41 downloads per month

MIT license

48KB
947 lines

iRacing.rs

Live telemetry and session data interface for Rust.

Usage

See further examples in /examples

extern crate iracing;
use iracing::Connection;
use iracing::telemetry::TelemetryError;

pub fn main() {

    // Open the iRacing Telemetry data
    let conn = Connection::new().expect("Unable to open telemetry. Is iRacing running?");

    // Get a blocking telemetry client
    let bc = Connection::blocking().expect("Unable to start telemetry reader");

    loop {
        // bc.get() will block until new telemetry data is available.
        let sample = match bc.get() {
            Ok(sample) => sample,
            Err(TelemetryError::TIMEOUT(ms)) => panic!("Telemetry timed out after {}ms", ms);
            Err(error) => panic!("Telemetry Error: {:?}", error);
        }
    }
}

How iRacing Telemetry Works

iRacing provides very little documentation on how the telemetry data is exported, so here's my version of it.

iRacing exports telemetry to a non-persisted memory-mapped file.
This allows iRacing to provide telemetry data with a high update rate which can be read by multiple reading applications.

The shared memory space is always called Local\\IRSDKMemMapFileName.
This memory contains four main areas:

  • A top-level header which describes the content of the memory space including:

    • The data version (currently 2.0)
    • The update rate (usually 60Hz)
    • The game-tick when the data was last updated
    • Information needed to find and read the session information and telemetry.
  • An ISO-8859-1 encoded YAML string containing semi-static session information such as the name and layout of the track, the cars being driven and the users driving those cars.

  • A secondary header which describes the data available in the telemetry buffers

  • Up to 4 telemetry data buffers

The simulator cycles through up to 4 telemetry data buffers when writing telemetry and updates the top-level header to indicate when each buffer was last updated and where it is located. All buffers share the same structure, the number of values available is fixed per-session.

The session data can be read as a string given the location and size indicated by the top-level header and parsed as YAML to get the full details of the session. The structure of the YAML document is provided in the IRSDK documentation.

The telemetry data available is variable and depends primarily on the player's car. The top-level header denotes how many telemetry values are available and a pointer to the start of an array of structures which describe these contents. The structure is as follows:

typedef struct iracing_telem_var_header {
    int value_type /* Enum of value type */
    int offset /* Offset from start of telemetry buffer where variable is stored */
    int count /* A count of values for this variable */

    char [3]pad /* Padding */

    char [32]name /* Varaible name */
    char [64]desc /* Variable description */
    char [32]units /* Variable units */
}

If the top-level header indicates there are 548 variables, then the the variables header will be an array of 548 items (iracing_telem_var_header[548]). This header can then used as a look-up-table to find specific telemetry variables within the telemetry buffer.

For example, given the following variable header:

{
    .value_type = 1, /* float */
    .offset = 0x4F82,
    .count = 6,
    .pad = [0,0,0],
    .name = "DampDeflectLR",
    .desc = "Damper Deflection (Left-Rear)",
    .units = "mm"
};

We know that the variable "DampDeflectLR" exists 0x4F82 bytes from the start of the telemetry buffer, the values are floats, of 4-bytes each and there are 6 values.

Knowing this we will need to read 24 bytes starting 0x4F82 bytes from the start of the telemetry buffer to 0x4F93 which will give us an array of 6 floats

A C implementation would look like this:

float* suspension_deflect = (float*)calloc(6, sizeof(float));
size_t suspection_deflect_loc = 0x4F82;

memcpy(suspension_deflect, telem_buffer_start + suspension_deflect_loc, 6 * sizeof(float));

Dependencies

~5MB
~88K SLoC