adafruit / Adafruit_CircuitPython_HID

USB Human Interface Device drivers.
MIT License
373 stars 105 forks source link

RawHID support #25

Closed timonsku closed 3 years ago

timonsku commented 6 years ago

Something that would be very helpful in communicating with computer side frameworks as an alternative to VCP would be the possiblity to have a RawHID class. My understanding of USB is not too in-depth but afaik this would just mean a new descriptor that allows for a report of the maximum possible size to send buffers back and forth.

Right now I can already do this with the existing classes, I'm just limited to very few bytes per transaction and can't receive something back. F.e. with the consumer key device:

import usb_hid

value = 4024
code = bytearray(2)
bytes = value.to_bytes(2,'big')
for device in usb_hid.devices:
            if device.usage_page == 0x0C and device.usage == 0x01:
                print('found consumer device')
                myDevice = device
                break
device.send_report(bytes)

I found this in the mpy docs but apart from this lonely docs page not much more and the pyb module does not seem to exist in CPY.

tannewt commented 6 years ago

I'd rather support a second cdc connection as tracked by: https://github.com/adafruit/circuitpython/issues/231

Please reopen if you need HID specifically.

timonsku commented 6 years ago

Seems I can't reopen by myself but yes, HID specifically would be what I'm interested in. I want to avoid serial all together as it poses a lot of trouble in the use cases I have. HID has proven to be a very robust way of communication. I think the second CDC port wants to tackle a different issue.

tannewt commented 6 years ago

Could you elaborate more on what you are doing then? Thanks!

timonsku commented 6 years ago

Sure thing! The main use case is getting data transmitted and received from an application running on Windows or Linux. The obvious way for that is using Serial though that comes with more than a few caveats.

First comes the uncertainty of the serial port number enumeration, this behaviour is the same on Windows and Linux (and Mac), after every reboot, your device might enumerate under a different port number. There are ways to circumvent this by having a hwid to port number resolver but that requires certain access to the OS and aren't always easy to implement in every framework.

Next and probably the most annoying one are the bugs that are often happening with the Serial port management on both Windows and Linux. It is far to common that a com port lands in a sort of zombie mode if the application using it had an issue/crashed or sometimes nothing apparent happening. Then the port is inaccessible until a system restart. This never happens to HID devices as they can have multiple users, every program is allowed to listen to an HID device, this is not the case with Serial ports. This is another big plus for HID if you want several applications listen to the same device.

Next issue is the unreliability of a transaction with Serial. There is no way of knowing if you fully received a message so you always have to spin a protocol in order to have any meaningful conversation with the device. HID is much more robust in this regard and does all of this for you. If you just want to share a few values with your PC application you can do this right away without any complexity and with a very high data rate.

When I talk about "frameworks" I mean things like openFrameworks, VVVV and more generic things like node.js and Python . These frameworks typically have support for reading HID device reports because the industry behind them often has to interface with odd hardware that quite often uses HID. So the support on the PC side is usually quite good but on the Microcontroller side there really only is Teensy if you want more than Mouse and Keyboard support.

If CPY HID support correlates in anyway to the Arduino cores HID support I also gladly see this on the Arduino side in addition to CPY.

If sponsoring the development can help in any way to get this feature implemented let me know!

tannewt commented 6 years ago

Thanks for the detailed explanation! Its not a high priority for us but may be easy to add.

I believe the place to start would be with the built in HID descriptors here: https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/tools/hid_report_descriptors.py They are then added to the full descriptor here: https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/tools/gen_usb_descriptor.py#L302

I think that once its added there it'll be available in usb_hid.devices.

timonsku commented 6 years ago

Are OUT endpoints represented in the API yet? That seems like it would be the biggest chunk of work if that doesn't exist yet. Getting the descriptor going shouldn't be too hard, having a look at some Arduino implementation probably helps. Teensy: https://github.com/PaulStoffregen/cores/blob/master/usb_rawhid/usb.c#L58-L90 AVR: https://github.com/NicoHood/HID/blob/master/src/SingleReport/RawHID.cpp#L26-L48

tannewt commented 6 years ago

Ah, OUT for HID isn't at the moment. I bet we'll want to add it as a queue of incoming reports.

timonsku commented 6 years ago

Queue sounds good!

fgervais commented 5 years ago

I'd also be interested in that feature

luolou commented 4 years ago

Can Adafruit_CircuitPython_HID operate in Python? An error appears when I run this in Python: ModuleNotFoundError: No module named 'usb_hid' Anyone knows the reason?

timonsku commented 4 years ago

@luolou thats a totally different issue but to answer that quickly, no if you are trying to run this on an SBC/Desktop, this will not work

timonsku commented 4 years ago

@tannewt could this get another shot? @hathach added raw hid support in TinyUSB a while back :)

dhalbert commented 4 years ago

I started working on raw HID for a special project but it's not at the top of my stack right now.

tannewt commented 4 years ago

@deshipu started adding OUT support here: https://github.com/adafruit/circuitpython/pull/2366

It is very basic for numlock only.

luolou commented 4 years ago

@luolou thats a totally different issue but to answer that quickly, no if you are trying to run this on an SBC/Desktop, this will not work

@PTS93 I run this on laptop(windows10 OS). Does this only run on adafruit devices? Whether regular computers also need support?

timonsku commented 4 years ago

@luolou this will only work on microcontrollers that have native USB device support and are supported by CircuitPython. No Laptop or Desktop computer will ever work with this library as they are not USB devices but USB hosts. This library only supports "emulating" HID devices which talk to a USB host like a laptop or desktop PC. E.g. a keyboard that plugs into your laptop. Your laptop is not capable of acting like a keyboard to another computer through a USB connection. If you have further questions please post them in the Adafruit Forums: https://forums.adafruit.com/viewforum.php?f=60 Or on the Adafruit Discord.

luolou commented 4 years ago

@PTS93 Thank you for your help.

dhalbert commented 3 years ago

CircuitPython 7.0.0 will allow you to supply your own HID report descriptors, and so will support raw HID. See https://github.com/adafruit/circuitpython/pull/4689, which is still in process. That PR only provides one HID device descriptor, which means you can only have raw, and no other HID devices, but could be extended in the future to support multiple HID devices (one raw, one conventional with multiple devices). Please open an issue in circuitpython if you will need multiple HID devices. I will close this for now.

timonsku commented 3 years ago

@dhalbert cool, will this also take care of being able to listen to both in and out endpoints? Afaik there was no API for the in endpoint.

dhalbert commented 3 years ago

There is now a .last_received_report attribute which was added to read LED status on keyboards, but I think it would work for this

dhalbert commented 1 year ago

https://github.com/adafruit/circuitpython/pull/7806 fixes a problem that gets in the way of raw HID, and should now allow this. There are some test programs there.