Skip to content

Commit

Permalink
moved files from hid-fanatecff
Browse files Browse the repository at this point in the history
  • Loading branch information
gotzl committed Sep 21, 2020
0 parents commit 4c74b19
Show file tree
Hide file tree
Showing 10 changed files with 638 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
install:
cp dbus/org.fanatec.CSLElite.conf /etc/dbus-1/system.d/
cp dbus/org.fanatec.CSLElite.service /usr/share/dbus-1/system-services/
cp dbus/fanatec-input.py /usr/bin/
# cp org.fanatec.policy /usr/share/polkit-1/actions/

uninstall:
rm /etc/dbus-1/system.d/org.fanatec.CSLElite.conf
rm /usr/share/dbus-1/system-services/org.fanatec.CSLElite.service
rm /usr/bin/fanatec-input.py
# rm /usr/share/polkit-1/actions/org.fanatec.policy
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dbus interface and tools to communicate with the LEDs and display exposed by the [hid-fanatecff](https://github.com/gotzl/hid-fanatecff) driver.
97 changes: 97 additions & 0 deletions dbus/fanatec-input.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/python

from pydbus.generic import signal
import glob

def get_sysfs_base(PID):
return glob.glob("/sys/module/hid_ftec/drivers/hid:ftec_csl_elite/0003:0EB7:%s.*"%(PID))[0]

class CSLElite(object):
"""
<node>
</node>
"""
def __init__(self):
pass


class CSLElitePedals(object):
"""
<node>
<interface name='org.fanatec.CSLElite.Pedals'>
<property name="Load" type="i" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
</interface>
</node>
"""

def __init__(self):
pass

def get_sysfs(self, name):
return "%s/%s"%(get_sysfs_base('6204'), name)

@property
def Load(self):
return int(open(self.get_sysfs('load'),'r').read())

@Load.setter
def Load(self, value):
return int(open(self.get_sysfs('load'),'w').write(str(value)))

PropertiesChanged = signal()


class CSLEliteWheel(object):
"""
<node>
<interface name='org.fanatec.CSLElite.Wheel'>
<property name="Display" type="i" access="write">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="RPM" type="ab" access="write">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
</interface>
</node>
"""

def __init__(self):
pass

def get_sysfs(self, name):
return "%s/%s"%(get_sysfs_base('0005'), name)

def get_sysfs_rpm(self):
sysfs_base = get_sysfs_base('0005')
return "%s/leds/0003:0EB7:0005.%s::RPM"%(sysfs_base,sysfs_base.split(".")[-1])

@Display.setter
def Display(self, value):
return int(open(self.get_sysfs('display'),'w').write(str(value)))

@RPM.setter
def RPM(self, values):
return list(map(lambda i: open('%s%i/brightness'%(self.get_sysfs_rpm(), i[0] + 1),'w').write('1' if i[1] else '0'), enumerate(values)))

PropertiesChanged = signal()


if __name__ == "__main__":
from pydbus import SystemBus
from gi.repository import GLib

bus = SystemBus()
r = bus.publish('org.fanatec.CSLElite', CSLElite(),
('Pedals', CSLElitePedals()),
('Wheel', CSLEliteWheel()))
try:
loop = GLib.MainLoop()
loop.run()
except (KeyboardInterrupt, SystemExit):
print("Exiting")
except Exception as e:
raise e
finally:
r.unpublish()
21 changes: 21 additions & 0 deletions dbus/org.fanatec.CSLElite.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>

<policy context="default">
<!-- Allow everyone to talk to main service -->
<allow send_destination="org.fanatec.CSLElite"/>
<allow send_destination="org.fanatec.CSLElite.Pedals"/>
<allow send_destination="org.fanatec.CSLElite.Wheel"/>
</policy>

<policy user="root">
<!-- Allow root to own the name on the bus -->
<allow own="org.fanatec.CSLElite"/>
<allow own="org.fanatec.CSLElite.Pedals"/>
<allow own="org.fanatec.CSLElite.Wheel"/>
</policy>
</busconfig>


3 changes: 3 additions & 0 deletions dbus/org.fanatec.CSLElite.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[D-Bus Service]
Name=org.fanatec.CSLElite
Exec=/usr/bin/fanatec-input.py
82 changes: 82 additions & 0 deletions tools/ac.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import socket
import struct
import select
import threading

class AcClient(threading.Thread):
UDP_IP = "127.0.0.1"
UDP_PORT = 9996

HANDSHAKE = 0
SUBSCRIBE_UPDATE = 1
SUBSCRIBE_SPOT = 2
DISMISS = 3

def __init__(self, ev):
threading.Thread.__init__(self)
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setblocking(0)
self.ev = ev

@staticmethod
def client_data(sock, operation):
sock.sendto(bytearray([
0x0,0x0,0x0,0x2, # android phone
0x0,0x0,0x0,0x0, # version
operation,0x0,0x0,0x0,
]), (AcClient.UDP_IP, AcClient.UDP_PORT))

def run(self):
import fanatec_led_server
while not self.ev.isSet():
# handshake
AcClient.client_data(self.sock, AcClient.HANDSHAKE)

# response
ready = select.select([self.sock], [], [], 2)
if not ready[0]:
# print("Timeout connecting to AC server")
continue
data, addr = self.sock.recvfrom(2048)

# confirm
AcClient.client_data(self.sock, AcClient.SUBSCRIBE_UPDATE)

timeout_cnt = 0
while not self.ev.isSet():
ready = select.select([self.sock], [], [], .5)
if not ready[0]:
print('Timeout waiting for AC server data,', timeout_cnt)
timeout_cnt+=1
if timeout_cnt>10:
print('Quitting AC server')
break
continue

timeout_cnt = 0
data, addr = self.sock.recvfrom(2048)
speed_kmh = int(struct.unpack('<f', data[8:12])[0])
rpm = int(struct.unpack('<f', data[68:72])[0])
gear = int.from_bytes(data[76:80], byteorder='little')

fanatec_led_server.set_leds([False if rpm<i*1000 else True for i in range(9)])
fanatec_led_server.set_display(speed_kmh)
# print(speed_kmh, rpm, gear)

AcClient.client_data(self.sock, AcClient.DISMISS)
fanatec_led_server.clear()
self.sock.setblocking(1)

if __name__ == "__main__":
try:
ev = threading.Event()
ac = AcClient(ev)
ac.start()
ac.join()

except (KeyboardInterrupt, SystemExit):
print("Exiting")
except Exception as e:
raise e
finally:
ev.set()
53 changes: 53 additions & 0 deletions tools/f1_2020.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import socket
import threading
import time


class F12020Client(threading.Thread):
UDP_IP = "127.0.0.1"
UDP_PORT = 20777

def __init__(self, ev):
threading.Thread.__init__(self)
self.sock = sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind((F12020Client.UDP_IP, F12020Client.UDP_PORT))
self.sock.setblocking(0)
self.ev = ev

def run(self):
import fanatec_led_server
while not self.ev.isSet():
try:
data, addr = self.sock.recvfrom(2048)
pkt_id = data[5]
# only use telemetry packets
if pkt_id != 6: continue
car_idx = data[22]

# start car delemetry data byte 24
# size of car delemetry data 58
car_telem_start = 24 + car_idx*58
speed = int.from_bytes(data[car_telem_start:car_telem_start+2], byteorder="little")
gear = int(data[car_telem_start+15])
rpm = int.from_bytes(data[car_telem_start+16:car_telem_start+18], byteorder="little")
suggestedGear = int(data[-1])

fanatec_led_server.set_leds([False if (rpm-5000)<i*1000 else True for i in range(9)])
fanatec_led_server.set_display(speed)
# print(speed, rpm, gear)
except:
time.sleep(.5)

if __name__ == "__main__":
try:
ev = threading.Event()
f1 = F12020Client(ev)
f1.start()
f1.join()

except (KeyboardInterrupt, SystemExit):
print("Exiting")
except Exception as e:
raise e
finally:
ev.set()
49 changes: 49 additions & 0 deletions tools/fanatec_led_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/python3
import glob
from pydbus import SystemBus

bus = SystemBus()
wheel = bus.get('org.fanatec.CSLElite', '/org/fanatec/CSLElite/Wheel')

def set_leds(values):
global wheel
wheel.RPM = values

def set_display(value):
global wheel
wheel.Display = value

# clear leds and display
def clear():
set_leds([False]*9)
set_display(-1)


if __name__ == "__main__":
import threading
from ac import AcClient
from f1_2020 import F12020Client

try:
ev = threading.Event()
# start f1 server
f1 = F12020Client(ev)
f1.start()

# start ac client
ac = AcClient(ev)
ac.start()

# run as long as the client threads are running, or CTRL+C
print("Running ...")
f1.join()
ac.join()

except (KeyboardInterrupt, SystemExit):
print("Exiting")
except Exception as e:
raise e
finally:
ev.set()
clear()

Loading

0 comments on commit 4c74b19

Please sign in to comment.