Skip to content

Issue #12: Converted joystick_xl to send 16-bits per axis #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions joystick_xl/hid.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ def create_joystick(

_descriptor.extend(bytes((
0x15, 0x00, # : LOGICAL_MINIMUM (0)
0x26, 0xFF, 0x00, # : LOGICAL_MAXIMUM (255)
0x75, 0x08, # : REPORT_SIZE (8)
0x27, 0xFF, 0xFF, 0x00, 0x00, # : LOGICAL_MAXIMUM (1 << 16)
Copy link

@henrygab henrygab Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

off-by-one in the comments?

LOGICAL_MAXIMUM ((1 << 16) - 1)

0x35, 0x00, # : PHYSICAL_MINIMUM (0)
0x47, 0xFF, 0xFF, 0x00, 0x00, # : PHYSICAL_MAXIMUM (1 << 16)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

off-by-one in the comments?

PHYSICAL_MAXIMUM ((1 << 16) - 1)****

0x75, 0x10, # : REPORT_SIZE (16)
0x95, _num_axes, # : REPORT_COUNT (num_axes)
0x81, 0x02, # : INPUT (Data,Var,Abs)
)))

_report_length = _num_axes
_report_length = _num_axes * 2

if _num_hats:
for i in range(_num_hats):
Expand Down
17 changes: 6 additions & 11 deletions joystick_xl/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ class Axis:
MIN = 0
"""Lowest possible axis value for USB HID reports."""

MAX = 255
MAX = (1 << 16) - 1
"""Highest possible axis value for USB HID reports."""

IDLE = 128
IDLE = 1 << 15
"""Idle/Center axis value for USB HID reports."""

X = 0
Expand Down Expand Up @@ -236,16 +236,11 @@ def _update(self) -> int:
new_value = min(max(self._source.value, self._min), self._max)

# account for deadband
if new_value < (self._raw_midpoint - self._deadband):
new_value -= self._min
elif new_value > (self._raw_midpoint + self._deadband):
new_value = new_value - self._min - (self._deadband * 2)
else:
new_value = self._db_range // 2

# calculate scaled joystick-compatible value and clamp to 0-255
self._value = min(new_value * 256 // self._db_range, 255)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct that scaling is not supported?
I note that physical and logical maximums are equal, so scaling shouldn't do anything. Just making sure...

if new_value >= self._raw_midpoint - self._deadband and \
new_value <= self._raw_midpoint + self._deadband:
new_value = self._raw_midpoint

self._value = new_value
return self._value


Expand Down
14 changes: 9 additions & 5 deletions joystick_xl/joystick.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def __init__(self) -> None:
self._axis_states = list()
for _ in range(self.num_axes):
self._axis_states.append(Axis.IDLE)
self._format += "B"
self._format += "H"

self.hat = list()
"""List of hat inputs associated with this joystick through ``add_input``."""
Expand Down Expand Up @@ -136,7 +136,7 @@ def _validate_axis_value(axis: int, value: int) -> bool:
if axis + 1 > Joystick._num_axes:
raise ValueError("Specified axis is out of range.")
if not Axis.MIN <= value <= Axis.MAX:
raise ValueError("Axis value must be in range 0 to 255")
raise ValueError(f"Axis value must be in range {Axis.MIN} to {Axis.MAX}")
return True

@staticmethod
Expand Down Expand Up @@ -241,7 +241,6 @@ def update(self, always: bool = False) -> None:

# Generate a USB HID report.
report_data = list()

report_data.extend(self._axis_states)

if self.num_hats:
Expand All @@ -256,8 +255,13 @@ def update(self, always: bool = False) -> None:

# Send the USB HID report if required.
if always or self._last_report != self._report:
self._device.send_report(self._report)
self._last_report[:] = self._report
try:
self._device.send_report(self._report)
self._last_report[:] = self._report
except OSError as e:
# This can occur if the USB is busy, or the host never properly connected to the
# USB device, drop the update and try later.
pass

def reset_all(self) -> None:
"""Reset all inputs to their idle states."""
Expand Down