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

usb_hid behaviour at boot.. #117

Closed
n0rt0nthec4t opened this issue May 17, 2023 · 28 comments · Fixed by #118
Closed

usb_hid behaviour at boot.. #117

n0rt0nthec4t opened this issue May 17, 2023 · 28 comments · Fixed by #118
Labels

Comments

@n0rt0nthec4t
Copy link

CircuitPython version

Adafruit CircuitPython 8.0.5 on 2023-03-31; Raspberry Pi Pico with rp2040

Code/REPL

import usb_midi
import usb_cdc
import usb_hid
import storage

usb_cdc.disable()   # Disable both serial devices.
usb_midi.disable()  # Disable mini
usb_hid.enable((usb_hid.Device.KEYBOARD, usb_hid.Device.CONSUMER_CONTROL))   # Enable just KEYBOARD and CONSUMER CONTROL

Behavior

...

Description

I have a project using circuitpython to provide a usb HID device (keyboard), however come up with some strange operating behaviour.

When connect a linux host (raspbian rpi4) at boot, the device is detected however doesnt function as a keyboard. Removing the usb connection and replugging back in, the device works as expected.

If I automount the CIRCUITPY disk at boot, then the device will work as expected also.

Is there a way to have this device function as expected without having to mount the usb-storage device?

dmesg output from boot

[    2.745421] usb 1-1.4: new full-speed USB device number 5 using xhci_hcd
[    2.892517] usb 1-1.4: New USB device found, idVendor=239a, idProduct=80f4, bcdDevice= 1.00
[    2.892543] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    2.892561] usb 1-1.4: Product: Pico
[    2.892578] usb 1-1.4: Manufacturer: Raspberry Pi
[    2.892594] usb 1-1.4: SerialNumber: E66118C4173BBA26
[    2.900386] usb-storage 1-1.4:1.0: USB Mass Storage device detected
[    2.901230] scsi host0: usb-storage 1-1.4:1.0
[    2.910112] input: Raspberry Pi Pico Keyboard as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.1/0003:239A:80F4.0003/input/input2
[    2.976415] input: Raspberry Pi Pico Consumer Control as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.1/0003:239A:80F4.0003/input/input3

Additional information

No response

@dhalbert dhalbert changed the title usb_hib behaviour at boot.. usb_hid behaviour at boot.. May 17, 2023
@dhalbert
Copy link
Collaborator

When connect a linux host (raspbian rpi4) at boot, the device is detected however doesnt function as a keyboard. Removing the usb connection and replugging back in, the device works as expected.

Could you describe the problem in more detail? What errors do you see? Sometimes a delay of a few seconds in your code.py is needed when the board powers up before you try to use an HID device, because the host computer (RPi in this case) is still enumerating and setting up the presented USB devices.

@n0rt0nthec4t
Copy link
Author

Tried adding a delay of 10seconds in code.py, but still same issue. SO, from power up, the boot process seems to run as per normal, just not functioning HID keyboard device. dmesg output from the boot process shows:

[    2.734495] usb 1-1.3: new full-speed USB device number 5 using xhci_hcd
[    2.881691] usb 1-1.3: New USB device found, idVendor=239a, idProduct=80f4, bcdDevice= 1.00
[    2.881714] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    2.881732] usb 1-1.3: Product: Pico
[    2.881749] usb 1-1.3: Manufacturer: Raspberry Pi
[    2.881766] usb 1-1.3: SerialNumber: E66118C4173BBA26
[    2.889542] usb-storage 1-1.3:1.0: USB Mass Storage device detected
[    2.890202] scsi host0: usb-storage 1-1.3:1.0
[    2.899070] input: Raspberry Pi Pico Keyboard as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.1/0003:239A:80F4.0003/input/input2
[    2.975512] input: Raspberry Pi Pico Consumer Control as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.1/0003:239A:80F4.0003/input/input3
[    2.975867] hid-generic 0003:239A:80F4.0003: input,hidraw2: USB HID v1.11 Keyboard [Raspberry Pi Pico] on usb-0000:01:00.0-1.3/input1

