Skip to content

Latest commit

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🏎️ Telemetry Lab

A high-performance, low-latency telemetry capture and analysis suite for sim racing games (Assetto Corsa, Assetto Corsa Competizione, iRacing, Le Mans Ultimate, etc.).

This project is built using a hybrid C/Rust architecture:

  • telemetry-fetcher (C11): A lightweight, low-level capture agent that maps game shared memory regions (Windows MMIO) at high frequencies (up to 360Hz) and writes them to disk in a highly packed, proprietary binary stream format (.rts).
  • telemetry-analyzer (Rust): A robust GUI-driven analysis application built using egui and eframe to parse .rts files in microseconds and plot driver inputs, speeds, GPS track maps, and suspension/tire behaviors for lap optimization.

📁 Repository Structure

telemetry-lab/
├── telemetry-fetcher/ # C capture utility
│ ├── include/
│ │ ├── adapters/ # Windows MMIO mappings for AC & iRacing
│ │ └── rts/ # Custom file writer & binary structures
│ ├── src/
│ │ ├── adapters/ # Game shared memory readers
│ │ ├── storage/ # File storage logic (.rts format)
│ │ └── main.c # Capture lifecycle and mock generation
│ ├── CMakeLists.txt
│ └── mingw-toolchain.cmake # Cross-compilation setup for Windows target
│
├── telemetry-analyzer/ # Rust GUI analysis application
│ ├── src/
│ │ ├── parser.rs # Zero-allocation .rts file parser
│ │ └── main.rs # egui desktop GUI & plotting pipeline
│ └── Cargo.toml
│
└── README.md # Main documentation

📑 RTS (Racing Telemetry Stream) Binary Specification

The .rts file extension represents a high-speed, zero-boilerplate telemetry stream. To achieve maximum throughput and minimal write latency, it writes packed binary representation directly from the CPU register states to disk, conforming to little-endian alignment.

Both the C writer (rts_writer.c) and Rust parser (parser.rs) align structures strictly to 1-byte boundary alignment:

  • C:#pragma pack(push, 1) / #pragma pack(pop)
  • Rust:#[repr(C, packed)] with bytemuck safe casts

Byte-Level File Layout

+------------------------------------------------------------+
| RTS HEADER |
| - Magic Signature (4 bytes) "RTS\0" |
| - Version (1 byte) |
| - Game ID (1 byte) |
| - Metadata Length N (2 bytes, uint16_t) |
+------------------------------------------------------------+
| METADATA PAYLOAD |
| - UTF-8 JSON String (N bytes) |
+------------------------------------------------------------+
| TELEMETRY FRAMES STREAM |
| - Frame 1 (77 bytes, packed telemetry struct) |
| - Frame 2 (77 bytes, packed telemetry struct) |
| - ... |
| - Frame M (77 bytes, packed telemetry struct) |
+------------------------------------------------------------+

1. RTS File Header Layout (Variable Length)

The header starts with an 8-byte fixed block, followed immediately by a variable-length metadata string payload.

Offset (Bytes)TypeField NameDescription
0x00 - 0x03char[4]magicMagic signature bytes: 'R', 'T', 'S', '\0'
0x04uint8_tversionFile structure version (currently 1)
0x05uint8_tgame_idGame enum code (0=Unknown, 1=Assetto Corsa, 2=ACC, 3=iRacing, 4=LMU)
0x06 - 0x07uint16_tmetadata_lengthLength N of the following metadata payload string (Max 65,535 bytes)
0x08 - (8+N-1)char[N]metadataUTF-8 encoded JSON metadata string (e.g., track name, car, driver)

2. Standardized Telemetry Frame Layout (77 Bytes Fixed)

Every telemetry sample is recorded as a single contiguous, packed block of exactly 77 bytes. To avoid alignment paddings, 1-byte packing is strictly enforced.

Offset (Bytes)Field OffsetTypeField NameUnits / ScaleDescription
00x00uint32_tsession_time_msmsTime elapsed since session start
40x04floatthrottle[0.0, 1.0]Driver throttle position (0% to 100%)
80x08floatbrake[0.0, 1.0]Driver brake pressure/position (0% to 100%)
120x0Cfloatclutch[0.0, 1.0]Driver clutch position (0% to 100%)
160x10floatsteering[-1.0, 1.0]Steering angle: negative=left, positive=right
200x14floatspeed_msm/sAbsolute vehicle speed in meters per second
240x18floatengine_rpmrpmCurrent engine RPM
280x1Cint8_tgearinteger-1=Reverse, 0=Neutral, 1+=Forward Gears
290x1Dfloatpos_xmeters3D World X coordinates (GPS translation)
330x21floatpos_ymeters3D World Y coordinates (Altitude)
370x25floatpos_zmeters3D World Z coordinates (GPS translation)
410x29floatlap_distancemetersDistance traveled from the starting line
450x2Dfloat[4]suspension_travelmetersSusp. travel array: [FL, FR, RL, RR]
610x3Dfloat[4]tire_temp_c°CCore tire temperatures: [FL, FR, RL, RR]
770x4Dfloat[4]tire_pressure_kpakPaTires inflation pressures: [FL, FR, RL, RR]

🛠️ Build and Compilation Instructions

1. Compiling the C Telemetry Fetcher

Since sim racing games are predominantly Windows-only, the telemetry-fetcher uses Windows shared memory APIs. However, it can be built/cross-compiled on Linux using the MinGW compiler toolchain.

To Cross-Compile for Windows on Linux: Ensure you have mingw-w64 packages installed on your system.

cd telemetry-fetcher
mkdir build &&cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../mingw-toolchain.cmake ..
make

This produces fetcher.exe in the build directory, ready to run on any sim racing rig.


2. Compiling and Running the Rust Analyzer

The analyzer can run natively on both Linux and Windows systems.

Prerequisites: You will need Rust installed on your computer.

cd telemetry-analyzer
cargo run --release
  • Click "Open File..." in the GUI to load any .rts binary file (e.g. the standard dummy_telemetry.rts generated by the fetcher).
  • Interact with the speed graphs, throttle/brake maps, tires thermal state plots, and top-down visual GPS track maps.

About

A high-performance, low-latency telemetry capture and analysis suite for sim racing games.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages