forked from mirror/joycontrol
set analog stick cleanup and some comments
This commit is contained in:
+15
-3
@@ -27,6 +27,7 @@ class ControllerProtocol(BaseProtocol):
|
|||||||
|
|
||||||
self.transport = None
|
self.transport = None
|
||||||
|
|
||||||
|
# Increases for each input report send, overflows at 0x100
|
||||||
self._input_report_timer = 0x00
|
self._input_report_timer = 0x00
|
||||||
|
|
||||||
self._data_received = asyncio.Event()
|
self._data_received = asyncio.Event()
|
||||||
@@ -35,6 +36,7 @@ class ControllerProtocol(BaseProtocol):
|
|||||||
|
|
||||||
self._0x30_input_report_sender = None
|
self._0x30_input_report_sender = None
|
||||||
|
|
||||||
|
# This event gets triggered once the Switch assigns a player number to the controller and accepts user inputs
|
||||||
self.sig_set_player_lights = asyncio.Event()
|
self.sig_set_player_lights = asyncio.Event()
|
||||||
|
|
||||||
async def write(self, input_report: InputReport):
|
async def write(self, input_report: InputReport):
|
||||||
@@ -61,10 +63,13 @@ class ControllerProtocol(BaseProtocol):
|
|||||||
await self.transport.write(input_report)
|
await self.transport.write(input_report)
|
||||||
self._controller_state.sig_is_send.set()
|
self._controller_state.sig_is_send.set()
|
||||||
|
|
||||||
def get_controller_state(self):
|
def get_controller_state(self) -> ControllerState:
|
||||||
return self._controller_state
|
return self._controller_state
|
||||||
|
|
||||||
async def wait_for_output_report(self):
|
async def wait_for_output_report(self):
|
||||||
|
"""
|
||||||
|
Blocks until an output report from the Switch is received.
|
||||||
|
"""
|
||||||
self._data_received.clear()
|
self._data_received.clear()
|
||||||
await self._data_received.wait()
|
await self._data_received.wait()
|
||||||
|
|
||||||
@@ -79,11 +84,15 @@ class ControllerProtocol(BaseProtocol):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
async def input_report_mode_0x30(self):
|
async def input_report_mode_0x30(self):
|
||||||
|
"""
|
||||||
|
Continuously sends 0x30 input reports containing the controller state.
|
||||||
|
"""
|
||||||
if self.transport.is_reading():
|
if self.transport.is_reading():
|
||||||
raise ValueError('Transport must be paused in 0x30 input report mode')
|
raise ValueError('Transport must be paused in 0x30 input report mode')
|
||||||
|
|
||||||
input_report = InputReport()
|
input_report = InputReport()
|
||||||
input_report.set_input_report_id(0x30)
|
input_report.set_input_report_id(0x30)
|
||||||
|
input_report.set_vibrator_input()
|
||||||
input_report.set_misc()
|
input_report.set_misc()
|
||||||
|
|
||||||
reader = asyncio.ensure_future(self.transport.read())
|
reader = asyncio.ensure_future(self.transport.read())
|
||||||
@@ -110,7 +119,10 @@ class ControllerProtocol(BaseProtocol):
|
|||||||
report = OutputReport(list(data))
|
report = OutputReport(list(data))
|
||||||
output_report_id = report.get_output_report_id()
|
output_report_id = report.get_output_report_id()
|
||||||
|
|
||||||
if output_report_id == OutputReportID.SUB_COMMAND:
|
if output_report_id == OutputReportID.RUMBLE_ONLY:
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
|
elif output_report_id == OutputReportID.SUB_COMMAND:
|
||||||
reply_send = await self._reply_to_sub_command(report)
|
reply_send = await self._reply_to_sub_command(report)
|
||||||
except ValueError as v_err:
|
except ValueError as v_err:
|
||||||
logger.warning(f'Report parsing error "{v_err}" - IGNORE')
|
logger.warning(f'Report parsing error "{v_err}" - IGNORE')
|
||||||
@@ -118,7 +130,7 @@ class ControllerProtocol(BaseProtocol):
|
|||||||
logger.warning(err)
|
logger.warning(err)
|
||||||
|
|
||||||
if reply_send:
|
if reply_send:
|
||||||
# Hack: Adding a delay here to avoid flooding
|
# Hack: Adding a delay here to avoid flooding during pairing
|
||||||
await asyncio.sleep(0.3)
|
await asyncio.sleep(0.3)
|
||||||
else:
|
else:
|
||||||
# write 0x30 input report. TODO: set some sensor data
|
# write 0x30 input report. TODO: set some sensor data
|
||||||
|
|||||||
+29
-17
@@ -67,20 +67,26 @@ class InputReport:
|
|||||||
"""
|
"""
|
||||||
Sets the joystick status bytes
|
Sets the joystick status bytes
|
||||||
"""
|
"""
|
||||||
self.data[7:10] = bytes(left_stick)
|
self.set_left_analog_stick(bytes(left_stick))
|
||||||
self.data[10:13] = bytes(right_stick)
|
self.set_right_analog_stick(bytes(right_stick))
|
||||||
|
|
||||||
def set_left_analog_stick(self):
|
def set_left_analog_stick(self, left_stick_bytes):
|
||||||
"""
|
"""
|
||||||
TODO
|
Set left analog stick status bytes.
|
||||||
|
:param left_stick_bytes: 3 bytes
|
||||||
"""
|
"""
|
||||||
self.data[7:10] = [0x01, 0x18, 0x80]
|
if len(left_stick_bytes) != 3:
|
||||||
|
raise ValueError('Left stick status data must be exactly 3 bytes!')
|
||||||
|
self.data[7:10] = left_stick_bytes
|
||||||
|
|
||||||
def set_right_analog_stick(self):
|
def set_right_analog_stick(self, right_stick_bytes):
|
||||||
"""
|
"""
|
||||||
TODO
|
Set right analog stick status bytes.
|
||||||
|
:param right_stick_bytes: 3 bytes
|
||||||
"""
|
"""
|
||||||
self.data[10:13] = [0x01, 0x18, 0x80]
|
if len(right_stick_bytes) != 3:
|
||||||
|
raise ValueError('Right stick status data must be exactly 3 bytes!')
|
||||||
|
self.data[10:13] = right_stick_bytes
|
||||||
|
|
||||||
def set_vibrator_input(self):
|
def set_vibrator_input(self):
|
||||||
"""
|
"""
|
||||||
@@ -101,6 +107,7 @@ class InputReport:
|
|||||||
def set_6axis_data(self):
|
def set_6axis_data(self):
|
||||||
"""
|
"""
|
||||||
Set accelerator and gyro of 0x30 input reports
|
Set accelerator and gyro of 0x30 input reports
|
||||||
|
TODO
|
||||||
"""
|
"""
|
||||||
# HACK: Set all 0 for now
|
# HACK: Set all 0 for now
|
||||||
for i in range(14, 50):
|
for i in range(14, 50):
|
||||||
@@ -215,9 +222,8 @@ class OutputReport:
|
|||||||
if not data:
|
if not data:
|
||||||
data = 50 * [0x00]
|
data = 50 * [0x00]
|
||||||
data[0] = 0xA2
|
data[0] = 0xA2
|
||||||
|
elif data[0] != 0xA2:
|
||||||
if data[0] != 0xA2:
|
raise ValueError('Output reports must start with a 0xA2 byte!')
|
||||||
raise ValueError('Output reports must start with 0xA2')
|
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def get_output_report_id(self):
|
def get_output_report_id(self):
|
||||||
@@ -237,7 +243,7 @@ class OutputReport:
|
|||||||
|
|
||||||
def set_timer(self, timer):
|
def set_timer(self, timer):
|
||||||
"""
|
"""
|
||||||
Output report timer [0x0 - 0xF]
|
Output report timer in [0x0, 0xF]
|
||||||
"""
|
"""
|
||||||
self.data[2] = timer % 0x10
|
self.data[2] = timer % 0x10
|
||||||
|
|
||||||
@@ -252,16 +258,22 @@ class OutputReport:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
raise NotImplementedError(f'Sub command id {hex(self.data[11])} not implemented')
|
raise NotImplementedError(f'Sub command id {hex(self.data[11])} not implemented')
|
||||||
|
|
||||||
|
def set_sub_command(self, _id):
|
||||||
|
if isinstance(_id, SubCommand):
|
||||||
|
self.data[11] = _id.value
|
||||||
|
elif isinstance(_id, int):
|
||||||
|
self.data[11] = _id
|
||||||
|
else:
|
||||||
|
raise ValueError('id must be int or SubCommand')
|
||||||
|
|
||||||
def get_sub_command_data(self):
|
def get_sub_command_data(self):
|
||||||
if len(self.data) < 13:
|
if len(self.data) < 13:
|
||||||
return None
|
return None
|
||||||
return self.data[12:]
|
return self.data[12:]
|
||||||
|
|
||||||
def set_sub_command(self, _id):
|
def set_sub_command_data(self, data):
|
||||||
if isinstance(_id, SubCommand):
|
for i, _byte in enumerate(data):
|
||||||
self.data[11] = _id.value
|
self.data[12+i] = _byte
|
||||||
else:
|
|
||||||
self.data[11] = _id
|
|
||||||
|
|
||||||
def sub_0x10_spi_flash_read(self, offset, size):
|
def sub_0x10_spi_flash_read(self, offset, size):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user