Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adafruit_CircuitPython_USB_Host_MIDI: __init__ fails on bad adafruit_usb_host_descriptors result #9930

Open
RobCranfill opened this issue Jan 3, 2025 · 3 comments
Labels
bug rp2 Both RP2 microcontrollers usb
Milestone

Comments

@RobCranfill
Copy link

RobCranfill commented Jan 3, 2025

CircuitPython version

Adafruit CircuitPython 9.2.1 on 2024-11-20; Adafruit Feather RP2040 USB Host with rp2040

Code/REPL

# A simplified (no UART output) version of 
#   examples/usb_host_midi_simpletest_rp2040usbfeather.py

# SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# pylint: disable=unused-import


import usb.core
import adafruit_midi
# from adafruit_midi.note_on import NoteOn
# from adafruit_midi.note_off import NoteOff
# from adafruit_midi.control_change import ControlChange
# from adafruit_midi.pitch_bend import PitchBend
import adafruit_usb_host_midi


print("Looking for midi device")
raw_midi = None
while raw_midi is None:
    for device in usb.core.find(find_all=True):
        try:
            raw_midi = adafruit_usb_host_midi.MIDI(device)
            print("Found", hex(device.idVendor), hex(device.idProduct))
        except ValueError:
            continue

# output not needed for this demo/test
# # This setup is to use TX pin on Feather RP2040 with USB Type A Host as MIDI out
# # You must wire up the needed resistors and jack yourself
# # This will forward all MIDI messages from the device to hardware uart MIDI
# uart = busio.UART(rx=board.RX, tx=board.TX, baudrate=31250, timeout=0.001)

midi_device = adafruit_midi.MIDI(midi_in=raw_midi, in_channel=0)
# midi_uart = adafruit_midi.MIDI(midi_out=uart, midi_in=uart)


while True:
    msg = midi_device.receive()
    if msg:
        print("midi msg:", msg)
        # midi_uart.send(msg)

Behavior

Run the code with a Roland FP30X MIDI keyboard attached and you get the following output, but which never returns from the constructor to adafruit_usb_host_midi.MIDI:

soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Looking for midi device
Found 0x582 0x29c

CTRL-C gets the following:

Traceback (most recent call last):
File "code.py", line 7, in
File "usb_host_midi_simpletest_rp2040usbfeather.py", line 40, in
File "adafruit_midi/init.py", line 128, in receive
File "/lib/adafruit_usb_host_midi.py", line 99, in read
KeyboardInterrupt:

Code done running.

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

Description

This error happens intermittently, along with succeeding perhaps 50% of the time. (It also gets a "usb.core.USBError: No configuration set" error, which is something else but perhaps a clue as to why nulls are being returned that cause the problem at hand.)

Here are 3 runs:

Success:

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Looking for midi device
Found 0x582 0x29c
midi msg: NoteOn(note=84, velocity=43, channel=0)
midi msg: NoteOn(note=86, velocity=42, channel=0)
...

Failure with usb**.core.USBError: No configuration set** error:

code.py output:
Looking for midi device
Found 0x582 0x29c
Traceback (most recent call last):
File "code.py", line 7, in
File "usb_host_midi_simpletest_rp2040usbfeather.py", line 40, in
File "adafruit_midi/init.py", line 128, in receive
File "/lib/adafruit_usb_host_midi.py", line 99, in read
usb.core.USBError: No configuration set

Code done running.

Failure but with my added null catcher:

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Looking for midi device
Traceback (most recent call last):
File "code.py", line 7, in
File "usb_host_midi_simpletest_rp2040usbfeather.py", line 24, in
File "/lib/adafruit_usb_host_midi.py", line 55, in init
Exception: adafruit_usb_host_descriptors has a null!

Code done running.

Additional information

If you make the following change to adafruit_usb_host_midi.py (starting at line 53, duplicated here)

            descriptor_len = config_descriptor[i]
            if descriptor_len == 0:                                             # cran
                raise Exception("adafruit_usb_host_descriptors has a null!")    # cran

you will see that previously the constructor got stuck in an infinite loop because config_descriptor[0] (as well as all the others!) has a value of 0, and the code
i += descriptor_len
at the end of the loop here never increments.

I'm not sure what the best way to handle this null value from config_descriptor is, but this works for me.

@RobCranfill RobCranfill added the bug label Jan 3, 2025
@tannewt tannewt added this to the Long term milestone Jan 3, 2025
@tannewt tannewt added usb rp2 Both RP2 microcontrollers labels Jan 3, 2025
@tannewt
Copy link
Member

tannewt commented Jan 3, 2025

Can you print out what the library is getting from the core? I suspect it is returning bad data and the library can't handle it. The fix would be to correct the core.

@RobCranfill
Copy link
Author

Can you print out what the library is getting from the core? I suspect it is returning bad data and the library can't handle it. The fix would be to correct the core.

The usb_host_descriptor is indeed a bunch of nulls - zeros. I can print that for ya if you want. :-) So yes, it's returning garbage. But it does seem like a Bad Thing for that iterator to assume it's nonzero. I realize one can only do so much error checking, but this seems like an easy one.

My project - and anyone else who connects to a similar MIDI device - is going to have to use patched code if this isn't fixed. Which yes, maybe usb_host_descriptor needs to have some way of saying "I got bad USB data", but we still need an error handler down the line, no?

@tannewt
Copy link
Member

tannewt commented Jan 6, 2025

Yup! The library can raise an exception to indicate the problem. The root fix will be in the core.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug rp2 Both RP2 microcontrollers usb
Projects
None yet
Development

No branches or pull requests

2 participants