• Welcome to PiBoSo Official Forum. Please login or sign up.
 
August 26, 2025, 04:33:37 AM

News:

GP Bikes beta21c available! :)


Python Proxy Plugin

Started by gaga_dreher, August 02, 2024, 11:56:35 AM

Previous topic - Next topic

gaga_dreher

# Python Alternative to C/C++ for GP Bikes Data Reading

This script is a friendly option for those who are not fluent in C/C++. It allows you to read and display GP Bikes data using Python. Below, you'll find instructions on required libraries, installation, and how the code works.

## Required Libraries

This script uses libraries that are part of Python's standard library, so no additional installations are needed:
- ctypes
- time
- os

To install Python, you can download it from https://www.python.org/downloads/.

## Installation Instructions

1. Install Python:
   Download and install Python from the official website (https://www.python.org/downloads/).

2. Save the script:
   Save the provided script as `gpbikes_data_reader.py`.

## How the Code Works

This Python script reads data from a shared memory object created by the GP Bikes simulator and prints the data in a user-friendly format. The script repeatedly updates the output every second, showing real-time information. You can change the update rate; the maximum output is 50 Hz.

### Key Sections of the Script

1. **Import Libraries**:
   The script starts by importing necessary libraries: `ctypes`, `time`, and `os`.

2. **Define Data Structures**:
   The script defines several data structures using Python's `ctypes` to match the data layout expected from the GP Bikes shared memory.

3. **Windows API Functions**:
   The script uses Windows API functions to access the shared memory object.

4. **Constants and File Mapping**:
   The script defines constants and opens the file mapping object created by GP Bikes.

5. **Map View of File**:
   The script maps a view of the file into the address space of the current process.

6. **Clear Console Function**:
   A helper function `clear_console` is defined to clear the console screen before updating the data display.

7. **Main Loop**:
   The main loop of the script continuously reads data from the shared memory and prints it to the console. The output includes rider name, bike ID, bike name, category, track ID, track name, track length, number of gears, max RPM, limiter, shift RPM, engine optimal temperature, engine temperature alarm, max fuel, suspension max travel, steer lock, type, current lap time, and RPM.

8. **Clean Up**:
   The script includes a `finally` block to unmap the view of the file and close the file handle, ensuring proper cleanup.

### Configuring the Sample Rate

To change the sample rate of the data output, create a file called `proxy.ini` in the "plugins" folder where GP Bikes is installed. Add the following lines to the file:

[params]
sample_rate = 50

The default sample rate is 10 Hz. For more information, refer to the forum post: https://forum.piboso.com/index.php?topic=34.15.

### Running the Script

1. Open a terminal or command prompt.
2. Navigate to the directory where you saved `gpbikes_data_reader.py`.
3. Run the script using Python:
python gpbikes_data_reader.py
or
py gpbikes_data_reader.py

The script will start displaying GP Bikes data in the console, updating every second (or at the configured sample rate).

## Notes

- Ensure that GP Bikes is running and the shared memory object is available.
- This script is designed to run on Windows as it uses Windows API functions.

I hope this Python alternative makes it easier for you to work with GP Bikes data. If you have any questions or need further assistance, feel free to ask in the forum.

Code:

import ctypes
from ctypes import wintypes
import time
import os

# Define the data structures
class SPluginsBikeEvent_t(ctypes.Structure):
    _fields_ = [
        ("m_szRiderName", ctypes.c_char * 100),
        ("m_szBikeID", ctypes.c_char * 100),
        ("m_szBikeName", ctypes.c_char * 100),
        ("m_iNumberOfGears", ctypes.c_int),
        ("m_iMaxRPM", ctypes.c_int),
        ("m_iLimiter", ctypes.c_int),
        ("m_iShiftRPM", ctypes.c_int),
        ("m_fEngineOptTemperature", ctypes.c_float),
        ("m_afEngineTemperatureAlarm", ctypes.c_float * 2),
        ("m_fMaxFuel", ctypes.c_float),
        ("m_afSuspMaxTravel", ctypes.c_float * 2),
        ("m_fSteerLock", ctypes.c_float),
        ("m_szCategory", ctypes.c_char * 100),
        ("m_szTrackID", ctypes.c_char * 100),
        ("m_szTrackName", ctypes.c_char * 100),
        ("m_fTrackLength", ctypes.c_float),
        ("m_iType", ctypes.c_int),
    ]

class SPluginsBikeSession_t(ctypes.Structure):
    _fields_ = [
        ("m_iSession", ctypes.c_int),
        ("m_iConditions", ctypes.c_int),
        ("m_fAirTemperature", ctypes.c_float),
        ("m_fTrackTemperature", ctypes.c_float),
        ("m_szSetupFileName", ctypes.c_char * 100),
    ]

class SPluginsBikeData_t(ctypes.Structure):
    _fields_ = [
        ("m_iRPM", ctypes.c_int),
        ("m_fEngineTemperature", ctypes.c_float),
        ("m_fWaterTemperature", ctypes.c_float),
        ("m_iGear", ctypes.c_int),
        ("m_fFuel", ctypes.c_float),
        ("m_fSpeedometer", ctypes.c_float),
        ("m_fPosX", ctypes.c_float), ("m_fPosY", ctypes.c_float), ("m_fPosZ", ctypes.c_float),
        ("m_fVelocityX", ctypes.c_float), ("m_fVelocityY", ctypes.c_float), ("m_fVelocityZ", ctypes.c_float),
        ("m_fAccelerationX", ctypes.c_float), ("m_fAccelerationY", ctypes.c_float), ("m_fAccelerationZ", ctypes.c_float),
        ("m_aafRot", (ctypes.c_float * 3) * 3),
        ("m_fYaw", ctypes.c_float), ("m_fPitch", ctypes.c_float), ("m_fRoll", ctypes.c_float),
        ("m_fYawVelocity", ctypes.c_float), ("m_fPitchVelocity", ctypes.c_float), ("m_fRollVelocity", ctypes.c_float),
        ("m_fPitchRel", ctypes.c_float), ("m_fRollRel", ctypes.c_float),
        ("m_afSuspLength", ctypes.c_float * 2),
        ("m_afSuspVelocity", ctypes.c_float * 2),
        ("m_iCrashed", ctypes.c_int),
        ("m_fSteer", ctypes.c_float),
        ("m_fInputThrottle", ctypes.c_float),
        ("m_fThrottle", ctypes.c_float),
        ("m_fFrontBrake", ctypes.c_float),
        ("m_fRearBrake", ctypes.c_float),
        ("m_fClutch", ctypes.c_float),
        ("m_afWheelSpeed", ctypes.c_float * 2),
        ("m_aiWheelMaterial", ctypes.c_int * 2),
        ("m_aafTreadTemperature", (ctypes.c_float * 3) * 2),
        ("m_afBrakePressure", ctypes.c_float * 2),
        ("m_fSteerTorque", ctypes.c_float),
        ("m_iPitLimiter", ctypes.c_int),
        ("m_iECUMode", ctypes.c_int),
        ("m_szEngineMapping", ctypes.c_char * 3),
        ("m_iTractionControl", ctypes.c_int),
        ("m_iEngineBraking", ctypes.c_int),
        ("m_iAntiWheeling", ctypes.c_int),
        ("m_iECUState", ctypes.c_int),
        ("m_fRiderLRLean", ctypes.c_float),
    ]

class SPluginsBikeLap_t(ctypes.Structure):
    _fields_ = [
        ("m_iLapNum", ctypes.c_int),
        ("m_iInvalid", ctypes.c_int),
        ("m_iLapTime", ctypes.c_int),
        ("m_iBest", ctypes.c_int),
    ]

class SPluginsBikeSplit_t(ctypes.Structure):
    _fields_ = [
        ("m_iSplit", ctypes.c_int),
        ("m_iSplitTime", ctypes.c_int),
        ("m_iBestDiff", ctypes.c_int),
    ]

class SProxyData_t(ctypes.Structure):
    _fields_ = [
        ("m_iVersion", ctypes.c_int),
        ("m_iState", ctypes.c_int),
        ("m_sEvent", SPluginsBikeEvent_t),
        ("m_sSession", SPluginsBikeSession_t),
        ("m_sLap", SPluginsBikeLap_t),
        ("m_iSplit", ctypes.c_int),
        ("m_sSplit", SPluginsBikeSplit_t),
        ("m_sData", SPluginsBikeData_t),
        ("m_fTime", ctypes.c_float),
        ("m_fPos", ctypes.c_float),
        ("m_fCurLapTime", ctypes.c_float),
    ]

# Windows API functions
OpenFileMapping = ctypes.windll.kernel32.OpenFileMappingW
OpenFileMapping.restype = wintypes.HANDLE
OpenFileMapping.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.LPCWSTR]

