Skip to content

Commit 60e93f3

Browse files
BLE HID composite device support (#1587)
* Adapted all libraries to support multiprotocol HID over BT & BLE * Added ATT DB depending on setup; still no success with working connection * Added hids_device from BTStack develop branch as override * Fixing the GATT handle patching, added working ATT DB * ran astyle on example * Updates in BLE implementation; WORKING! (but only if all are activated). Removed sdkoverride again, doesn't work. * Moved ATT DB handles to correct places * Finally functioning for Mouse+KBD+Joy, and each individual * Cleaned up code & ran astyle * Added sdkoverrides to pull develop functions from BTSTack * Changed a few typos by BTStack to run codespell successfully * Ran astyle on sdkoverride files * Added some #if guards for including BTSTack file only if BT is enabled * Fixed Feature Report value characteristics handle assignment; fixed too long HID report * Ran astyle
1 parent 7e8fcc5 commit 60e93f3

File tree

16 files changed

+4523
-87
lines changed

16 files changed

+4523
-87
lines changed

cores/rp2040/sdkoverride/att_db.c

Lines changed: 1863 additions & 0 deletions
Large diffs are not rendered by default.

cores/rp2040/sdkoverride/att_db.h

Lines changed: 443 additions & 0 deletions
Large diffs are not rendered by default.

cores/rp2040/sdkoverride/bluetooth.h

Lines changed: 926 additions & 0 deletions
Large diffs are not rendered by default.

cores/rp2040/sdkoverride/hids_device.c

Lines changed: 524 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
Copyright (C) 2014 BlueKitchen GmbH
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions
6+
are met:
7+
8+
1. Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
2. Redistributions in binary form must reproduce the above copyright
11+
notice, this list of conditions and the following disclaimer in the
12+
documentation and/or other materials provided with the distribution.
13+
3. Neither the name of the copyright holders nor the names of
14+
contributors may be used to endorse or promote products derived
15+
from this software without specific prior written permission.
16+
4. Any redistribution, use, or modification is done solely for
17+
personal benefit and not for any commercial purpose or for
18+
monetary gain.
19+
20+
THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21+
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23+
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24+
GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27+
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28+
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30+
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31+
SUCH DAMAGE.
32+
33+
Please inquire about commercial licensing options at
34+
35+
36+
*/
37+
38+
/**
39+
@title HID Service Server
40+
41+
*/
42+
43+
#ifndef HIDS_DEVICE_H
44+
#define HIDS_DEVICE_H
45+
46+
#if defined ENABLE_CLASSIC
47+
48+
#include <sdkoverride/att_db.h>
49+
#include <stdint.h>
50+
#include "btstack_defines.h"
51+
#include "btstack_hid.h"
52+
#include "bluetooth.h"
53+
54+
#if defined __cplusplus
55+
extern "C" {
56+
#endif
57+
58+
/* API_START */
59+
60+
typedef struct {
61+
uint16_t value_handle;
62+
uint16_t client_configuration_handle;
63+
uint16_t client_configuration_value;
64+
65+
hid_report_type_t type;
66+
uint16_t id;
67+
} hids_device_report_t;
68+
69+
/**
70+
@text Implementation of the GATT HIDS Device
71+
To use with your application, add '#import <hids.gatt>' to your .gatt file
72+
*/
73+
74+
/**
75+
@brief Set up HIDS Device with single INPUT, OUTPUT and FEATURE report
76+
*/
77+
void hids_device_init(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size);
78+
79+
/**
80+
@brief Set up HIDS Device for multiple instances of INPUT, OUTPUT and FEATURE reports
81+
*/
82+
void hids_device_init_with_storage(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
83+
uint16_t num_reports, hids_device_report_t * report_storage);
84+
85+
/**
86+
@brief Register callback for the HIDS Device client.
87+
@param callback
88+
*/
89+
void hids_device_register_packet_handler(btstack_packet_handler_t callback);
90+
91+
/**
92+
@brief Request can send now event to send HID Report
93+
Generates an HIDS_SUBEVENT_CAN_SEND_NOW subevent
94+
@param hid_cid
95+
*/
96+
void hids_device_request_can_send_now_event(hci_con_handle_t con_handle);
97+
98+
/**
99+
@brief Send HID Input Report for Report ID
100+
@param con_handle
101+
@param report_id
102+
@param report
103+
@param report_len
104+
@returns status
105+
*/
106+
uint8_t hids_device_send_input_report_for_id(hci_con_handle_t con_handle, uint16_t report_id, const uint8_t * report, uint16_t report_len);
107+
108+
/**
109+
@brief Send HID Input Report for first Input Report
110+
@param con_handle
111+
@param report
112+
@param report_len
113+
@returns status
114+
*/
115+
uint8_t hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);
116+
117+
/**
118+
@brief Send HID Boot Mouse Input Report
119+
@param con_handle
120+
@param report
121+
@param report_len
122+
@returns status
123+
*/
124+
uint8_t hids_device_send_boot_mouse_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);
125+
126+
/**
127+
@brief Send HID Boot Mouse Input Report
128+
@param con_handle
129+
@param report
130+
@param report_len
131+
@returns status
132+
*/
133+
uint8_t hids_device_send_boot_keyboard_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);
134+
135+
/* API_END */
136+
137+
#if defined __cplusplus
138+
}
139+
#endif
140+
141+
#endif
142+
143+
#endif
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
#include "HID_Bluetooth.h"
2+
3+
//setup the report map.
4+
//more generic function to be used with BLE & BT Classis
5+
void __SetupHIDreportmap(void (*WeakMouse)(), void (*WeakKeyboard)(), void (*WeakJoystick)(), bool absMouse, uint16_t *report_size, uint8_t **reportmap) {
6+
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
7+
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
8+
uint8_t desc_hid_report_absmouse[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(1)) };
9+
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(1)) };
10+
uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)), TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(2)) };
11+
int size = 0;
12+
13+
//enable to debug the individual report maps
14+
#if 0
15+
Serial.printf("Report mouse: %d bytes\n", sizeof(desc_hid_report_mouse));
16+
for (uint16_t i = 0; i < sizeof(desc_hid_report_mouse); i++) {
17+
Serial.print(desc_hid_report_mouse[i], HEX);
18+
Serial.print(" ");
19+
if (i % 4 == 3) {
20+
Serial.print("\n");
21+
}
22+
}
23+
Serial.printf("Report absmouse: %d bytes\n", sizeof(desc_hid_report_absmouse));
24+
for (uint16_t i = 0; i < sizeof(desc_hid_report_absmouse); i++) {
25+
Serial.print(desc_hid_report_absmouse[i], HEX);
26+
Serial.print(" ");
27+
if (i % 4 == 3) {
28+
Serial.print("\n");
29+
}
30+
}
31+
Serial.printf("Report kbd: %d bytes\n", sizeof(desc_hid_report_keyboard));
32+
for (uint16_t i = 0; i < sizeof(desc_hid_report_keyboard); i++) {
33+
Serial.print(desc_hid_report_keyboard[i], HEX);
34+
Serial.print(" ");
35+
if (i % 4 == 3) {
36+
Serial.print("\n");
37+
}
38+
}
39+
Serial.printf("Report joystick: %d bytes\n", sizeof(desc_hid_report_joystick));
40+
for (uint16_t i = 0; i < sizeof(desc_hid_report_joystick); i++) {
41+
Serial.print(desc_hid_report_joystick[i], HEX);
42+
Serial.print(" ");
43+
if (i % 4 == 3) {
44+
Serial.print("\n");
45+
}
46+
}
47+
#endif
48+
49+
//accumulate the size of all used HID report descriptors
50+
if (WeakKeyboard) {
51+
size += sizeof(desc_hid_report_keyboard);
52+
}
53+
if (WeakMouse && absMouse == false) {
54+
size += sizeof(desc_hid_report_mouse);
55+
} else if (WeakMouse && absMouse == true) {
56+
size += sizeof(desc_hid_report_absmouse);
57+
}
58+
if (WeakJoystick) {
59+
size += sizeof(desc_hid_report_joystick);
60+
}
61+
62+
//no HID used at all
63+
if (size == 0) {
64+
*report_size = 0;
65+
return;
66+
}
67+
68+
//allocate the "real" HID report descriptor
69+
*reportmap = (uint8_t *)malloc(size);
70+
if (*reportmap) {
71+
*report_size = size;
72+
73+
//now copy the descriptors
74+
75+
//1.) keyboard descriptor, if requested
76+
if (WeakKeyboard) {
77+
memcpy(*reportmap, desc_hid_report_keyboard, sizeof(desc_hid_report_keyboard));
78+
}
79+
80+
//2.) mouse descriptor, if necessary. Additional offset & new array is necessary if there is a keyboard.
81+
if (WeakMouse && absMouse == false) {
82+
//determine if we need an offset (USB keyboard is installed)
83+
if (WeakKeyboard) {
84+
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(3)) };
85+
memcpy(*reportmap + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
86+
} else {
87+
memcpy(*reportmap, desc_hid_report_mouse, sizeof(desc_hid_report_mouse));
88+
}
89+
} else if (WeakMouse && absMouse == true) {
90+
//determine if we need an offset (USB keyboard is installed)
91+
if (WeakKeyboard) {
92+
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(3)) };
93+
memcpy(*reportmap + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
94+
} else {
95+
memcpy(*reportmap, desc_hid_report_absmouse, sizeof(desc_hid_report_absmouse));
96+
}
97+
}
98+
99+
//3.) joystick descriptor. 2 additional checks are necessary for mouse and/or keyboard
100+
if (WeakJoystick) {
101+
uint8_t reportid = 1;
102+
int offset = 0;
103+
if (WeakKeyboard) {
104+
reportid += 2;
105+
offset += sizeof(desc_hid_report_keyboard);
106+
}
107+
if (WeakMouse && absMouse == false) {
108+
reportid++;
109+
offset += sizeof(desc_hid_report_mouse);
110+
} else if (WeakMouse && absMouse == true) {
111+
reportid++;
112+
offset += sizeof(desc_hid_report_absmouse);
113+
}
114+
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(reportid)) };
115+
memcpy(*reportmap + offset, desc_local, sizeof(desc_local));
116+
}
117+
118+
//enable for debugging the final report map
119+
#if 0
120+
Serial.begin(115200);
121+
Serial.printf("Final map: %d bytes\n", size);
122+
for (uint16_t i = 0; i < size; i++) {
123+
Serial.print(*reportmap[i], HEX);
124+
Serial.print(" ");
125+
if (i % 4 == 3) {
126+
Serial.print("\n");
127+
}
128+
}
129+
#endif
130+
} else {
131+
Serial.println("No report map pointer provided!");
132+
}
133+
}
134+
135+
136+
//get Class of Device number for starting HID, type depends on activated libraries
137+
uint16_t __BTGetCOD() {
138+
//mouse only
139+
if (__BTInstallMouse && !__BTInstallKeyboard && !__BTInstallJoystick) {
140+
return 0x2580;
141+
}
142+
//keyboard only
143+
if (__BTInstallKeyboard && !__BTInstallMouse && !__BTInstallJoystick) {
144+
return 0x2540;
145+
}
146+
//joystick only
147+
if (__BTInstallJoystick && !__BTInstallKeyboard && !__BTInstallMouse) {
148+
return 0x2508;
149+
}
150+
//any other combination will return "combo device"
151+
return 0x25C0;
152+
}
153+
154+
//get Class of Device number for starting HID, type depends on activated libraries
155+
uint16_t __BLEGetAppearance() {
156+
//mouse only
157+
if (__BLEInstallMouse && !__BLEInstallKeyboard && !__BLEInstallJoystick) {
158+
return 0x03C2;
159+
}
160+
//keyboard only
161+
if (__BLEInstallKeyboard && !__BLEInstallMouse && !__BLEInstallJoystick) {
162+
return 0x03C1;
163+
}
164+
//joystick only
165+
if (__BLEInstallJoystick && !__BLEInstallMouse && !__BLEInstallKeyboard) {
166+
return 0x03C4;
167+
}
168+
//any other combination will return "generic HID"
169+
return 0x03C0;
170+
}
171+
172+
//keyboard report id is always 1 (compatibility with iOS)
173+
int __BTGetKeyboardReportID() {
174+
return 1;
175+
}
176+
177+
//
178+
int __BTGetMouseReportID() {
179+
return __BTInstallKeyboard ? 3 : 1;
180+
}
181+
182+
int __BTGetJoystickReportID() {
183+
int i = 1;
184+
if (__BTInstallKeyboard) {
185+
i += 2;
186+
}
187+
if (__BTInstallMouse) {
188+
i++;
189+
}
190+
return i;
191+
}
192+
193+
int __BLEGetKeyboardReportID() {
194+
return 1;
195+
}
196+
197+
int __BLEGetMouseReportID() {
198+
return __BLEInstallKeyboard ? 3 : 1;
199+
}
200+
201+
int __BLEGetFeatureReportID() {
202+
int feature = 1;
203+
if (__BLEInstallKeyboard) {
204+
feature += 2;
205+
}
206+
if (__BLEInstallMouse) {
207+
feature ++;
208+
}
209+
if (__BLEInstallJoystick) {
210+
feature ++;
211+
}
212+
return feature;
213+
}
214+
215+
int __BLEGetJoystickReportID() {
216+
int i = 1;
217+
if (__BLEInstallKeyboard) {
218+
i += 2;
219+
}
220+
if (__BLEInstallMouse) {
221+
i++;
222+
}
223+
return i;
224+
}

0 commit comments

Comments
 (0)