Hey there,
I would like to ask for help and direction, how to set up a custom HID descriptor via BLE (nRF52840), e.g. for the Telephony page (0x0B).
I have played around with the source code, just to understand how it works, however unsuccessful. Later, I have found out in the link below, that perhaps custom HID API will be supported in CircuitPython 7, is that correct?
https://learn.adafruit.com/customizing- ... id-devices
Could you please share some examples, that could help me get started? E.g. Modifying the Consumer control, or similar.
How to use the API, so I don't have to open the source code?
Thanks!
Cheers,
Tom
Custom HID descriptor API via BLE nRF52840
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- tannewt
- Posts: 3304
- Joined: Thu Oct 06, 2016 8:48 pm
Re: Custom HID descriptor API via BLE nRF52840
I don't know of any Telephony page examples.
It's much easier for us to support when looking at the code. I'd recommend you post what you have so far and what error you are getting.
It's much easier for us to support when looking at the code. I'd recommend you post what you have so far and what error you are getting.
- tannewt
- Posts: 3304
- Joined: Thu Oct 06, 2016 8:48 pm
Re: Custom HID descriptor API via BLE nRF52840
I think you want to start from this example: https://github.com/adafruit/Adafruit_Ci ... _periph.py
To switch the HID descriptor, you provide it to the HIDService constructor: https://circuitpython.readthedocs.io/pr ... HIDService
We don't have any examples of this but the HID descriptor should be the same as USB.
To switch the HID descriptor, you provide it to the HIDService constructor: https://circuitpython.readthedocs.io/pr ... HIDService
We don't have any examples of this but the HID descriptor should be the same as USB.
- tomeku
- Posts: 19
- Joined: Wed Jul 21, 2021 6:51 am
Re: Custom HID descriptor API via BLE nRF52840
Thanks, Tannewt, sure thing!
Ok, let's put the Telephone page aside for now, and let's focus on the custom HID gamepad example.
Here is a quick and dirty code, where I try to use the example taken from the tutorial, but adapting to BLE.
Tutorial: https://learn.adafruit.com/customizing- ... id-devices
Note: Other Adafruit BLE HID examples work fine.
code.py
For this example, I have just modified the "consumer_control_code.py" so it matches the Usage Page of game pad.
And I get this output...
It seems, the HIDService accepted the custom gamepad descriptor, however, I don't understand the error. Let me know please, if you need more context, that I could forget to share.
What would be the right approach?
Thank you!
Cheers,
Tom
Ok, let's put the Telephone page aside for now, and let's focus on the custom HID gamepad example.
Here is a quick and dirty code, where I try to use the example taken from the tutorial, but adapting to BLE.
Tutorial: https://learn.adafruit.com/customizing- ... id-devices
Note: Other Adafruit BLE HID examples work fine.
code.py
Code: Select all
import time
import board
from digitalio import DigitalInOut, Direction
import adafruit_ble
from adafruit_ble.advertising import Advertisement
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.standard.hid import HIDService
from adafruit_ble.services.standard.device_info import DeviceInfoService
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
# This is the custom gamepad descriptor, taken from the tutorial
GAMEPAD_REPORT_DESCRIPTOR = bytes((
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x05, # Usage (Game Pad)
0xA1, 0x01, # Collection (Application)
0x85, 0x01, # Report ID (will be replaced at runtime)
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
))
#here is how I try to call it, trying to adapt that for BLE (instead of the usb_hid class)
hid = HIDService(GAMEPAD_REPORT_DESCRIPTOR)
button = DigitalInOut(board.D12)
button.direction = Direction.INPUT
device_info = DeviceInfoService(software_revision=adafruit_ble.__version__,
manufacturer="Adafruit Industries")
advertisement = ProvideServicesAdvertisement(hid)
advertisement.appearance = 961
scan_response = Advertisement()
scan_response.complete_name = "CircuitPython HID test"
ble = adafruit_ble.BLERadio()
if not ble.connected:
print("advertising...")
ble.start_advertising(advertisement, scan_response)
else:
print("already connected")
print(ble.connections)
cc = ConsumerControl(hid.devices)
while True:
while not ble.connected:
pass
print("Start typing:")
while ble.connected:
if not button.value:
print("Button up pressed!")
cc.send(ConsumerControlCode.BRIGHTNESS_INCREMENT)
time.sleep(0.2)
ble.start_advertising(advertisement)
Code: Select all
self._consumer_device = find_device(devices, usage_page=0x01, usage=0x05)
Code: Select all
code.py output:
already connected
(<BLEConnection object at 20019720>,)
Traceback (most recent call last):
File "code.py", line 66, in <module>
File "/lib/adafruit_hid/consumer_control.py", line 43, in __init__
File "/lib/adafruit_hid/consumer_control.py", line 64, in send
File "/lib/adafruit_hid/consumer_control.py", line 84, in press
File "/lib/adafruit_ble/services/standard/hid.py", line 204, in send_report
ValueError: Value length != required fixed length
What would be the right approach?
Thank you!
Cheers,
Tom
- tannewt
- Posts: 3304
- Joined: Thu Oct 06, 2016 8:48 pm
Re: Custom HID descriptor API via BLE nRF52840
Unfortunately, I think you are on your own on this one. We haven't validated the BLE HID stuff with different descriptors and clearly there is a bug.
The code its in is probably: https://github.com/adafruit/Adafruit_Ci ... id.py#L190
The error is due to the BLE characteristic being setup at a fixed size and the report you are sending is a different size. I'm not sure why this is happening and don't have time to look into it.
I'd suggest that you work from the lower level and not use the keyboard library if you are trying to make something besides a keyboard. Instead, just craft the reports yourself.
The code its in is probably: https://github.com/adafruit/Adafruit_Ci ... id.py#L190
The error is due to the BLE characteristic being setup at a fixed size and the report you are sending is a different size. I'm not sure why this is happening and don't have time to look into it.
I'd suggest that you work from the lower level and not use the keyboard library if you are trying to make something besides a keyboard. Instead, just craft the reports yourself.
- tomeku
- Posts: 19
- Joined: Wed Jul 21, 2021 6:51 am
Re: Custom HID descriptor API via BLE nRF52840
Understand, no worries. Thank you, tannewt, anyway for your time looking into it. I will give it a try.
Could you give me at least guidance, how to call it from code.py? I am not sure how to adapt the code from the tutorial to the BLE HID syntax.
Many thanks,
Cheers,
Tom
Could you give me at least guidance, how to call it from code.py? I am not sure how to adapt the code from the tutorial to the BLE HID syntax.
Many thanks,
Cheers,
Tom
- tannewt
- Posts: 3304
- Joined: Thu Oct 06, 2016 8:48 pm
Re: Custom HID descriptor API via BLE nRF52840
Unfortunately, I can't be very specific without doing it myself. My approach would be to start from a working BLE HID example and then migrating the descriptor and reports over.
- tomeku
- Posts: 19
- Joined: Wed Jul 21, 2021 6:51 am
Re: Custom HID descriptor API via BLE nRF52840
Thanks.
I was able to modify it, however, still I have some doubts about few things because it looks different than the "Customizing USB Devices".
Here is my descriptor and how I use it:
Here is how I pass it in...
I also needed to modify the hid.py (class ReportIn), to avoid that issue, about fixed length, discussed previously.
Now, the code runs without the previously mentioned error, but I have no clue how to verify if it is working. I only receive reports in my Xcode app, but I am not sure if the report is having the right length, etc.
The tutorial provided also API for setting a specific attributes, like: "in_report_length", "out_report_length", etc..
How could I set it up for BLE as well? Am I on a right track?
I was able to modify it, however, still I have some doubts about few things because it looks different than the "Customizing USB Devices".
Here is my descriptor and how I use it:
Code: Select all
My_REPORT_DESCRIPTOR = bytes((
b"\x05\x0B" # Telephony
b"\x09\x05" # Usage (Headset)
b"\xA1\x01" # Collection (Application)
b"\x85\x02" # Report ID (2)
b"\x05\x0B" # Usage Page (Telephony Devices)
b"\x15\x00" # Logical Minimum (0)
b"\x25\x01" # Logical Maximum (1)
b"\x09\x20" # Usage (Hook Switch)
b"\x09\x97" # Usage (Line BusyTone)
b"\x75\x01" # Report Size (1)
b"\x95\x02" # Report Count (2)
b"\x81\x22" # Input (Data,Var,Abs,NWrp,Lin,NPrf,NNul,Bit)
b"\x09\x2F" # Usage (Phone Mute)
b"\x09\x21" # Usage (Flash)
b"\x09\x24" # Usage (Redial)
b"\x09\x50" # Usage (Speed Dial)
b"\x75\x01" # Report Size (1)
b"\x95\x04" # Report Count (4)
b"\x81\x06" # Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit)
b"\x09\x07" # Usage (Programmable Button)
b"\x05\x09" # Usage Page (Button)
b"\x75\x01" # Report Size (1)
b"\x95\x01" # Report Count (1)
b"\x81\x02" # Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)
b"\x05\x0B" # Usage Page (Telephony Devices)
b"\x09\x06" # Usage (Telephony Key Pad)
b"\xA1\x02" # Collection (Logical)
b"\x19\xB0" # Usage Minimum (Phone Key 0)
b"\x29\xBB" # Usage Maximum (Phone Key Pound)
b"\x15\x00" # Logical Minimum (0)
b"\x25\x0B" # Logical Maximum (11)
b"\x75\x04" # Report Size (4)
b"\x95\x01" # Report Count (1)
b"\x81\x00" # Input (Data,Ary,Abs)
b"\xC0" # End Collection
b"\x75\x01" # Report Size (1)
b"\x95\x05" # Report Count (5)
b"\x81\x01" # Input (Cnst,Ary,Abs)
b"\x05\x08" # Usage Page (LEDs)
b"\x15\x00" # Logical Minimum (0)
b"\x25\x01" # Logical Maximum (1)
b"\x09\x17" # Usage (Off-Hook)
b"\x09\x09" # Usage (Mute)
b"\x09\x18" # Usage (Ring)
b"\x09\x20" # Usage (Hold)
b"\x09\x21" # Usage (Microphone)
b"\x75\x01" # Report Size (1)
b"\x95\x05" # Report Count (5)
b"\x91\x22" # Output (Data,Var,Abs,NWrp,Lin,NPrf,NNul,NVol,Bit)
b"\x05\x0B" # Usage Page (Telephony Devices)
b"\x15\x00" # Logical Minimum (0)
b"\x25\x01" # Logical Maximum (1)
b"\x09\x9E" # Usage (Ringer)
b"\x75\x01" # Report Size (1)
b"\x95\x01" # Report Count (1)
b"\x91\x22" # Output (Data,Var,Abs,NWrp,Lin,NPrf,NNul,NVol,Bit)
b"\x75\x01" # Report Size (1)
b"\x95\x0A" # Report Count (10)
b"\x91\x01" # Output (Cnst,Ary,Abs,NWrp,Lin,Pref,NNul,NVol,Bit)
b"\xC0" # End Collection
))
Code: Select all
hid = HIDService(My_REPORT_DESCRIPTOR)
Code: Select all
# max_length=max_length,
fixed_length=False,
The tutorial provided also API for setting a specific attributes, like: "in_report_length", "out_report_length", etc..
Code: Select all
gamepad = usb_hid.Device(
report_descriptor=GAMEPAD_REPORT_DESCRIPTOR,
usage_page=0x01, # Generic Desktop Control
usage=0x05, # Gamepad
in_report_length=6, # This gamepad sends 6 bytes in its report.
out_report_length=0, # It does not receive any reports.
report_id_index=7, # The report id is at byte 7 (counting from 0)
# in the report descriptor.
)
- tomeku
- Posts: 19
- Joined: Wed Jul 21, 2021 6:51 am
Re: Custom HID descriptor API via BLE nRF52840
I read through more docs, and I guess, the custom HID descriptor should be initialized in boot.py. I will try again, and let you know.
- tomeku
- Posts: 19
- Joined: Wed Jul 21, 2021 6:51 am
Re: Custom HID descriptor API via BLE nRF52840
Hey tannewt,
I have progressed a bit. The good thing is, that I made it successfully working via USB (custom HID descriptor).
The challenge I have now is, how to make it work the same way using BLE?
Is there some trick, how to pass the custom descriptor, when initializing the BLE hid service?
Here is, how I pass the devices into my driver (btw. this works great via USB cable)
However, here I struggle. How to make the BLE HID service inherit my custom descriptor, defined in boot.py.
Thank you,
Tom
I have progressed a bit. The good thing is, that I made it successfully working via USB (custom HID descriptor).
The challenge I have now is, how to make it work the same way using BLE?
Is there some trick, how to pass the custom descriptor, when initializing the BLE hid service?
Here is, how I pass the devices into my driver (btw. this works great via USB cable)
Code: Select all
cdc = CustomDescriptorControl(usb_hid.devices)
Code: Select all
hid = HIDService()
Tom
Please be positive and constructive with your questions and comments.