Unplugging the device while system operating and plugging back in, the HID keyboard generates errors in dmesg (or it works as normal:

[  222.298833] usb 1-1.3: USB disconnect, device number 5
[  226.944243] usb 1-1.3: new full-speed USB device number 6 using xhci_hcd
[  227.195308] usb 1-1.3: device descriptor read/all, error -32
[  227.294231] usb 1-1.3: new full-speed USB device number 7 using xhci_hcd
[  227.404514] usb 1-1.3: device descriptor read/64, error -32
[  228.251921] xhci_hcd 0000:01:00.0: Setup ERROR: setup address command for slot 4.
[  228.464414] xhci_hcd 0000:01:00.0: Setup ERROR: setup address command for slot 4.
[  228.684223] usb 1-1.3: device not accepting address 7, error -22
[  228.684967] usb 1-1-port3: attempt power cycle
[  229.344220] usb 1-1.3: new full-speed USB device number 8 using xhci_hcd
[  229.344404] xhci_hcd 0000:01:00.0: Setup ERROR: setup address command for slot 4.
[  229.564380] xhci_hcd 0000:01:00.0: Setup ERROR: setup address command for slot 4.
[  229.784250] usb 1-1.3: device not accepting address 8, error -22
[  229.884248] usb 1-1.3: new full-speed USB device number 9 using xhci_hcd
[  229.884434] xhci_hcd 0000:01:00.0: Setup ERROR: setup address command for slot 4.
[  230.104423] xhci_hcd 0000:01:00.0: Setup ERROR: setup address command for slot 4.
[  230.324252] usb 1-1.3: device not accepting address 9, error -22
[  230.324891] usb 1-1-port3: unable to enumerate USB device
[  416.675697] usb 1-1.3: new full-speed USB device number 10 using xhci_hcd
[  417.157315] usb 1-1.3: New USB device found, idVendor=239a, idProduct=80f4, bcdDevice= 1.00
[  417.157338] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  417.157356] usb 1-1.3: Product: Pico
[  417.157374] usb 1-1.3: Manufacturer: Raspberry Pi
[  417.157391] usb 1-1.3: SerialNumber: E66118C4173BBA26
[  417.177452] usb-storage 1-1.3:1.0: USB Mass Storage device detected
[  417.179879] scsi host0: usb-storage 1-1.3:1.0
[  417.190576] input: Raspberry Pi Pico Keyboard as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.1/0003:239A:80F4.0004/input/input4
[  417.266864] input: Raspberry Pi Pico Consumer Control as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.1/0003:239A:80F4.0004/input/input5
[  417.267265] hid-generic 0003:239A:80F4.0004: input,hidraw2: USB HID v1.11 Keyboard [Raspberry Pi Pico] on usb-0000:01:00.0-1.3/input1

@dhalbert
Copy link
Collaborator

Could you post your code.py, or the simplest version that reproduces the problem? Thanks.

@n0rt0nthec4t
Copy link
Author

@n0rt0nthec4t
Copy link
Author

Any thoughts on this ?

@dhalbert
Copy link
Collaborator

dhalbert commented Jun 3, 2023

Diagnostic testing:
If you roll back to 8.0.0 or 7.3.3, do you see the same problem?
If you remove boot.py, do you see the same problem?
What version of Raspberry Pi OS is running on the Pi 4? Is the the latest, brought up to date?

@n0rt0nthec4t
Copy link
Author

Seems to make no difference with.out the boot.py and uf2 versions either (been back as far as 6.3.3). Setup is running RetroPie 4.8.4, rpi4 (armv7l) - Raspbian GNU/Linux 10 (buster) - Linux retropie 5.10.103-v7l+

@uzi18
Copy link

uzi18 commented Aug 22, 2023

@dhalbert @n0rt0nthec4t Same problem here on pico with CP 8.2.3

boot.py:

import usb_midi
import usb_cdc
import usb_hid
import storage

usb_cdc.disable()   # Disable both serial devices.
usb_midi.disable()  # Disable mini
usb_hid.enable((usb_hid.Device.KEYBOARD, ))   # Enable just KEYBOARD 
storage.disable_usb_drive()

storage.disable_usb_drive() - with this line commented HID KEYBOARD shows and works properly - tested on WIN7 64bit

So how to disable storage with usb_hid enabled?

@dhalbert
Copy link
Collaborator

dhalbert commented Aug 22, 2023

if you remove the usb_hid.enable() line entirely, but leave all the rest, does it work?

I have a volume control that is built with a Trinket M0, with code similar to the above. I upgraded it to 8.2.3, and it is still working properly. It does not disable anything in HID, and it does not disable MIDI, but it does do this:

    storage.disable_usb_drive()
    usb_cdc.enable(console=False)

Host computer is a PC running Ubuntu 22.04.

@uzi18
Copy link

uzi18 commented Aug 23, 2023

if you remove the usb_hid.enable() line entirely, but leave all the rest, does it work?

@dhalbert No change. No hid device on device manager.

Host computer is a PC running Ubuntu 22.04.

Look's like Host is not a problem here.

Any ideas?

@uzi18
Copy link

uzi18 commented Aug 23, 2023

But it works on WinCE if it is connected from boot time.

@n0rt0nthec4t
Copy link
Author

makes no difference for me

@eightycc
Copy link

eightycc commented Sep 12, 2023

I've set up a small test jig that can reproduce the problem. I borrowed a simple keyboard HID emulator from here https://learn.adafruit.com/circuitpython-essentials/circuitpython-hid-keyboard-and-mouse and modified it slightly to work with a Pico W. I put these lines from @dhalbert into boot.py:

import usb_cdc
import storage

storage.disable_usb_drive()
usb_cdc.enable(console=False)

Plugging this into a cold RP 4 fails, but plugging it in when the RP 4 is booted works. I also tried it on a Linux box with similar but oddly intermittent results. Sometimes it worked with the cold Linux box and sometimes it didn't. I also noticed that when it failed, the onboard led blinked two shorts and a long pause repeatedly. I think this means that board has fallen into REPL on an error, I'll hook it up the through picoprobe next to see if that's the case.

