diff --git a/Feather_RP2040_USB_Host/CircuitPython_GamePad_ReadData/code.py b/Feather_RP2040_USB_Host/CircuitPython_GamePad_ReadData/code.py new file mode 100644 index 000000000..cfb34b3bb --- /dev/null +++ b/Feather_RP2040_USB_Host/CircuitPython_GamePad_ReadData/code.py @@ -0,0 +1,138 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import array +import time +import usb.core +import adafruit_usb_host_descriptors + +# Set to true to print detailed information about all devices found +VERBOSE_SCAN = True + +# indexes within the reports to ignore when determining equality. +# some devices send alternating values with each report, this +# allows to ignore those and focus only on bytes that are +# affected by buttons. Value of [19] will ignore data at index 19. +# Check your own output for values that change even when you don't +# do anything on the controller and add their indexes here. +IGNORE_INDEXES = [] + +DIR_IN = 0x80 +controller = None + +if VERBOSE_SCAN: + for device in usb.core.find(find_all=True): + controller = device + print("pid", hex(device.idProduct)) + print("vid", hex(device.idVendor)) + print("man", device.manufacturer) + print("product", device.product) + print("serial", device.serial_number) + print("config[0]:") + config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor( + device, 0 + ) + + i = 0 + while i < len(config_descriptor): + descriptor_len = config_descriptor[i] + descriptor_type = config_descriptor[i + 1] + if descriptor_type == adafruit_usb_host_descriptors.DESC_CONFIGURATION: + config_value = config_descriptor[i + 5] + print(f" value {config_value:d}") + elif descriptor_type == adafruit_usb_host_descriptors.DESC_INTERFACE: + interface_number = config_descriptor[i + 2] + interface_class = config_descriptor[i + 5] + interface_subclass = config_descriptor[i + 6] + print(f" interface[{interface_number:d}]") + print( + f" class {interface_class:02x} subclass {interface_subclass:02x}" + ) + elif descriptor_type == adafruit_usb_host_descriptors.DESC_ENDPOINT: + endpoint_address = config_descriptor[i + 2] + if endpoint_address & DIR_IN: + print(f" IN {endpoint_address:02x}") + else: + print(f" OUT {endpoint_address:02x}") + i += descriptor_len + +# get the first device found +device = None +while device is None: + for d in usb.core.find(find_all=True): + device = d + break + time.sleep(0.1) + +# set configuration so we can read data from it +device.set_configuration() +print(f"configuration set for {device.manufacturer}, {device.product}, {device.serial_number}") + +# Test to see if the kernel is using the device and detach it. +if device.is_kernel_driver_active(0): + device.detach_kernel_driver(0) + +# buffer to hold 64 bytes +buf = array.array("B", [0] * 64) + + +def print_array(arr, max_index=None, fmt="hex"): + """ + Print the values of an array + :param arr: The array to print + :param max_index: The maximum index to print. None means print all. + :param fmt: The format to use, either "hex" or "bin" + :return: None + """ + out_str = "" + if max_index is None or max_index >= len(arr): + length = len(arr) + else: + length = max_index + + for _ in range(length): + if fmt == "hex": + out_str += f"{int(arr[_]):02x} " + elif fmt == "bin": + out_str += f"{int(arr[_]):08b} " + print(out_str) + + +def reports_equal(report_a, report_b): + """ + Test if two reports are equal. Accounting for any IGNORE_INDEXES + + :param report_a: First report data + :param report_b: Second report data + :return: True if the reports are equal, otherwise False. + """ + if report_a is None and report_b is not None or \ + report_b is None and report_a is not None: + return False + for _ in range(len(report_a)): + if IGNORE_INDEXES is not None and _ not in IGNORE_INDEXES: + if report_a[_] != report_b[_]: + return False + return True + + +idle_state = None +prev_state = None + +while True: + try: + count = device.read(0x81, buf) + # print(f"read size: {count}") + except usb.core.USBTimeoutError: + continue + + if idle_state is None: + idle_state = buf[:] + print("Idle state:") + print_array(idle_state, max_index=count) + print() + + if not reports_equal(buf, prev_state) and not reports_equal(buf, idle_state): + print_array(buf, max_index=count) + + prev_state = buf[:]