Open
Description
CircuitPython version
Adafruit CircuitPython 8.0.0-rc.2 on 2023-02-02; Adafruit NeoPixel Trinkey M0 with samd21e18
Code/REPL
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Blink example for boards with ONLY a NeoPixel LED (e.g. without a built-in red LED).
Includes QT Py and various Trinkeys.
Requires two libraries from the Adafruit CircuitPython Library Bundle.
Download the bundle from circuitpython.org/libraries and copy the
following files to your CIRCUITPY/lib folder:
* neopixel.mpy
* adafruit_pixelbuf.mpy
Once the libraries are copied, save this file as code.py to your CIRCUITPY
drive to run it.
"""
import time
import board
import neopixel
import usb_hid
import rainbowio
import math
import touchio
from hid_gamepad import Gamepad
def dim(color, divisor=16):
color_tuple = color
if type(color) is int:
r = (color >> 16) & 0xff
g = (color >> 8) & 0xff
b = color & 0xff
color_tuple = (r, g, b)
rv = tuple(int(i/divisor) for i in color_tuple)
return rv
gp = Gamepad(usb_hid.devices)
pixels = neopixel.NeoPixel(board.NEOPIXEL, 4)
b0 = touchio.TouchIn(board.TOUCH1)
b1 = touchio.TouchIn(board.TOUCH2)
def p(i, t, color):
v = t.value
if v:
gp.press_buttons(i+1)
else:
gp.release_buttons(i+1)
# print(i, t.threshold, t.raw_value)
pixels[i+2] = color if v else 0x000000
gp.reset_all()
color_wheel_index = 0
b3 = True
with b0, b1:
while True:
t0 = time.monotonic()
while (time.monotonic() - t0 < 0.5):
pixels[0] = dim(rainbowio.colorwheel(color_wheel_index))
pixels[1] = dim(rainbowio.colorwheel(color_wheel_index+64))
p(0, b0, dim(rainbowio.colorwheel(color_wheel_index+128)))
p(1, b1, dim(rainbowio.colorwheel(color_wheel_index+192)))
jx = min (color_wheel_index - 127, 127)
jy = math.sin (color_wheel_index * 2 * 3.14159 / 256)
gp.move_joysticks(x=jx, y=int(jy*127))
color_wheel_index = (color_wheel_index + 1) % 256
time.sleep(0.01)
# do half second stuff here
if b3:
gp.press_buttons(3)
gp.release_buttons(4)
else:
gp.release_buttons(3)
gp.press_buttons(4)
b3 = not b3
Behavior
open code.py file from NeoTrinket. when I save file from Thonny, it throws a:
PROBLEM IN THONNY'S BACK-END: Exception while handling 'write_file' (ConnectionError: EOF).
See Thonny's backend.log for more info.
You may need to press "Stop/Restart" or hard-reset your CircuitPython device and try again.
Process ended with exit code 1.
Thonny log ends with:
11:40:58.747 ERROR thonny.backend: Exception while handling 'write_file'
Traceback (most recent call last):
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\backend.py", line 282, in _handle_normal_command
response = handler(cmd)
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\bare_metal_backend.py", line 1094, in _cmd_write_file
return super(BareMetalMicroPythonBackend, self)._cmd_write_file(cmd)
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\backend.py", line 568, in _cmd_write_file
self._write_file(
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\bare_metal_backend.py", line 1267, in _write_file
self._write_file_via_serial(source_fp, target_path, file_size, callback)
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\bare_metal_backend.py", line 1313, in _write_file_via_serial
out, err = self._execute(
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\mp_back.py", line 525, in _execute
self._execute_with_consumer(script, consume_output)
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\bare_metal_backend.py", line 703, in _execute_with_consumer
self._process_output_until_active_prompt(output_consumer)
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\bare_metal_backend.py", line 855, in _process_output_until_active_prompt
new_data = self._connection.soft_read_until(
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\connection.py", line 67, in soft_read_until
return self.read_until(terminator, timeout, timeout_is_soft=True)
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\connection.py", line 83, in read_until
self.check_for_error()
File "C:\Users\dwegs\AppData\Local\Programs\Thonny\lib\site-packages\thonny\plugins\micropython\connection.py", line 135, in check_for_error
raise ConnectionError(self._error)
ConnectionError: EOF
CircuitPython is throwing this to the console:
Auto-reload is off.
Running in safe mode! Not running saved code.
You are in safe mode because:
CircuitPython core code crashed hard. Whoops!
Crash into the HardFault_Handler.
Please file an issue with the contents of your CIRCUITPY drive at
https://github.com/adafruit/circuitpython/issues
Press any key to enter the REPL. Use CTRL-D to reload.
After this, the CircuitPython just does 3 yellow flashes over and over until reset.
Description
No response
Additional information
Problem does not exist with 7.3.3.
boot.py:
import usb_hid, usb_midi
usb_midi.disable()
# This is only one example of a gamepad descriptor, and may not suit your needs.
GAMEPAD_REPORT_DESCRIPTOR = bytes((
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x05, # Usage (Game Pad)
0xA1, 0x01, # Collection (Application)
#
0x85, 0x04, # Report ID (4)
0x05, 0x09, # Usage Page (Button)
0x19, 0x01, # Usage Minimum (Button 1)
0x29, 0x10, # Usage Maximum (Button 16)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x10, # Report Count (16)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
#
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x15, 0x81, # Logical Minimum (-127)
0x25, 0x7F, # Logical Maximum (127)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x09, 0x32, # Usage (Z)
0x09, 0x35, # Usage (Rz)
0x75, 0x08, # Report Size (8)
0x95, 0x04, # Report Count (4)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
#
0xC0, # End Collection
))
gamepad = usb_hid.Device(
report_descriptor=GAMEPAD_REPORT_DESCRIPTOR,
usage_page=0x01, # Generic Desktop Control
usage=0x05, # Gamepad
report_ids=(4,), # Descriptor uses report ID 4.
in_report_lengths=(6,), # This gamepad sends 6 bytes in its report.
out_report_lengths=(0,), # It receives a 1 byte report.
)
usb_hid.enable((
#usb_hid.Device.KEYBOARD,
usb_hid.Device.MOUSE,
#usb_hid.Device.CONSUMER_CONTROL,
gamepad,
))
hid.gamepad.py:
# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`Gamepad`
====================================================
* Author(s): Dan Halbert
"""
import struct
import time
from adafruit_hid import find_device
class Gamepad:
"""Emulate a generic gamepad controller with 16 buttons,
numbered 1-16, and two joysticks, one controlling
``x` and ``y`` values, and the other controlling ``z`` and
``r_z`` (z rotation or ``Rz``) values.
The joystick values could be interpreted
differently by the receiving program: those are just the names used here.
The joystick values are in the range -127 to 127."""
def __init__(self, devices):
"""Create a Gamepad object that will send USB gamepad HID reports.
Devices can be a list of devices that includes a gamepad device or a gamepad device
itself. A device is any object that implements ``send_report()``, ``usage_page`` and
``usage``.
"""
self._gamepad_device = find_device(devices, usage_page=0x1, usage=0x05)
# Reuse this bytearray to send mouse reports.
# Typically controllers start numbering buttons at 1 rather than 0.
# report[0] buttons 1-8 (LSB is button 1)
# report[1] buttons 9-16
# report[2] joystick 0 x: -127 to 127
# report[3] joystick 0 y: -127 to 127
# report[4] joystick 1 x: -127 to 127
# report[5] joystick 1 y: -127 to 127
self._report = bytearray(6)
# Remember the last report as well, so we can avoid sending
# duplicate reports.
self._last_report = bytearray(6)
# Store settings separately before putting into report. Saves code
# especially for buttons.
self._buttons_state = 0
self._joy_x = 0
self._joy_y = 0
self._joy_z = 0
self._joy_r_z = 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 press_buttons(self, *buttons):
"""Press and hold the given buttons."""
for button in buttons:
self._buttons_state |= 1 << self._validate_button_number(button) - 1
self._send()
def release_buttons(self, *buttons):
"""Release the given buttons."""
for button in buttons:
self._buttons_state &= ~(1 << self._validate_button_number(button) - 1)
self._send()
def release_all_buttons(self):
"""Release all the buttons."""
self._buttons_state = 0
self._send()
def click_buttons(self, *buttons):
"""Press and release the given buttons."""
self.press_buttons(*buttons)
self.release_buttons(*buttons)
def move_joysticks(self, x=None, y=None, z=None, r_z=None):
"""Set and send the given joystick values.
The joysticks will remain set with the given values until changed
One joystick provides ``x`` and ``y`` values,
and the other provides ``z`` and ``r_z`` (z rotation).
Any values left as ``None`` will not be changed.
All values must be in the range -127 to 127 inclusive.
Examples::
# Change x and y values only.
gp.move_joysticks(x=100, y=-50)
# Reset all joystick values to center position.
gp.move_joysticks(0, 0, 0, 0)
"""
if x is not None:
self._joy_x = self._validate_joystick_value(x)
if y is not None:
self._joy_y = self._validate_joystick_value(y)
if z is not None:
self._joy_z = self._validate_joystick_value(z)
if r_z is not None:
self._joy_r_z = self._validate_joystick_value(r_z)
self._send()
def reset_all(self):
"""Release all buttons and set joysticks to zero."""
self._buttons_state = 0
self._joy_x = 0
self._joy_y = 0
self._joy_z = 0
self._joy_r_z = 0
self._send(always=True)
def _send(self, always=False):
"""Send a report with all the existing settings.
If ``always`` is ``False`` (the default), send only if there have been changes.
"""
struct.pack_into(
"<Hbbbb",
self._report,
0,
self._buttons_state,
self._joy_x,
self._joy_y,
self._joy_z,
self._joy_r_z,
)
if always or self._last_report != self._report:
self._gamepad_device.send_report(self._report)
# Remember what we sent, without allocating new storage.
self._last_report[:] = self._report
@staticmethod
def _validate_button_number(button):
if not 1 <= button <= 16:
raise ValueError("Button number must in range 1 to 16")
return button
@staticmethod
def _validate_joystick_value(value):
if not -127 <= value <= 127:
raise ValueError("Joystick value must be in range -127 to 127")
return value