Telemetry UDP - example

formula1996

Registered
I would like to send speed, rpm, gear data through UDP. But i don't well in programming. Can anybody send me a basic plugin example how to send data on UDP or help me? It would be great :)
 
Hmm. I tried this approach and been really diappointed by winsockets2. Data went slow and sometimes been lost so my display flickered.
If you plan to use it on the same machine, use mapped files instead, they should work better imo (i didn't try it yet though, gonna do in next week or two).
 
Sending data via UDP works just fine for me, and if you're looking for an example you can check out: https://bitbucket.org/marrs/rfactor...542bc469607b9bd9/cpp/DataPlugin_v2/?at=master

This is a plugin that sends all kinds of telemetry data and can easily be customized. For my application (endurance racing software) I am receiving that data in Java (example: https://bitbucket.org/marrs/rfactor...scoring/v2/impl/PluginListener.java?at=master) and using it mainly to do my own scoring in a practice session, but I have used the same code to display telemetry data as well so it's a good starting point.
 
Sorry :)

But I felt so bad when I could not know how to down load the two folders DataPlugin & DataPlugin_v2.
Do I need to edit them and copy the contents? I can not find the download link from that site
 
You should have not given up that easily :) Go to Downloads tab, then Branches. I used Marrs code and works wonderfully.
 
Thank you B1K3R, I could get it,

I compiled the both projects and copied .dll file to the plugin directory and started listing to 127.0.0.1 port 6789 but i did not get any data
I am using rFactor 1 and C# while my firewall is tuned off, is there anything special thing I need to do to start receiving the data?
even there was not a popup screen showing any data, any suggestion?
 
Ye, like noel said, it depends what code your doing to receive data. I will post some c# code but won't be home any time soon.

Sent from my GT-I9300 using Tapatalk

Edit: Here's some code based on Marrs example. These are code extracts so that you get an idea.

public void StartUdpListener(object process) {
List<BinaryReader> m_buffers = new List<BinaryReader>();


IPEndPoint remoteSender = new IPEndPoint(IPAddress.Any, 0);


// Create UDP client
UdpClient updClient = new UdpClient(process.pluginPort);


UdpState state = new UdpState(updClient, remoteSender, process.sessionID, m_buffers);
// Start async receiving
updClient.BeginReceive(new AsyncCallback(DataReceived), state);
}

private void DataReceived(IAsyncResult ar)
{
List<BinaryReader> m_buffers = (List<BinaryReader>)((UdpState)ar.AsyncState).m_buffers;
UdpClient c = (UdpClient)((UdpState)ar.AsyncState).c;


IPEndPoint wantedIpEndPoint = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);


Byte[] receiveBytes = c.EndReceive(ar, ref receivedIpEndPoint);
HandleData(receiveBytes, m_buffers);


// Restart listening for udp data packages
c.BeginReceive(new AsyncCallback(DataReceived), ar.AsyncState);
}


public void HandleData(byte[] receiveBytes, List<BinaryReader> m_buffers)
{
MemoryStream stream = new MemoryStream(receiveBytes, 0, receiveBytes.Length, true);
BinaryReader reader = new BinaryReader(stream);


stream.Position = 0; // Rewind so stream can be read again


byte protocolVersion = reader.ReadByte();
byte packet = reader.ReadByte();
short sequence = reader.ReadInt16();


if (packet == 0 && m_buffers.Count != 0)
{
MemoryStream streamDest = new MemoryStream(m_buffers.Count * 512);
BinaryWriter dest = new BinaryWriter(streamDest);


byte[] tmp = new byte[512 - 4];
BinaryReader b = m_buffers.FirstOrDefault();
m_buffers.Remove(b);


while (b != null)
{
int remaining = (int)(b.BaseStream.Length - b.BaseStream.Position);
b.Read(tmp, 0, remaining);
dest.Write(tmp, 0, remaining);
b = m_buffers.FirstOrDefault();
m_buffers.Remove(b);
}


// Rewind so stream can be read again
streamDest.Position = 0;


try
{
ProcessDataStream(streamDest);
}
catch (Exception e)
{
this.Invoke((MethodInvoker)delegate
{
txtLog.Text = txtLog.Text + "Error: " + e.Message + Environment.NewLine;
});
}


// clear the queue
m_buffers.Clear();
}


// add to the queue
m_buffers.Add(reader);
}

