Hopefully over the next few days, I am going to try to migrate some of the SDP Bluetooth code from the test sketch object into some part(s) of the USBHost Bluetooth code.
I am still not sure of the best way to factor/refactor the functionality the cleanest but compatible way.
Right now, mostly concentrating on the Keyboard support, but this can easily spill over into several other places.
Part one is to build in support for SDP protocol. I have some of that already in my fork/Branch, which can handle some of the query/responses. But the code to understand the data coming back is currently within my test sketches object. I will migrate some of that. But may start off with simplified version that can query for the SDP Report Descriptor.
I currently have 3 Bluetooth keyboards. I already know that with existing code base, we don't have any support in place to handle the Key state LEDS like (caps lock). Also we do not support Multi-media keys.
The best one is the Kenessis Freestyle 2 Blue: From my test sketch its descriptor looks like:
Code:
HID Report Descriptor (0x200059b0) size: 300
05 01 // Usage Page(1) - Generic Desktop
09 06 // Usage(6) -(Keyboard)
A1 01 // Collection(1) top Usage(10000)
85 01 // Report ID(1)
75 01 // Report Size(1)
95 08 // Report Count(8)
05 07 // Usage Page(7) - Keycode
19 E0 // Usage Minimum(e0) - (Left Control)
29 E7 // Usage Maximum(e7) - (Right GUI)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 08 // Report Size(8)
81 03 // Input(3) // (Constant, Variable, Absolute)
95 05 // Report Count(5)
75 01 // Report Size(1)
05 08 // Usage Page(8) - LEDs
19 01 // Usage Minimum(1) -
29 05 // Usage Maximum(5) -
91 02 // Output(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 03 // Report Size(3)
91 03 // Output(3) // (Constant, Variable, Absolute)
95 06 // Report Count(6)
75 08 // Report Size(8)
15 00 // Logical Minimum(0)
26 FF 00 // Logical maximum(ff)
05 07 // Usage Page(7) - Keycode
19 00 // Usage Minimum(0) - (Keycode 0)
29 FF // Usage Maximum(ff) - (Keycode 255)
81 00 // Input(0) // (Data, Array, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 02 // Report ID(2)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 12 // Report Count(12)
0A 23 02 // Usage(223) -(AC Home)
0A 8A 01 // Usage(18a) -(AL Email Reader)
0A 24 02 // Usage(224) -(AC Back)
0A 25 02 // Usage(225) -(AC Forward)
0A 21 02 // Usage(221) -(AC Search)
09 CD // Usage(cd) -(Pause/Continue)
09 B7 // Usage(b7) -(Stop)
09 B6 // Usage(b6) -(Scan Previous Track)
09 B5 // Usage(b5) -(Scan Next Track)
09 E9 // Usage(e9) -(Volume Up)
09 EA // Usage(ea) -(Volume Down)
09 E2 // Usage(e2) -(Mute)
0A 94 01 // Usage(194) -(AL Local Machine Browser)
0A 92 01 // Usage(192) -(AL Calculator)
0A 83 01 // Usage(183) -(AL Consumer Control Configuration)
0A 2A 02 // Usage(22a) -(AC Bookmarks)
0A 26 02 // Usage(226) -(AC Stop)
0A 27 02 // Usage(227) -(AC Refresh)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 06 // Report Size(6)
81 03 // Input(3) // (Constant, Variable, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 03 // Report ID(3)
05 01 // Usage Page(1) - Generic Desktop
09 06 // Usage(6) -(Keyboard)
A1 02 // Collection(2)
05 06 // Usage Page(6) - Generic Device Controls
09 20 // Usage(20) -(Battery Strength)
15 00 // Logical Minimum(0)
26 FF 00 // Logical maximum(ff)
75 08 // Report Size(8)
95 01 // Report Count(1)
81 02 // Input(2) // (Data, Variable, Absolute)
C0 // End Collection
C0 // End Collection
05 01 // Usage Page(1) - Generic Desktop
09 80 // Usage(80) -(?)
A1 01 // Collection(1) top Usage(10080)
85 04 // Report ID(4)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 01 // Report Count(1)
09 82 // Usage(82) -(System Sleep)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 07 // Report Size(7)
81 03 // Input(3) // (Constant, Variable, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 05 // Report ID(5)
05 01 // Usage Page(1) - Generic Desktop
09 06 // Usage(6) -(Keyboard)
A1 02 // Collection(2)
06 00 FF // Usage Page(ff00) - Vendor Defined
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 02 // Report Count(2)
0A 03 FE // Usage(fe03) -
0A 04 FE // Usage(fe04) -
81 02 // Input(2) // (Data, Variable, Absolute)
95 06 // Report Count(6)
81 03 // Input(3) // (Constant, Variable, Absolute)
C0 // End Collection
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 FF // Report ID(ff)
05 06 // Usage Page(6) - Generic Device Controls
95 01 // Report Count(1)
75 02 // Report Size(2)
19 24 // Usage Minimum(24) - (Security Code Entered)
29 26 // Usage Maximum(26) - (Security Code cleared)(?)
81 02 // Input(2) // (Data, Variable, Absolute)
75 06 // Report Size(6)
81 01 // Input(1) // (Constant, Array, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 11 // Report ID(11)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 03 // Report Count(3)
81 01 // Input(1) // (Constant, Array, Absolute)
75 01 // Report Size(1)
95 01 // Report Count(1)
05 0C // Usage Page(c) - Consumer
09 B8 // Usage(b8) -(Eject)
81 02 // Input(2) // (Data, Variable, Absolute)
06 FF 00 // Usage Page(ff) - Other ?
09 03 // Usage(3) -
81 02 // Input(2) // (Data, Variable, Absolute)
75 01 // Report Size(1)
95 03 // Report Count(3)
81 01 // Input(1) // (Constant, Array, Absolute)
C0 // End Collection
I also have the NyKO, that attaches to a PS4 controller. Nothing that interesting with that one.
The most interesting one to talk about is the Rii one which also has a small touchpad...
Code:
HID Report Descriptor (0x200059b0) size: 332
05 01 // Usage Page(1) - Generic Desktop
09 06 // Usage(6) -(Keyboard)
A1 01 // Collection(1) top Usage(10000)
85 01 // Report ID(1)
75 01 // Report Size(1)
95 08 // Report Count(8)
05 07 // Usage Page(7) - Keycode
19 E0 // Usage Minimum(e0) - (Left Control)
29 E7 // Usage Maximum(e7) - (Right GUI)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 08 // Report Size(8)
81 03 // Input(3) // (Constant, Variable, Absolute)
95 05 // Report Count(5)
75 01 // Report Size(1)
05 08 // Usage Page(8) - LEDs
19 01 // Usage Minimum(1) -
29 05 // Usage Maximum(5) -
91 02 // Output(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 03 // Report Size(3)
91 03 // Output(3) // (Constant, Variable, Absolute)
95 06 // Report Count(6)
75 08 // Report Size(8)
15 00 // Logical Minimum(0)
26 FF 00 // Logical maximum(ff)
05 07 // Usage Page(7) - Keycode
19 00 // Usage Minimum(0) - (Keycode 0)
29 FF // Usage Maximum(ff) - (Keycode 255)
81 00 // Input(0) // (Data, Array, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 02 // Report ID(2)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 12 // Report Count(12)
0A 23 02 // Usage(223) -(AC Home)
0A 83 01 // Usage(183) -(AL Consumer Control Configuration)
0A 0A 03 // Usage(30a) -(?)
0A 0B 03 // Usage(30b) -(?)
0A 05 03 // Usage(305) -(?)
0A 8A 01 // Usage(18a) -(AL Email Reader)
0A 21 02 // Usage(221) -(AC Search)
09 B6 // Usage(b6) -(Scan Previous Track)
09 CD // Usage(cd) -(Pause/Continue)
09 B5 // Usage(b5) -(Scan Next Track)
09 E2 // Usage(e2) -(Mute)
09 EA // Usage(ea) -(Volume Down)
09 E9 // Usage(e9) -(Volume Up)
09 B7 // Usage(b7) -(Stop)
09 40 // Usage(40) -(Menu)
0A 83 01 // Usage(183) -(AL Consumer Control Configuration)
0A 02 03 // Usage(302) -(?)
0A 07 03 // Usage(307) -(?)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 06 // Report Size(6)
81 03 // Input(3) // (Constant, Variable, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 03 // Report ID(3)
05 01 // Usage Page(1) - Generic Desktop
09 06 // Usage(6) -(Keyboard)
A1 02 // Collection(2)
05 06 // Usage Page(6) - Generic Device Controls
09 20 // Usage(20) -(Battery Strength)
15 00 // Logical Minimum(0)
26 FF 00 // Logical maximum(ff)
75 08 // Report Size(8)
95 01 // Report Count(1)
81 02 // Input(2) // (Data, Variable, Absolute)
C0 // End Collection
C0 // End Collection
05 01 // Usage Page(1) - Generic Desktop
09 80 // Usage(80) -(?)
A1 01 // Collection(1) top Usage(10080)
85 04 // Report ID(4)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 01 // Report Count(1)
09 82 // Usage(82) -(System Sleep)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 07 // Report Size(7)
81 03 // Input(3) // (Constant, Variable, Absolute)
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 05 // Report ID(5)
05 01 // Usage Page(1) - Generic Desktop
09 06 // Usage(6) -(Keyboard)
A1 02 // Collection(2)
06 00 FF // Usage Page(ff00) - Vendor Defined
25 01 // Logical maximum(1)
75 01 // Report Size(1)
95 02 // Report Count(2)
0A 03 FE // Usage(fe03) -
0A 04 FE // Usage(fe04) -
81 02 // Input(2) // (Data, Variable, Absolute)
95 06 // Report Count(6)
81 03 // Input(3) // (Constant, Variable, Absolute)
C0 // End Collection
C0 // End Collection
05 01 // Usage Page(1) - Generic Desktop
09 02 // Usage(2) -(Mouse)
A1 01 // Collection(1) top Usage(10000)
85 08 // Report ID(8)
09 01 // Usage(1) -(?)
A1 00 // Collection(0)
05 09 // Usage Page(9) - Button
19 01 // Usage Minimum(1) - (BUTTON 1)
29 05 // Usage Maximum(5) - (BUTTON 5)
15 00 // Logical Minimum(0)
25 01 // Logical maximum(1)
95 05 // Report Count(5)
75 01 // Report Size(1)
81 02 // Input(2) // (Data, Variable, Absolute)
95 01 // Report Count(1)
75 03 // Report Size(3)
81 01 // Input(1) // (Constant, Array, Absolute)
05 01 // Usage Page(1) - Generic Desktop
09 30 // Usage(30) -(X)
09 31 // Usage(31) -(Y)
16 01 80 // Logical Minimum(8001)
26 FF 7F // Logical maximum(7fff)
75 10 // Report Size(10)
95 02 // Report Count(2)
81 06 // Input(6) // (Data, Variable, Relative)
09 38 // Usage(38) -(Wheel)
15 81 // Logical Minimum(81)
25 7F // Logical maximum(7f)
75 08 // Report Size(8)
95 01 // Report Count(1)
81 06 // Input(6) // (Data, Variable, Relative)
05 0C // Usage Page(c) - Consumer
0A 38 02 // Usage(238) -(AC Pan)
95 01 // Report Count(1)
81 06 // Input(6) // (Data, Variable, Relative)
C0 // End Collection
C0 // End Collection
05 0C // Usage Page(c) - Consumer
09 01 // Usage(1) -(Consumer Controls)
A1 01 // Collection(1) top Usage(c0000)
85 FF // Report ID(ff)
05 06 // Usage Page(6) - Generic Device Controls
95 01 // Report Count(1)
75 02 // Report Size(2)
19 24 // Usage Minimum(24) - (Security Code Entered)
29 26 // Usage Maximum(26) - (Security Code cleared)(?)
81 02 // Input(2) // (Data, Variable, Absolute)
75 06 // Report Size(6)
81 01 // Input(1) // (Constant, Array, Absolute)
C0 // End Collection
Note: all three of these will currently be claimed by the Keyboard object (assuming you have a Bluetooth object, and they are paired...)
However, with my test sketch they are claimed by my own BTHIDDumper class, which I added in a slightly stripped down version of the HID parser from HID.cpp.
Stripped down in that it does not ask others to claim top level reports. It assumes its own class will process the HID stuff.
Note, this object is seeing multiple different types of HID messages:
For example: Keyboard:
Like a Shift Z -
Code:
(BTHID(0x2000588a, 9): 01 02 00 1D 00 00 00 00 00
Begin topusage:10000 type:2 min:0 max:1 indent:0
usage=700E0, value=0 (Left Control)
usage=700E1, value=1 (Left Shift)
usage=700E2, value=0 (Left Alt)
usage=700E3, value=0 (Left GUI)
usage=700E4, value=0 (Right Control)
usage=700E5, value=0 (Right Shift)
usage=700E6, value=0 (Right Alt)
usage=700E7, value=0 (Right GUI)
Begin topusage:10000 type:0 min:0 max:255 indent:1
usage=7001D, value=1 (z and Z)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
END:
END:
Battery Strength:
Code:
(BTHID(0x2000588a, 8): 03 74 CC C5 0A 23 22 79
Begin topusage:c0000 type:2 min:0 max:255 indent:0
usage=60020, value=116 :t(Battery Strength)
END:
Multi media key, in this case Mute:
Code:
(BTHID(0x2000588a, 9): 01 00 00 00 00 00 00 00 00
Begin topusage:10000 type:2 min:0 max:1 indent:0
usage=700E0, value=0 (Left Control)
usage=700E1, value=0 (Left Shift)
usage=700E2, value=0 (Left Alt)
usage=700E3, value=0 (Left GUI)
usage=700E4, value=0 (Right Control)
usage=700E5, value=0 (Right Shift)
usage=700E6, value=0 (Right Alt)
usage=700E7, value=0 (Right GUI)
Begin topusage:10000 type:0 min:0 max:255 indent:1
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
usage=70000, value=1 (Keycode 0)
END:
END:
(BTHID(0x2000588a, 5): 02 00 04 00 00
Begin topusage:c0000 type:2 min:0 max:1 indent:0
usage=C0223, value=0 (AC Home)
usage=C0183, value=0 (AL Consumer Control Configuration)
usage=C030A, value=0 (?)
usage=C030B, value=0 (?)
usage=C0305, value=0 (?)
usage=C018A, value=0 (AL Email Reader)
usage=C0221, value=0 (AC Search)
usage=C00B6, value=0 (Scan Previous Track)
usage=C00CD, value=0 (Pause/Continue)
usage=C00B5, value=0 (Scan Next Track)
usage=C00E2, value=1 (Mute)
usage=C00EA, value=0 (Volume Down)
usage=C00E9, value=0 (Volume Up)
usage=C00B7, value=0 (Stop)
usage=C0040, value=0 (Menu)
usage=C0183, value=0 (AL Consumer Control Configuration)
usage=C0302, value=0 (?)
usage=C0307, value=0 (?)
END:
And trackpad/Mouse like messages, example pressing the left mouse button:
Code:
(BTHID(0x2000588a, 8): 08 01 00 00 00 00 00 00
Begin topusage:10000 type:2 min:0 max:1 indent:0
usage=90001, value=1 (BUTTON 1)
usage=90002, value=0 (BUTTON 2)
usage=90003, value=0 (BUTTON 3)
usage=90004, value=0 (BUTTON 4)
usage=90005, value=0 (BUTTON 5)
Begin topusage:10000 type:6 min:-32767 max:32767 indent:1
usage=10030, value=0 (X)
usage=10031, value=0 (Y)
Begin topusage:10000 type:6 min:-127 max:127 indent:2
usage=10038, value=0 (Wheel)
Begin topusage:10000 type:6 min:-127 max:127 indent:2
usage=C0238, value=0 (AC Pan)
END:
END:
And Touch pad
Code:
(BTHID(0x2000588a, 8): 08 00 FA FF F6 FF 00 00
Begin topusage:10000 type:2 min:0 max:1 indent:0
usage=90001, value=0 (BUTTON 1)
usage=90002, value=0 (BUTTON 2)
usage=90003, value=0 (BUTTON 3)
usage=90004, value=0 (BUTTON 4)
usage=90005, value=0 (BUTTON 5)
Begin topusage:10000 type:6 min:-32767 max:32767 indent:1
usage=10030, value=-6 (X)
usage=10031, value=-10 (Y)
Begin topusage:10000 type:6 min:-127 max:127 indent:2
usage=10038, value=0 (Wheel)
Begin topusage:10000 type:6 min:-127 max:127 indent:2
usage=C0238, value=0 (AC Pan)
END:
END:
------------------------------------------------------------------------
So real question again how to factor this.
Again all three are claimed by keyboard as their Bluetooth class is: BTHIDDumpController Controller::claim_bluetooth - Class 540
The 0x40 bit says keyboard. Note we are not check maybe 100% accurate as if it were 0x5c0 we would claim it or Mouse would claim it
as the 0x80 is is Mouse, but 0xc0 bottom byte means combined, although I have not seen this case.
But in theory there could be top level object that claims these objects, like the USBHIDParser, Which would then process the parsing of the report and asking all of the objects, derived from some class, like the current BTHIDInput.
So assume that BluetoothController object parses HID. Should all of the Top Level objects go to the one object that claims a BT object now, or should it work like HID and for each top level, it asks each of the BTHIDInput objects if they want this report and then remembers which ones...
Or should we completly refactor, and USBHIDParser should also Handle BTHID parsing...
But that might turn everything on their ear!
For now, thinking baby steps. Maybe like the Keyboard controller code, when it claims the BT, it can ask BT if this object has a HID Descriptor, if it does it saves it away, and then when BT calls it with an Input Record it says I have a HID REPORT, call off to the Parser... And have similar named callbacks to handle each input field...
Sorry I know sort of rambling.
Thoughts?