/
telemetry_client.py
119 lines (116 loc) · 3.62 KB
/
telemetry_client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import ctypes
import socket
import ac
class TelemetryStructure(ctypes.Structure):
def to_bytes(self):
return (ctypes.c_char*ctypes.sizeof(self)).from_buffer_copy(self)
def from_bytes(self,bytes):
fit = min(len(bytes),ctypes.sizeof(self))
ctypes.memmove(ctypes.addressof(self),bytes,fit)
class Handshaker(TelemetryStructure):
_fields_ = [
('identifier',ctypes.c_int),
('version',ctypes.c_int),
('operationId',ctypes.c_int),
]
class HandshakerResponse(TelemetryStructure):
_fields_ = [
('carName',ctypes.c_char*50),
('driverName',ctypes.c_char*50),
('identifier',ctypes.c_int),
('version',ctypes.c_int),
('trackName',ctypes.c_char*50),
('trackConfig',ctypes.c_char*50),
]
class RTCarInfo(TelemetryStructure):
_fields_ = [
('identifier',ctypes.c_char),
('size',ctypes.c_int),
('speed_Kmh',ctypes.c_float),
('speed_Mph',ctypes.c_float),
('speed_Ms',ctypes.c_float),
('isAbsEnabled',ctypes.c_bool),
('isAbsInAction',ctypes.c_bool),
('isTcInAction',ctypes.c_bool),
('isTcEnabled',ctypes.c_bool),
('isInPit',ctypes.c_bool),
('isEngineLimiterOn',ctypes.c_bool),
('accG_vertical',ctypes.c_float),
('accG_horizontal',ctypes.c_float),
('accG_frontal',ctypes.c_float),
('lapTime',ctypes.c_int),
('lastLap',ctypes.c_int),
('bestLap',ctypes.c_int),
('lapCount',ctypes.c_int),
('gas',ctypes.c_float),
('brake',ctypes.c_float),
('clutch',ctypes.c_float),
('engineRPM',ctypes.c_float),
('steer',ctypes.c_float),
('gear',ctypes.c_int),
('cgHeight',ctypes.c_float),
('wheelAngularSpeed',ctypes.c_float*4),
('slipAngle',ctypes.c_float*4),
('slipAngle_ContactPatch',ctypes.c_float*4),
('slipRatio',ctypes.c_float*4),
('tyreSlip',ctypes.c_float*4),
('ndSlip',ctypes.c_float*4),
('load',ctypes.c_float*4),
('Dy',ctypes.c_float*4),
('Mz',ctypes.c_float*4),
('tyreDirtyLevel',ctypes.c_float*4),
('camberRAD',ctypes.c_float*4),
('tyreRadius',ctypes.c_float*4),
('tyreLoadedRadius',ctypes.c_float*4),
('suspensionHeight',ctypes.c_float*4),
('carPositionNormalized',ctypes.c_float),
('carSlope',ctypes.c_float),
('carCoordinates',ctypes.c_float*3)
]
class InternalTelemetryClient:
def __init__(self):
# Properties are the relevant fields from the received data
self.abs_enabled = False
self.abs_in_action = False
self.tc_enabled = False
self.tc_in_action = False
self.in_pit = False
self.limiter = False
self.sock = None
self.address = ('127.0.0.1',9996)
self.handshake_done = False
self.connected = False
def connect(self):
self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
handshake_data = Handshaker(4,1,0)
ctypes.string_at(ctypes.addressof(handshake_data),ctypes.sizeof(handshake_data))
self.sock.sendto(handshake_data,self.address)
ac.log("Sent :-)")
self.connected = True
def tick(self):
return #FIXME
ac.log("Ticking")
if not self.connected:
return
ac.log("Getting data")
data = self.sock.recvfrom(max(ctypes.sizeof(HandshakerResponse),ctypes.sizeof(RTCarInfo)))[0]
if not self.handshake_done:
ac.log("Sending handshake")
handshake = Handshaker(4,1,1)
self.sock.sendto(handshake.to_bytes(),self.address)
self.handshake_done = True
else:
ac.log("Getting raw data")
raw_data = RTCarInfo()
raw_data.from_bytes(data)
self.abs_enabled = raw_data.isAbsEnabled
self.abs_in_action = raw_data.isAbsInAction
self.tc_enabled = raw_data.isTcEnabled
self.tc_in_action = raw_data.isTcInAction
self.in_pit = raw_data.isInPit
self.limiter = raw_data.isEngineLimiterOn
def disconnect(self):
data = Handshaker(4,1,3)
self.sock.sendto(data.to_bytes(),self.address)
self.handshake_done = False
self.connected = False