#hid

1 messages ยท Page 1 of 1 (latest)

round hedge
#
# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`Gamepad`
====================================================

* Author(s): Dan Halbert
"""

import time

from adafruit_hid import find_device
class Gamepad:
    def __init__(self, devices):
        """Create a Gamepad object that will send USB gamepad HID reports."""
        self._gamepad_device = find_device(devices, usage_page=0x1, usage=0x05)

        # Reuse this bytearray to send gamepad reports.
        # Report structure:
        #   Byte 0: RX
        #   Byte 1: RY
        #   Byte 2: RZ
        self._report = bytearray(3)

        # Remember the last report as well, so we can avoid sending duplicate reports.
        self._last_report = bytearray(3)

        # Store axis states separately for easier manipulation.
        self._rx = 0
        self._ry = 0
        self._rz = 0

        # Send an initial report to test if HID device is ready.
        # If not, wait a bit and try once more.
        try:
            self.reset_all()
        except OSError:
            time.sleep(1)
            self.reset_all()

    def set_axes(self, rx, ry, rz):
        """Set the RX, RY, and RZ axis values (0-255)."""
        self._rx = self._validate_axis_value(rx)
        self._ry = self._validate_axis_value(ry)
        self._rz = self._validate_axis_value(rz)
        self._send()

    def reset_all(self):
        self._rx = 0
        self._ry = 0
        self._rz = 0
        time.sleep(0.05)  # Short delay to prevent USB busy state
        self._send(always=True)
#
        # Pack RX, RY, RZ axes into the HID report
        self._report[0] = self._rx
        self._report[1] = self._ry
        self._report[2] = self._rz

        # Debug print to verify the report content
        print(f"Sending HID report: {self._report.hex()}")

        # Retry logic for USB busy state
        retry_count = 3
        for attempt in range(retry_count):
            try:
                # Only send the report if it has changed, unless `always` is True
                if always or self._last_report != self._report:
                    self._gamepad_device.send_report(self._report)
                    self._last_report[:] = self._report
                break
            except OSError as e:
                if attempt < retry_count - 1:
                    print(f"USB busy, retrying... (attempt {attempt + 1})")
                    time.sleep(0.05)  # Short delay before retrying
                else:
                    print("USB busy error, retries exhausted.")
                    raise e

    @staticmethod
    def _validate_axis_value(value):
        if not 0 <= value <= 255:
            raise ValueError("Axis value must be in range 0 to 255")
        return value```
pastel creek
#

Try the time.sleep() first. If that doesn't work, upload boot.py and code.py here.

round hedge
#

i got this as boot

# It may not suit your needs, or be supported on your host computer.
import usb_hid

GAMEPAD_REPORT_DESCRIPTOR = bytes([
    0x05, 0x01,        # Usage Page (Generic Desktop Controls)
    0x09, 0x05,        # Usage (Gamepad)
    0xA1, 0x01,        # Collection (Application)
    0x15, 0x00,        # Logical Minimum (0)
    0x26, 0xFF, 0x00,  # Logical Maximum (255)
    0x75, 0x08,        # Report Size (8 bits)
    0x95, 0x03,        # Report Count (3 fields: RX, RY, RZ)
    0x09, 0x33,        # Usage (RX - Rotation about X-axis)
    0x09, 0x34,        # Usage (RY - Rotation about Y-axis)
    0x09, 0x35,        # Usage (RZ - Rotation about Z-axis)
    0x81, 0x02,        # Input (Data, Variable, Absolute)
    0xC0               # End Collection
])

gamepad_descriptor = usb_hid.Device(
    report_descriptor=GAMEPAD_REPORT_DESCRIPTOR,
    usage_page=0x01,        # Generic Desktop Controls
    usage=0x05,             # Gamepad
    report_ids=(1,),        # Report ID is 1
    in_report_lengths=(3,), # 3 bytes: RX, RY, RZ
    out_report_lengths=(0,) # No output reports
)
#

this is the hid part

pastel creek
#

upload the whole files. Use the + instead of pasting. It takes less space

round hedge
#

oke one sec i can put it on github

#

might be easier

pastel creek
#

i have to go pick up a pizza; will be back alter

round hedge
#

๐Ÿ™‚ oke

round hedge
#

i wish i could just unit test it or something to get easier bug errors out of it

pastel creek
#

errors in boot.py are reported in boot_out.txt. Look in that file and see if there's an error reported

round hedge
#

oke will try that in a sec

#

Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode because:
Boot device must be first (interface #0).
Press reset to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.```
#

in need to reflash the whole pico when it gets in this state

pastel creek
#

you should not need to reflash everything. you need to do a hard reset to get out of safe mode

round hedge
#

Set interface name for the gamepad

usb_hid.enable((gamepad_descriptor,), boot_device=1)
usb_hid.set_interface_name("PedalBox")
usb_cdc.enable(console=True, data=True)

#

i got this and it stuck

#

in save mode

#

i cant copy files to it

pastel creek
#

the gamepad can't be a boot device.

#

only keyboard or mouse can be boot device.

round hedge
#

ah so the serial is?

#

oh oke

pastel creek
#

boot device is a special thing so you can use a keyboard to talk to the bios

#

or similar

round hedge
#

ah oke

#

i left this empty as well no cigar

pastel creek
#

but it should not be read-only, that's weird

#

is this 9.2.1?

#

There's a typo (missing comma) in the documentation, sorry :/

round hedge
#

9.0.5 i think im on

pastel creek
#

update to 9.2.1, and also make sure adafruit_hid is up to date

round hedge
#

oke

#

it did work for other projects ๐Ÿ™‚

#

just combination kinda freaks it out i think

#

but just hid or just serial on 9.0.5

pastel creek
#

there may well be some bug, but take away boot_device=1, you don't need that for the gamepad

round hedge
#

yes i did ๐Ÿ™‚

pastel creek
#

what is the host computer?

round hedge
#

and left the , cause python things

#

windows 11

#

hmm it makes 2 serial devices ..

pastel creek
#

that is right, console and data. Two COM ports

round hedge
#

ah oke ๐Ÿ™‚

pastel creek
#

do you need two? The data is for transferring binary data without getting in the way of the REPL. But if you don't need it, you can take that away

round hedge
#

ah now i get nice errors again ๐Ÿ™‚

  File "code.py", line 53, in <module>
  File "code.py", line 14, in __init__
  File "Pedals.py", line 26, in __init__
  File "Pedal.py", line 24, in __init__
  File "adafruit_ads1x15/ads1x15.py", line 153, in __init__
AttributeError: 'NoneType' object has no attribute 'try_lock'```
#

i can work with this

pastel creek
#

ok, you are on your way. looks like you i2c device is None

round hedge
#

i try to connect to this now

#

i have this on ardiuno now want it to pico bit more modern ๐Ÿ™‚

#

it uses serial to set settings to the device

#

and hid for game input

#

fun stuff

round hedge
#

@pastel creek thank you for your help and your awesome work on CircuitPython ๐Ÿ‘

pastel creek
#

you're welcome!

round hedge
#

i must say hid reports are not easy

#

like black magic ๐Ÿ˜„

pastel creek
#

it is so easy to make a mistake; too many times I have changed the comment but not the actual value

round hedge
#

winter project is building a pcb for it

#

old project didnt have it

#

i got lik 50 stars on it and i know most people using it dont have any github so ๐Ÿ™‚

#

fun to help the sim racing community bit