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)