Circuitpython: USB HID

Created on 10 Jul 2018  Â·  41Comments  Â·  Source: adafruit/circuitpython

All 41 comments

split this into Bluetooth and wired USB support?

This is USB only. A BLE HID issue would be good too.

Descriptors to support are

  • keyboard
  • mouse
  • consumer key ( for volume up, down, brightness +/-)

We have code to generate the USB descriptors in https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/tools/gen_usb_descriptor.py (most of which should maybe be moved out of the port-specific directory). For HID, that code calls the library code in https://github.com/adafruit/usb_descriptor(which is a submodule further up in the tree), including pre-made HID descriptors in https://github.com/adafruit/usb_descriptor/blob/master/adafruit_usb_descriptor/hid.py. Besides the ones you listed, we also support a generic gamepad. There is latent support for a touchscreen but it does not work on all OS platforms so I turned it off.

Ah thanks, I am also quite familiar with hid descriptor, so it is not really an issue. Almost forgot the gamepad, I will add it as well

I figured you were an expert on that :grinning:. Let me know if you think there's something that could be improved in the current descriptors.

It is not true, I just copy thing here and there and put them together :)) . The whole hid descriptor is too complicated for anyone to digest :) . I will try out the descriptor generator as well. Above descriptors are all that I worked with so far.

If you want, you can use the descriptors in https://github.com/adafruit/usb_descriptor/blob/master/adafruit_usb_descriptor/hid.py. They are all lumped in a single-endpoint composite HID device. I spent a while tuning them up and making sure they work on all platforms.

Ah yeah, I also plan to have an one composite endpoint for all the hid. Since most the advance host should be able to parse it.

Please make it easy to change the descriptor from C at runtime. I want to expose it from Python in the future.

@tannewt no problem, I will make the hid report descriptor changeable dynamically (you will need to update the configuration descriptor for new length as well). However, to reduce amount of work, and get this done quickly, we will still implement it with fixed descriptor at first. When needed, we will change it with a separated PR.

Fixed now is good. Later all should be dynamic, not just HID.

On Mon, Jul 23, 2018 at 10:07 PM hathach notifications@github.com wrote:

@tannewt https://github.com/tannewt no problem, I will make the hid
report descriptor changeable dynamically (you will need to update the
configuration descriptor for new length as well). However, to reduce amount
of work, and get this done quickly, we will still implement it with fixed
descriptor at first. When needed, we will change it with a separated PR.

—
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/adafruit/circuitpython/issues/1009#issuecomment-407282580,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADNqQilN8TNpXLBvxMI38dYVa8BRWrUks5uJqt2gaJpZM4VIpq6
.

@tannewt just out of curiousity, we want to change hid report dynamically is to switch on/offf keyboard, mouse, gamepad etc right ? I ask since I always want to have a high level of api as much as possible for tinyusb. Those can be achieved at some level with predefined hid descriptor, though the full hid parser is too much for a device to support.

PS for configuration descriptor it is already dynamic supported by tinyusb, it will reconfigure endpoints based on parsing config desc when enumeration :)

We do want that but we also want the ability to enable and disable other functions such as mass storage, CDC, HID, audio and video. See #231, #672 and #1015 for background.

In general for CircuitPython we want a minimal C API that isn't timing sensitive. For example, for HID we construct the reports in Python because we can load that code dynamically and its not timing sensitive. C: https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/common-hal/usb_hid/Device.c Python: https://github.com/adafruit/Adafruit_CircuitPython_HID/blob/master/adafruit_hid/gamepad.py

@tannewt I see, class dynamic enable/disable is already support by tinyusb. python only need to feed the correct config descriptor. So it is not a problem at all.

For HID, to construct report in Python, I feel like we don't need to dynamically change the report descriptor. I could be wrong, let's me get something running first to see what it turns out to be.

For HID, we mean adding or dropping devices from the multiple report descriptor: https://github.com/adafruit/usb_descriptor/blob/master/adafruit_usb_descriptor/hid.py#L170. E.g. turn off keyboard, or allow a user to add another device with its own Report ID. As you mention, this affects the length field in the composite descriptor. (This stuff was clearly designed by two different committees: it would be a lot easier if the length were in the header of the HID Report Descriptor :frowning_face:)

@dhalbert thanks, I already got the idea, the C level should only need to implement a generic HID where user need to supply report descriptor and report, which I will added to the stack. Indeed one of issue when changing the wReportLength in the HID descriptor of Config Desc. Though, the stack is flexible enough, so it is not an issue (at least on nrf52 port :D )

FYI, In my stack, originally it attempts to support higher API with both keyboard & mouse API. It is useful to user that is not familiar with HID and only want to use out of the box keyboard/mouse.
https://github.com/hathach/tinyusb/blob/develop/src/class/hid/hid_device.h#L65