Something else caught my eye: The linux box fails when power is present on the USB port with the box powered down, but does not fail when it isn't. That's probably due to some janky BIOS code in the Linux box for wake from sleep, but it could be an important clue.

@n0rt0nthec4t
Copy link
Author

Plugging this into a cold RP 4 fails, but plugging it in when the RP 4 is booted works

This is exactly the behaviour I experienced when starting this issue. Lets see where your testing goes

@uzi18
Copy link

uzi18 commented Sep 12, 2023

You all confirmed what we also have.
If it is already connected at boot time it works as expected.
But looks like only in boot mode.
Is there a way to detect hid mode at runtime?

@uzi18
Copy link

uzi18 commented Sep 12, 2023

Also used now tonny editor instead of bloated Mu-editor. Give it a try.

@eightycc
Copy link

Activated UART REPL by adding these lines to ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.h:

#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO0)
#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO1)

and then connected the UART through picoprobe. Here's what I get on a cold RP 4:

Serial console setup                                                                                     
Adafruit CircuitPython 8.2.5-1-g707120244c-dirty on 2023-09-12; Raspberry Pi Pico W with rp2040          
Board ID:raspberry_pi_pico_w                                                                             
UID:E6614C775B4D5335                                                                                     
MAC:28:CD:C1:00:D3:A5                                                                                    
boot.py output:                                                                                          
0;🐍Wi-Fi: off | Done | 8.2.5-1-g707120244c-dirty                                                        
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.                      
code.py output:                                                                                          
0;🐍Wi-Fi: off | code.py | 8.2.5-1-g707120244c-dirtyTraceback (most recent call last):                   
  File "code.py", line 27, in <module>                                                                   
  File "adafruit_hid/keyboard.py", line 74, in __init__                                                  
  File "adafruit_hid/keyboard.py", line 122, in release_all
OSError: USB busy
0;🐍Wi-Fi: off | 122@adafruit_hid/keyboard.py OSError | 8.2.5-1-g707120244c-dirty
Code done running.

And here's what I get with a warm RP 4:

Serial console setup
Adafruit CircuitPython 8.2.5-1-g707120244c-dirty on 2023-09-12; Raspberry Pi Pico W with rp2040
Board ID:raspberry_pi_pico_w
UID:E6614C775B4D5335
MAC:28:CD:C1:00:D3:A5
boot.py output:
0;🐍Wi-Fi: off | Done | 8.2.5-1-g707120244c-dirty
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
0;🐍Wi-Fi: off | code.py | 8.2.5-1-g707120244c-dirtyWaiting for key pin...

@tannewt
Copy link
Member

tannewt commented Sep 12, 2023

led blinked two shorts and a long pause repeatedly.

This is an exception. REPL is usually solid white when entered.

OSError: USB busy

This can be trying to send over USB before it is fully connected.

@eightycc
Copy link

If I plug the Pico into a simple power adapter, I get the same OSError as for a cold RP 4. That leads me to think that something in the USB stack doesn't like getting invoked by keyboard.py before the host USB is initialized.

@dhalbert
Copy link
Collaborator

You can use supervisor.runtime.usb_connected to detect whether USB enumeration has completed. If you busy-wait on that in the code.py, does it help?

@eightycc
Copy link

eightycc commented Sep 12, 2023

During HID initialization, adafruit_hid/keyboard.py tries to release all keys by means of self.release_all() and then tries once more on failure after 1 second. So, this clearly isn't going to cut it if there's a long delay between power-on and host enumeration. Thanks @dhalbert I was just going to search for such an animal as supervisor.runtime.usb_connected. Giving it a try now.

@dhalbert
Copy link
Collaborator

The library code like keyboard.py and mouse.py don't wait indefinitely for things to come up. They try once, and then sleep and try once again. That was based on empirical testing a long time years ago on SAMD21 on host computers. If they should busy-wait for longer, that would be a fine improvement to the HID library.

@eightycc
Copy link

On the RP 4 the delay is several seconds (seems like at least 10 without measuring it), while your typical desktop PC the BIOS enumerates PDQ after power on to find HID devices.

@dhalbert
Copy link
Collaborator

The original delay was done here: #15, clearly not enough now sometimes.

@eightycc
Copy link

I'm doing some empirical testing here to find an appropriate delay, then I'll submit a PR.

@dhalbert
Copy link
Collaborator

I'm doing some empirical testing here to find an appropriate delay, then I'll submit a PR.

Will this be a library PR? We can transfer this issue to the HID library.

@eightycc
Copy link

Yes, please transfer to the HID library and I'll pick it up from there.

@dhalbert dhalbert transferred this issue from adafruit/circuitpython Sep 12, 2023
@eightycc
Copy link

It's taking the RP 4 up to 15 seconds to enumerate after POR, so I'm going to retry every second for up to 20 seconds. Having multiple retries 1 second apart avoids the problem of having an unresponsive HID device if enumeration takes just a bit more than 1 second. Updating all HID devices similarly.

dhalbert added a commit that referenced this issue Sep 14, 2023
Fix #117: Rework host USB ready timeout
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants