Simple test

Ensure your device works with this simple test.

examples/usb_host_gamepad_simpletest.py
 1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
 2# SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple
 3#
 4# SPDX-License-Identifier: Unlicense
 5#
 6# Tested on Fruit Jam RP2350b
 7# Install prerequisites: circup install neopixel
 8import time
 9
10import board
11import displayio
12from neopixel import NeoPixel
13
14import relic_usb_host_gamepad
15
16DEBUG = False
17
18# disable REPL display output for better performance
19displayio.release_displays()
20
21neopixels = NeoPixel(board.NEOPIXEL, 5)
22neopixels.fill(0x000000)
23
24# create gamepad objects for ports 1 and 2
25gamepads = [relic_usb_host_gamepad.Gamepad(i + 1, debug=DEBUG) for i in range(2)]
26
27while True:
28    changed = False
29    for i, gamepad in enumerate(gamepads):
30        if gamepad.update() and gamepad.buttons.changed:
31            changed = True
32            for j, pressed in enumerate((gamepad.buttons.A, gamepad.buttons.B)):
33                neopixels[i * len(gamepads) + j] = 0xFFFFFF if pressed else 0x000000
34            for event in gamepad.buttons.events:
35                print(
36                    "Gamepad {:d}: {:s} {:s}".format(
37                        i + 1,
38                        relic_usb_host_gamepad.BUTTON_NAMES[event.key_number],
39                        ("Pressed" if event.pressed else "Released"),
40                    )
41                )
42    if changed:
43        neopixels.show()
44    time.sleep(1 / 60)

Displayio

Display the status of usb gamepads on ports 1 and 2 of an Adafruit Fruit Jam device using the HDMI video output.

examples/usb_host_gamepad_simpletest.py
  1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
  2# SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple
  3#
  4# SPDX-License-Identifier: Unlicense
  5#
  6# Tested on Fruit Jam RP2350b
  7# Install prerequisites: circup install adafruit_fruitjam
  8import time
  9
 10import displayio
 11import supervisor
 12import vectorio
 13from adafruit_fruitjam.peripherals import request_display_config
 14
 15import relic_usb_host_gamepad
 16
 17displayio.release_displays()
 18
 19request_display_config(320, 240)
 20display = supervisor.runtime.display
 21display.auto_refresh = False
 22
 23main_group = displayio.Group()
 24display.root_group = main_group
 25
 26
 27class Gamepad(displayio.Group):
 28    def __init__(self, port: int, size: int = 100):
 29        super().__init__()
 30        self._gamepad = relic_usb_host_gamepad.Gamepad(port)
 31
 32        bg_palette = displayio.Palette(1)
 33        bg_palette[0] = 0x0000FF
 34        self._bg = vectorio.Rectangle(pixel_shader=bg_palette, width=size, height=int(size * 0.6))
 35        self.append(self._bg)
 36
 37        self._released_palette = displayio.Palette(1)
 38        self._released_palette[0] = 0x888888
 39
 40        self._pressed_palette = displayio.Palette(1)
 41        self._pressed_palette[0] = 0xFFFFFF
 42
 43        button_size = int(size * 0.05)
 44
 45        self._buttons = (
 46            (0.85, 0.4),  # A
 47            (0.8, 0.5),  # B
 48            (0.8, 0.3),  # X
 49            (0.75, 0.4),  # Y
 50            (0.2, 0.3),  # UP
 51            (0.2, 0.5),  # DOWN
 52            (0.15, 0.4),  # LEFT
 53            (0.25, 0.4),  # RIGHT
 54            (0.6, 0.4),  # START
 55            (0.4, 0.4),  # SELECT
 56            (0.5, 0.4),  # HOME
 57            (0.1, 0.1),  # L1
 58            (0.9, 0.1),  # R1
 59            (0.2, 0.1),  # L2
 60            (0.8, 0.1),  # R2
 61            (0.3, 0.1),  # L3
 62            (0.7, 0.1),  # R3
 63            (0.35, 0.6),  # JOYSTICK_UP
 64            (0.35, 0.9),  # JOYSTICK_DOWN
 65            (0.25, 0.75),  # JOYSTICK_LEFT
 66            (0.45, 0.75),  # JOYSTICK_RIGHT
 67        )
 68        self._circles = []
 69        for x, y in self._buttons:
 70            circle = vectorio.Circle(
 71                pixel_shader=self._released_palette,
 72                radius=button_size // 2,
 73                x=int(x * self.width),
 74                y=int(y * self.height),
 75            )
 76            self._circles.append(circle)
 77            self.append(circle)
 78
 79        self._joystick_outer_size = int(size * 0.15)
 80        self._joystick_inner_size = int(size * 0.05)
 81
 82        joystick_outer_palette = displayio.Palette(1)
 83        joystick_outer_palette[0] = 0x000000
 84
 85        joystick_inner_palette = displayio.Palette(1)
 86        joystick_inner_palette[0] = 0xFFFFFF
 87
 88        self._joysticks = (
 89            ("left_joystick", 0.35, 0.75),
 90            ("right_joystick", 0.65, 0.75),
 91        )
 92        self._joystick_circles = []
 93        for name, x, y in self._joysticks:
 94            outer = vectorio.Circle(
 95                pixel_shader=joystick_outer_palette,
 96                radius=self._joystick_outer_size // 2,
 97                x=int(x * self.width),
 98                y=int(y * self.height),
 99            )
100            self.append(outer)
101            inner = vectorio.Circle(
102                pixel_shader=joystick_inner_palette,
103                radius=self._joystick_inner_size // 2,
104                x=int(x * self.width),
105                y=int(y * self.height),
106            )
107            self._joystick_circles.append(inner)
108            self.append(inner)
109
110    @property
111    def width(self) -> int:
112        return self._bg.width
113
114    @property
115    def height(self) -> int:
116        return self._bg.height
117
118    def update(self) -> bool:
119        if self._gamepad.update():
120            for event in self._gamepad.events:
121                self._circles[event.key_number].pixel_shader = (
122                    self._pressed_palette if event.pressed else self._released_palette
123                )
124            for i, data in enumerate(self._joysticks):
125                name, x, y = data
126                js_x, js_y = getattr(self._gamepad, name)
127                self._joystick_circles[i].x = int(
128                    (js_x * self._joystick_outer_size // 2) + (x * self.width)
129                )
130                self._joystick_circles[i].y = int(
131                    (-js_y * self._joystick_outer_size // 2) + (y * self.height)
132                )
133            return True
134        return False
135
136
137gamepads = [Gamepad(i + 1) for i in range(2)]
138
139gap = (display.width - sum(x.width for x in gamepads)) // (len(gamepads) + 1)
140for i, gamepad in enumerate(gamepads):
141    gamepad.x = gap * (i + 1) + gamepad.width * i
142    gamepad.y = (display.height - gamepad.height) // 2
143    main_group.append(gamepad)
144
145# initial refresh
146display.refresh()
147
148while True:
149    updated = False
150    for gamepad in gamepads:
151        if gamepad.update():
152            updated = True
153    if updated:
154        display.refresh()
155
156    time.sleep(1 / 30)