I also try to support boot keyboard at stack C-level as well, so it is a bit confusing with option and things. Trying to nail it now :D

Yeah, I don't think we need boot keyboard support, but it could be moved out of the multi-device HID descriptor to its own endpoint. We have enough endpoints on the SAMD, at least.

It can still packed within the multiple report one interface. Normally OS that does not support report protocol will SET_PROTOCOL to boot mode, in which the device will behave as a single report keyboard. Though it could be non-consistent if python user e.g does not enable keyboard. I will try to get something running first, I will could tweak things later :D

Boot keyboard is only essential if we want device to work with a simpler host such us SAMD with host stack or bios etc..

PS: It is just me trying to support multiple variant of things at once, which cause some confusing setting :( .

@dhalbert @tannewt do you have an simple python code, that I could paste into the REPL to run a usb hid test e.g sending 'A' repeatedly with keyboard profile.

Note that you will not see this echoed in the REPL while it's running (if you just do >>> k.send(Keycode.A) you'll see it). But if you move the focus to another window you'll see 'a's being sent.

from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
import time
k = Keyboard()
while True:
    k.send(Keycode.A)
    time.sleep(1.0)

Superb, thanks. Sorry for silly question, I haven't used cp much :(

You're welcome. https://circuitpython.readthedocs.io/projects/hid/en/latest/index.html has examples for other devices as well.

:+1: :+1:

btw, @tannewt do you decide the API to change the usb descriptor dynamically (enable/disable classes). If it is decided already, I will make it into the next PR as well.

Not sure what it will be. Static is ok for now. Thanks!

@dhalbert the readthedoc link should list Adafruit_CircuitPython_HID as dependency instead of the core repo right ?

never mind, I think you mean the dependency of the HID library. Sorry, misunderstand there.

@dhalbert @tannewt I would like to light up an LED when receiving SET REPORT request from host e.g CAPSLOCK. But couldn't find where to add it, could you please give me a hint ?

keyboard and mouse works quite well, cleaning it up for full list of devices support

@dhalbert @tannewt I would like to light up an LED when receiving SET REPORT request from host e.g CAPSLOCK. But couldn't find where to add it, could you please give me a hint ?

We haven't provided a way to do that reverse-direction dataflow at all yet in the HID module, so it would be noticeable work and an API addition. Fine to skip it for now. You could open a long-term issue

Ah, thanks. Since I don't know how to organize the cp API and my obj things. I will just turn on/off an LED0 for that, does it sound OK, if not I will leave it as stub.

A stub is fine too, since we don't want to reserve an LED just for this. It's more likely LED state would be sent on to some peripheral, (e.g. a pin) for someone who's building a keyboard. Right now CircuitPython doesn't have an of handling callbacks which we might want for this case (since SET REPORT can arrive spontaneously).

@dhalbert everything seems works, except for the gamepad, I got this error. I have no idea about this, am I missing something

Adafruit CircuitPython 4.0.0-alpha-40-g2c85f42-dirty on 2018-07-31; PCA10056 with nRF52840                                                                                                                                                                                 

>>> from adafruit_hid.gamepad import Gamepad                                                                                                                                                                                                                               

>>> gp = Gamepad()                                                                                                                                                                                                                                                         

Traceback (most recent call last):                                                                                                                                                                                                                                         

  File "<stdin>", line 1, in <module>                                                                                                                                                                                                                                      

  File "adafruit_hid/gamepad.py", line 89, in __init__                                                                                                                                                                                                                     

  File "adafruit_hid/gamepad.py", line 86, in __init__                                                                                                                                                                                                                     

  File "adafruit_hid/gamepad.py", line 149, in reset_all                                                                                                                                                                                                                   

  File "adafruit_hid/gamepad.py", line 163, in _send                                                                                                                                                                                                                       

TypeError: 'bytearray' object does not support item assignment                                                                                                                                                                                                             

btw @tannewt this line should be declaration only, and is missing extern right ?

https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/common-hal/usb_hid/Device.h#L48

I am basing nrf52 port on samd, just to make sure I am not missing something.

TypeError: 'bytearray' object does not support item assignment

In mpconfigport.h, try changing these from 0 to 1:

#define MICROPY_PY_ARRAY_SLICE_ASSIGN            (0)
...
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)

There are probably some other changes to the feature on/off flags that I should make match up with atmel-samd and esp8266. I'll do some diff'ing.

Superb !! It is all working now, thanks. I will do some clean up and submit an PR for review

@hathach Whatever works. :-) Feel free to change it.

Fixed by #1074.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

PaulStoffregen picture PaulStoffregen  Â·  29Comments

DWiskow picture DWiskow  Â·  29Comments

kevinjwalters picture kevinjwalters  Â·  38Comments

kattni picture kattni  Â·  49Comments

ATMakersBill picture ATMakersBill  Â·  24Comments