MapViewOfFile = ctypes.windll.kernel32.MapViewOfFile
MapViewOfFile.restype = wintypes.LPVOID
MapViewOfFile.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.DWORD, wintypes.DWORD, ctypes.c_size_t]

UnmapViewOfFile = ctypes.windll.kernel32.UnmapViewOfFile
UnmapViewOfFile.restype = wintypes.BOOL
UnmapViewOfFile.argtypes = [wintypes.LPCVOID]

CloseHandle = ctypes.windll.kernel32.CloseHandle
CloseHandle.restype = wintypes.BOOL
CloseHandle.argtypes = [wintypes.HANDLE]

# Constants
FILE_MAP_READ = 0x0004
szName = "Local\\GPBProxyObject"

# Open the file mapping object.
hMapFile = OpenFileMapping(FILE_MAP_READ, False, szName)
if not hMapFile:
    print("Could not open file mapping object ({})".format(ctypes.GetLastError()))
    exit(1)

# Map a view of the file mapping into the address space of the current process.
pData = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, ctypes.sizeof(SProxyData_t))
if not pData:
    print("Could not map view of file ({})".format(ctypes.GetLastError()))
    CloseHandle(hMapFile)
    exit(1)

# Cast the pointer to our structure type
pProxyData = ctypes.cast(pData, ctypes.POINTER(SProxyData_t))

def clear_console():
    os.system('cls' if os.name == 'nt' else 'clear')

try:
    while True:
        clear_console()
        print("Rider Name:", pProxyData.contents.m_sEvent.m_szRiderName.decode())
        print("Bike ID:", pProxyData.contents.m_sEvent.m_szBikeID.decode())
        print("RPM:", pProxyData.contents.m_sData.m_iRPM)

        # Add other fields as needed...

        time.sleep(1)

finally:
    # Clean up
    UnmapViewOfFile(pData)
    CloseHandle(hMapFile)