How to use Bluetooth hid

Posted on
  • Hi,

    I'm currently trying to test the hid function with the "Bluetooth Keyboard" and "Binary Bluetooth Keyboard" applications and a linux computer, but I'm not able to input any keys.

    The device is paired successfully:

    input: Bangle.js 3f3e Keyboard as /devices/virtual/misc/uhid/0005:0000:000­0.0003/input/input3
    input: Bangle.js 3f3e Consumer Control as > /devices/virtual/misc/uhid/0005:0000:000­0.0003/input/input4
    hid-generic 0005:0000:0000.0003: input,hidraw1: BLUETOOTH HID v0.00 Keyboard [Bangle.js 3f3e] on AA:AA:AA:AA:AA:AA

    but I do not seem to get any bytes from the hidraw device:

    xxd /dev/hidraw1

    prints nothing. The same procedure worked with a bluetooth keyboard.

    The "hid"-option is enabled on the bangle.js. Does anyone has an idea what extra steps needs to be done?

  • According to the BLE+Keyboard documentation NRF.setServices() accepts 8 arguments, but hid-keyboard.js gives 9 arguments. Also the shift modifier is set and the NRF.setServices() call is missing. Is there any other documentation to check?

  • Sun 2020.04.19

    HID is out of my league, but has the HID event been checked out?

    https://www.espruino.com/Reference#l_NRF­_HID

    Bluetooth LE HID Keyboards


    'but hid-keyboard.js gives 9 arguments'

    Hmmmm, seems you may have discovered an 'undocumented feature' ;-)

    Although it appears the array may contain a variable length:

    first hyper link 'ble_hid_keyboard' within the page loaded from first link #2 post
    https://www.espruino.com/modules/ble_hid­_keyboard.js

  • Sorry, I don't see where you get the variable length from, the ble_hid_keyboard.js also does only 8 arguments? According to the source the function accepts different length. Still I don't know if 9 arguments is correct since I have not read the hid documentation yet. Also jswrap_ble_sendHIDReport() states:

    Send a USB HID report. HID must first be enabled with NRF.setServices({}, {hid: hid_report})

    so the setServices() call is really missing here.

  • The NRF.setServices call is actually in the bootloader: https://github.com/espruino/BangleApps/b­lob/master/apps/boot/boot0.js#L8

    In terms of NRF.sendHIDReport size, it could be a bug, but the size of the data sent depends on the HID report that Bangle.js is reporting, and what it tells the computer about what's available. I believe the HID report used for Bangle.js includes 'music controls' which is why it's larger.

    Eg music control app: https://github.com/espruino/BangleApps/b­lob/master/apps/hidmsic/hid-music.js#L11­

    Just to rule out OS issues, can you try connecting with an Android phone or something like that? Just tried here and it works great.

  • Thanks, the bootloader code was a missing part. I read it "HID needs to be enabled when turning on the clock" or else it will not work.

    Still it does not work with the Linux computer, but it works with an Android (the 9 byte version, not the 8 byte) after restarting the clock.

    Can I assume Android was the primary target this was tested with?
    Any do you have a commented version of the hid description in the bootloader somewhere? The longterm goal is a joystick app using the accelerometer as stick and I guess the description would need modification for that.
    Also does it work for anyone with a Linux PC?

  • "HID needs to be enabled when turning on the clock"

    I don't think this is true now. HID just needs to be enabled when you pair it with your device

    Can I assume Android was the primary target this was tested with?

    I think it was Windows/Mac OS. However afaik Windows makes it difficult to access the UART connection while using it as a HID device.

    Also does it work for anyone with a Linux PC?

    I actually tried here and didn't have success.

    do you have a commented version of the hid description

    I think it's this, but I'm afraid I don't have comments as it came from someone else (https://github.com/jasnell). I believe it is just a modified version of https://github.com/espruino/BangleApps/b­lob/master/apps/hidkbd/hid-keyboard.js

    0x05, 0x01,
          0x09, 0x06,
          0xA1, 0x01,
          0x05, 0x07,
          0x19, 0xe0,
          0x29, 0xe7,
          0x15, 0x00,
          0x25, 0x01,
          0x75, 0x01,
          0x95, 0x08,
          0x81, 0x02,
          0x95, 0x01,
          0x75, 0x08,
          0x81, 0x01,
          0x95, 0x05,
          0x75, 0x01,
          0x05, 0x08,
          0x19, 0x01,
          0x29, 0x05,
          0x91, 0x02,
          0x95, 0x01,
          0x75, 0x03,
          0x91, 0x01,
          0x95, 0x06,
          0x75, 0x08,
          0x15, 0x00,
          0x25, 0x73,
          0x05, 0x07,
          0x19, 0x00,
          0x29, 0x73,
          0x81, 0x00,
          0x09, 0x05,
          0x15, 0x00,
          0x26, 0xFF, 0x00,
          0x75, 0x08,
          0x95, 0x02,
          0xB1, 0x02,
          0xC0
    

    joystick app using the accelerometer

    Yes, you could look at using a USB HID report for a mouse/similar: https://www.espruino.com/USB

    I'm sure you could get a joystick one working too

  • I don't think this is true now. HID just needs to be enabled when you pair it with your device

    Well I'm new to this, but when exactly is boot0.js executed, when I pair with another device or a single time on start?

    The code in boot0.js is basically:

    var s = require('Storage').readJSON('setting.jso­n',1)||{};
    if (s.HID) { // Human interface device
        Bangle.HID = "(...)";
        NRF.setServices({}, {uart:true, hid:Bangle.HID});
    }
    

    so when HID is not enabled in settings while starting and boot0.js is only executed on start the NRF.setServices() never happens, correct?

  • Found a parser:
    https://eleccelerator.com/usbdescreqpars­er/

    0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
    0x09, 0x06, // Usage (Keyboard)
    0xA1, 0x01, // Collection (Application)
    0x85, 0x02, // Report ID (2)
    0x05, 0x07, // Usage Page (Kbrd/Keypad)
    0x19, 0xE0, // Usage Minimum (0xE0)
    0x29, 0xE7, // Usage Maximum (0xE7)
    0x15, 0x00, // Logical Minimum (0)
    0x25, 0x01, // Logical Maximum (1)
    0x75, 0x01, // Report Size (1)
    0x95, 0x08, // Report Count (8)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x01, // Report Count (1)
    0x75, 0x08, // Report Size (8)
    0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x05, // Report Count (5)
    0x75, 0x01, // Report Size (1)
    0x05, 0x08, // Usage Page (LEDs)
    0x19, 0x01, // Usage Minimum (Num Lock)
    0x29, 0x05, // Usage Maximum (Kana)
    0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0x95, 0x01, // Report Count (1)
    0x75, 0x03, // Report Size (3)
    0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0x95, 0x06, // Report Count (6)
    0x75, 0x08, // Report Size (8)
    0x15, 0x00, // Logical Minimum (0)
    0x25, 0x73, // Logical Maximum (115)
    0x05, 0x07, // Usage Page (Kbrd/Keypad)
    0x19, 0x00, // Usage Minimum (0x00)
    0x29, 0x73, // Usage Maximum (0x73)
    0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x05, // Usage (0x05)
    0x15, 0x00, // Logical Minimum (0)
    0x26, 0xFF, 0x00, // Logical Maximum (255)
    0x75, 0x08, // Report Size (8)
    0x95, 0x02, // Report Count (2)
    0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0xC0, // End Collection
    0x05, 0x0C, // Usage Page (Consumer)
    0x09, 0x01, // Usage (Consumer Control)
    0xA1, 0x01, // Collection (Application)
    0x85, 0x01, // Report ID (1)
    0x15, 0x00, // Logical Minimum (0)
    0x25, 0x01, // Logical Maximum (1)
    0x75, 0x01, // Report Size (1)
    0x95, 0x01, // Report Count (1)
    0x09, 0xB5, // Usage (Scan Next Track)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xB6, // Usage (Scan Previous Track)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xB7, // Usage (Stop)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xB8, // Usage (Eject)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xCD, // Usage (Play/Pause)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xE2, // Usage (Mute)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xE9, // Usage (Volume Increment)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xEA, // Usage (Volume Decrement)
    0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0, // End Collection
    // 127 bytes

  • At least now I understand why hidkbd.app.js sends 9 bytes instead of 8: Since there are now two collections instead of only one as in ble_hid_keyboard.js the report id (2 for keyboard) needs to be prefixed. Unfortunately Linux still seem to think it is 0:

    drivers/hid/hid-core.c: undefined report_id 0 received

    What Linux receives is:

    cat /sys/kernel/debug/hid/0005:0000:0000.000­3/events
    report (size 10) (numbered) = 00 02 00 00 52 00 00 00 00 00

    ..10 bytes

  • when exactly is boot0.js executed

    Just at startup. However because Bangle.js tears everything down between apps, that's basically every time you start a new app.

    so when HID is not enabled in settings while starting and boot0.js is only executed on start the NRF.setServices() never happens, correct?

    ish. The second you leave settings after setting HID to true, it's a new app (the clock) starting so it then gets called.

    What Linux receives is:

    Interesting. So what actual bytes are you sending in order to get that?

    edit: Also thanks for the parser - that's really handy!

  • I have sent:

    [2,0,0,0x52,0,0,0,0,0]

    (basically the same as Linux displays, just without the leading zero)

  • The additional zero is inserted in bluez hog-lib.c in the "if (hog->has_report_id)"-block . Unfortunately "report->id" is zero at this time.

  • Update: I got it working by hacking my bluez to not add this extra zero, but this is only a workaround. I posted the question on the linux-bluetooth mailing list, but so far no one seems to be interested, so this issue will probably persist for quite a while.

  • Thanks for trying to chase this down. It's an odd one - since it works on Windows/Mac OS/Android/iOS I'm inclined to think you may have stumbled upon a bug in the driver?

  • Actually there's an issue open here to add a descriptor for joysticks: https://github.com/espruino/BangleApps/i­ssues/349

    Am I right in thinking that the issue with Linux is really having the two devices rolled into one? If we allow HID to set to 'Just Keyboard' rather than 'Keyboard + multimedia', it'd fix it for you?

  • For me it is a bug, but I do not know the bt spec well enough to declare it as one.

    -

    Given that this is my issue I have seen it ;)

    Setting only one device in the descriptor is not enough. All apps would need change to not include the first report id byte.

  • All apps would need change to not include the first report id byte.

    But if they did, that'd fix it? Given there are only a few HID apps right now, that'd be a reasonably straightforward fix.

  • Yes it will avoid that problem, with the downside that sometimes my bt host does not pick up the change of the hid descriptor.
    Let me check again if these were isolated incidents because I had the descriptor wrong or reproducible.

  • If you install Bootloader/Settings/HID keyboard from https://espruino.github.io/BangleApps/ (the developer apps repo) now then I think you'll be able to change to HID : Kbrd in settings. Hopefully it'll pair and then work fine for you :)

  • Thanks, I'm going to test it.

  • I like the flexible setting, I commented it in the github report.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How to use Bluetooth hid

Posted by Avatar for Humpelstilzchen @Humpelstilzchen

Actions