pyiforce/pyiforce.py

161 lines
3.5 KiB
Python
Raw Normal View History

2020-10-30 02:00:14 +01:00
_rx_stream = None
_pkt_handlers = {}
class Packet:
SOP = 0x2B
MAX_LENGTH = 255 # TBD
INPUT_JOYSTICK = 0x01
INPUT_WHEEL = 0x03
EFFECT_STATES = 0x02
SET_CONTROL = 0x40
CONTROL = 0x41
2020-10-31 00:47:40 +01:00
SET_DEVICE_STATE = 0x42
2020-10-30 02:00:14 +01:00
SET_OVERALL = 0x43
QUERY = 0xFF
Types = [
INPUT_JOYSTICK,
INPUT_WHEEL,
EFFECT_STATES,
SET_CONTROL,
CONTROL,
2020-10-31 00:47:40 +01:00
SET_DEVICE_STATE,
2020-10-30 02:00:14 +01:00
SET_OVERALL,
QUERY
]
class ControlType:
DEAD_ZONE = 0x00
IGNORE_DEADMAN_SWITCH = 0x01
ENABLE_COMM_WATCHDOG = 0x02
SET_SPRING_STRENGTH = 0x03
ENABLE_SPRING = 0x04
SET_AXIS_SATURATION = 0x05
class OverallControlType:
GAIN = 0x00
2020-10-31 00:47:40 +01:00
class DeviceState:
PAUSE_FFB = 0x08
ENABLE_FFB = 0x04
STOP_ALL = 0x01
2020-10-30 02:00:14 +01:00
class Query:
# Queries
BufferSize = 0x42 # ('B'uffer size)
Manufacturer = 0x4d # ('M'anufacturer)
Product = 0x50 # ('P'roduct)
Version = 0x56 # ('V'ersion)
NumberOfEffects = 0x4e # ('N'umber of effects)
Effect = 0x45 # ('E')ffect
# Control
Open = 0x4f # ('O'pen)
Close = 0x43 # ('C')lose
def tx_packet(command, data):
cs = Packet.SOP
yield Packet.SOP
cs ^= command
yield command
cs ^= len(data)
yield len(data)
for d in data:
cs ^= d
yield d
yield cs
def rx_packet(instream):
while instream:
# sync start
c = 0
cs = Packet.SOP
while c != Packet.SOP:
c = next(instream)
# packet type
pkt_type = next(instream)
cs ^= pkt_type
if pkt_type not in Packet.Types:
continue
# packet length
pkt_len = next(instream)
cs ^= pkt_len
assert pkt_len < Packet.MAX_LENGTH
# data
data = []
for _ in range(pkt_len):
d = next(instream)
cs ^= d
data.append(d)
# checksum
cs_in = next(instream)
cs ^= cs_in
yield (pkt_type, data, (cs == 0))
def create_rx_stream(input_stream):
global _rx_stream
_rx_stream = rx_packet(input_stream)
def rx_pump():
global _rx_stream
command, data, ok = next(_rx_stream)
if ok:
handle_pkt(command, data)
def set_handler(pkt_type, handler):
global _pkt_handlers
_pkt_handlers[pkt_type] = handler
def handle_pkt(command, data):
global _pkt_handlers
if command == Packet.INPUT_WHEEL:
output = {
'axis': {
'wheel': int.from_bytes(data[0:2], byteorder='little', signed=True) / 2048,
'gas': 1 - data[2] / 255,
'brake': 1 - data[3] / 255
},
'buttons': {
'B': bool(data[5] & 0x20),
'A': bool(data[5] & 0x10),
'4': bool(data[5] & 0x08),
'3': bool(data[5] & 0x04),
'2_PaddleDown': bool(data[5] & 0x02),
'1_PaddleUp_Start': bool(data[5] & 0x01)
},
'hat': {
'center': (data[6] & 0xF0) == 0xF0,
'up': (data[6] & 0xF0) == 0x00,
'down': (data[6] & 0xF0) == 0x40,
'left': (data[6] & 0xF0) == 0x60,
'right': (data[6] & 0xF0) == 0x20
}
}
elif command == Packet.QUERY:
output = {
'query': data[0],
'data': data[1:]
}
else:
output = data
if _pkt_handlers.get(command):
_pkt_handlers[command](output)