private void ProcessDataStream(MemoryStream streamDest)
{
string currentLapNo = "0";


using (BinaryReader dest = new BinaryReader(streamDest))
{
short type = dest.ReadInt16();


//update score
if (type == 2)
{
string pluginSessionID = getString(dest, 16);
string sessionName = getString(dest, 512);


Boolean startSession = dest.ReadBoolean();
Boolean enterRealtime = dest.ReadBoolean();
Boolean exitRealtime = dest.ReadBoolean();


string trackName = getString(dest, 64);
uint session = dest.ReadUInt32();
double eventTime = dest.ReadDouble();
double endEventTime = dest.ReadDouble();
double trackLapDistance = dest.ReadDouble();
uint maxLaps = dest.ReadUInt32();
uint numberOfVehicles = dest.ReadUInt32();


byte gamePhase = dest.ReadByte();
byte yellowFlagState = dest.ReadByte();
byte[] sectorFlags = new byte[3];
sectorFlags[0] = dest.ReadByte();
sectorFlags[1] = dest.ReadByte();
sectorFlags[2] = dest.ReadByte();
byte startLight = dest.ReadByte();
byte numRedLights = dest.ReadByte();


double darkCloud = dest.ReadDouble();
double raining = dest.ReadDouble();
double ambientTemp = dest.ReadDouble();
double trackTemp = dest.ReadDouble();
double windx = dest.ReadDouble();
double windy = dest.ReadDouble();
double windz = dest.ReadDouble();
double onPathWetness = dest.ReadDouble();
double offPathWetness = dest.ReadDouble();


//
// Get Weather data
//
// TODO Values currently set to 0 until the weatherdata can be read from the plugin
//float darkCloud = 0f;
//float raining = 0f;
//float ambientTemp = 0f;
//float windX = 0f;
//float windY = 0f;
//float windZ = 0f;
//float onPathWetness = 0f;
//float offPathWetness = 0f;


//WeatherData weatherData = new WeatherData(darkCloud, raining, ambientTemp, windX, windY, windZ, onPathWetness, offPathWetness);
// End weather data


for (int i = 0; i < numberOfVehicles; i++)
{
uint recordID = dest.ReadUInt32();
uint mID = dest.ReadUInt32();
double xPosition = dest.ReadDouble();
double zPosition = dest.ReadDouble();
byte place = dest.ReadByte();
double lapDistance = dest.ReadDouble();
double pathLateral = dest.ReadDouble();
double speed = dest.ReadDouble();
string vehicleName = getString(dest, 64);
string driverName = getString(dest, 32);
string vehicleClass = getString(dest, 32);
short totalLaps = dest.ReadInt16();
double bestSector1 = dest.ReadDouble();
double bestSector2 = dest.ReadDouble();
double bestLapTime = dest.ReadDouble();
double lastSector1 = dest.ReadDouble();
double lastSector2 = dest.ReadDouble();
double lastLapTime = dest.ReadDouble();
double currentSector1 = dest.ReadDouble();
double currentSector2 = dest.ReadDouble();
double timeBehindLeader = dest.ReadDouble();
uint lapsBehindLeader = dest.ReadUInt32();
double timeBehindNext = dest.ReadDouble();
uint lapsBehindNext = dest.ReadUInt32();
short numberOfPitstops = dest.ReadInt16();
short numberOfPenalties = dest.ReadInt16();
Boolean inPits = dest.ReadBoolean();
byte sector = dest.ReadByte();
byte finishStatus = dest.ReadByte();
}
}
}
}
 
Last edited by a moderator:
Thank you guys,

I could test that in rFactor2 and I could detect the data, but in rFactor1 I could not.
I am using simple C# code that I already used for listening to UDP ports.

UdpClient listener = new UdpClient(6789);
IPEndPoint groupEP = new IPEndPoint(127001, 6789);

private void listen()
{

if (listener.Available > 0)
{
MessageBox.Show("There is data");
byte[] vals = listener.Receive(ref groupEP);
}
}

private void timer1_Tick(object sender, EventArgs e)
{
listen();
}
is DataPlugin_v2 project is for rFactor2 and DataPlugin project is for rFactor1?
I only want it to work in rFactor1 since rFactor 2 is a demo version at me.
 
Thank you B1K3R for the code,

I want to use this data to build a hardware simulator and send them to com port later. I could see that data such as the orientation matrix, pitch, roll..etc are not available in the telemetry, so I will try to do some modification to get them on both projects.
 
When I launch the game it freezes :/
sad.sin_addr.S_un.S_addr = *((ULONG*)&(((sockaddr_in*)pResult->ai_addr)->sin_addr));
This line cause the crash anybody can help why?
 
Last edited by a moderator:
I have created a Wind Simulator that works on other SimRacing games.
I want to make it compatible with RF2.

I am trying to fetch telemetry variables such as speed, rpm, gear, etc. using a Python script.

I downloaded the DataPlugin_V2.dll and added it to the game Bin folders.
When I open the in-game options, I do not see this plugin available (all other plugins appear)

Here is a piece of my Python code:

Code:
import struct
import socket

# Configure listener IP & Port for UDP transmission of packed values
udp_ip = "127.0.0.1"
udp_port = 6789
unpacked_data = None
data = None

def checkStatus():
    global data, udp_ip, udp_port
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # UDP
    #sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    sock.bind((udp_ip, udp_port))
    sock.settimeout(1/30)

    try:
        data, addr = sock.recvfrom(1024)  # receiving from socket
        sock.close()
        return data
    except:
        return False

def receiveData():
    global unpacked_data, data
    fmt = '<' + '70' + 'f'                                 # define structure of packed data
    s = struct.Struct(fmt)                                  # declare structure

    #rx_data = net_rx(udp_ip, udp_port)
    #unpacked_data = s.unpack(data)                  #  unpack data into tuple, requires correct 'fmt'
    unpacked_data = struct.unpack('64f', data[0:256])
    return True


def getChannel(channel):
    global unpacked_data
    if channel == 'rpm':
        return str(int(unpacked_data[37]))
    elif channel == 'max_rpm':
        return str(int(unpacked_data[63]))
    elif channel == 'gear':
        return str(int(unpacked_data[33])-1)
    elif channel == 'speed':
        return str(int(unpacked_data[7]*0.6214))
    elif channel == 'track_loc':
        return '-1'
    elif channel == 'car_name':
        return '-1'
    else:
        return 0

For more information about the Wind Simulator, you can visit our website at: https://www.simracingstudio.com/

Thanks,
Phil.
 
Back
Top