Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLE HID composite devices #1587

Merged
merged 30 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6b0e2ce
Adapted all libraries to support multiprotocol HID over BT & BLE
benjaminaigner Jun 9, 2023
22ad3fb
Merge branch 'earlephilhower:master' into BLEHID_Composite
Jun 19, 2023
fdd495d
Added ATT DB depending on setup; still no success with working connec…
Jun 19, 2023
6fbcef1
Merge branch 'earlephilhower:master' into BLEHID_Composite
Jun 27, 2023
222edd0
Merge branch 'earlephilhower:master' into BLEHID_Composite
Jun 28, 2023
4b97776
Added hids_device from BTStack develop branch as override
Jun 28, 2023
980ba4b
Fixing the GATT handle patching, added working ATT DB
Jun 28, 2023
3d3ed9e
ran astyle on example
Jun 28, 2023
4a83815
Updates in BLE implementation; WORKING! (but only if all are activate…
Jun 28, 2023
233f898
Moved ATT DB handles to correct places
benjaminaigner Jul 11, 2023
db78851
Finally functioning for Mouse+KBD+Joy, and each individual
benjaminaigner Jul 11, 2023
43a1f8b
Cleaned up code & ran astyle
benjaminaigner Jul 12, 2023
a563342
Merge branch 'earlephilhower:master' into BLEHID_Composite
Jul 12, 2023
dbeb74b
Added sdkoverrides to pull develop functions from BTSTack
benjaminaigner Jul 12, 2023
5ed1597
Merge branch 'BLEHID_Composite' of https://github.com/benjaminaigner/…
benjaminaigner Jul 12, 2023
42a27d4
Changed a few typos by BTStack to run codespell successfully
benjaminaigner Jul 14, 2023
828eedd
Ran astyle on sdkoverride files
benjaminaigner Jul 14, 2023
8b67b0e
Added some #if guards for including BTSTack file only if BT is enabled
benjaminaigner Jul 14, 2023
517e177
Merge branch 'master' into BLEHID_Composite
benjaminaigner Jul 14, 2023
a935fac
Merge branch 'master' into BLEHID_Composite
earlephilhower Jul 14, 2023
429b83e
Merge branch 'master' into BLEHID_Composite
earlephilhower Jul 14, 2023
e79d9ac
Merge branch 'master' into BLEHID_Composite
earlephilhower Jul 17, 2023
d1d19ef
Merge branch 'master' into BLEHID_Composite
earlephilhower Aug 25, 2023
0a35dbf
Merge branch 'earlephilhower:master' into BLEHID_Composite
Sep 12, 2023
814d7d7
Merge branch 'master' into BLEHID_Composite
earlephilhower Sep 15, 2023
f4fab1d
Merge branch 'master' into BLEHID_Composite
earlephilhower Sep 15, 2023
20889f1
Fixed Feature Report value characteristics handle assignment; fixed t…
benjaminaigner Sep 18, 2023
7baeda3
Ran astyle
benjaminaigner Sep 18, 2023
f4bd205
Merge branch 'master' into BLEHID_Composite
benjaminaigner Sep 18, 2023
563ccff
Merge branch 'master' into BLEHID_Composite
earlephilhower Sep 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,863 changes: 1,863 additions & 0 deletions cores/rp2040/sdkoverride/att_db.c

Large diffs are not rendered by default.

443 changes: 443 additions & 0 deletions cores/rp2040/sdkoverride/att_db.h

Large diffs are not rendered by default.

926 changes: 926 additions & 0 deletions cores/rp2040/sdkoverride/bluetooth.h

Large diffs are not rendered by default.

524 changes: 524 additions & 0 deletions cores/rp2040/sdkoverride/hids_device.c

Large diffs are not rendered by default.

143 changes: 143 additions & 0 deletions cores/rp2040/sdkoverride/hids_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
Copyright (C) 2014 BlueKitchen GmbH

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
4. Any redistribution, use, or modification is done solely for
personal benefit and not for any commercial purpose or for
monetary gain.

THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

Please inquire about commercial licensing options at
[email protected]

*/

/**
@title HID Service Server

*/

#ifndef HIDS_DEVICE_H
#define HIDS_DEVICE_H

#if defined ENABLE_CLASSIC

#include <sdkoverride/att_db.h>
#include <stdint.h>
#include "btstack_defines.h"
#include "btstack_hid.h"
#include "bluetooth.h"

#if defined __cplusplus
extern "C" {
#endif

/* API_START */

typedef struct {
uint16_t value_handle;
uint16_t client_configuration_handle;
uint16_t client_configuration_value;

hid_report_type_t type;
uint16_t id;
} hids_device_report_t;

/**
@text Implementation of the GATT HIDS Device
To use with your application, add '#import <hids.gatt>' to your .gatt file
*/

/**
@brief Set up HIDS Device with single INPUT, OUTPUT and FEATURE report
*/
void hids_device_init(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size);

/**
@brief Set up HIDS Device for multiple instances of INPUT, OUTPUT and FEATURE reports
*/
void hids_device_init_with_storage(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
uint16_t num_reports, hids_device_report_t * report_storage);

/**
@brief Register callback for the HIDS Device client.
@param callback
*/
void hids_device_register_packet_handler(btstack_packet_handler_t callback);

/**
@brief Request can send now event to send HID Report
Generates an HIDS_SUBEVENT_CAN_SEND_NOW subevent
@param hid_cid
*/
void hids_device_request_can_send_now_event(hci_con_handle_t con_handle);

/**
@brief Send HID Input Report for Report ID
@param con_handle
@param report_id
@param report
@param report_len
@returns status
*/
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);

/**
@brief Send HID Input Report for first Input Report
@param con_handle
@param report
@param report_len
@returns status
*/
uint8_t hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);

/**
@brief Send HID Boot Mouse Input Report
@param con_handle
@param report
@param report_len
@returns status
*/
uint8_t hids_device_send_boot_mouse_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);

/**
@brief Send HID Boot Mouse Input Report
@param con_handle
@param report
@param report_len
@returns status
*/
uint8_t hids_device_send_boot_keyboard_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);

/* API_END */

#if defined __cplusplus
}
#endif

#endif

#endif
224 changes: 224 additions & 0 deletions libraries/HID_Bluetooth/src/HID_Bluetooth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#include "HID_Bluetooth.h"

//setup the report map.
//more generic function to be used with BLE & BT Classis
void __SetupHIDreportmap(void (*WeakMouse)(), void (*WeakKeyboard)(), void (*WeakJoystick)(), bool absMouse, uint16_t *report_size, uint8_t **reportmap) {
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
uint8_t desc_hid_report_absmouse[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(1)) };
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(1)) };
uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)), TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(2)) };
int size = 0;

//enable to debug the individual report maps
#if 0
Serial.printf("Report mouse: %d bytes\n", sizeof(desc_hid_report_mouse));
for (uint16_t i = 0; i < sizeof(desc_hid_report_mouse); i++) {
Serial.print(desc_hid_report_mouse[i], HEX);
Serial.print(" ");
if (i % 4 == 3) {
Serial.print("\n");
}
}
Serial.printf("Report absmouse: %d bytes\n", sizeof(desc_hid_report_absmouse));
for (uint16_t i = 0; i < sizeof(desc_hid_report_absmouse); i++) {
Serial.print(desc_hid_report_absmouse[i], HEX);
Serial.print(" ");
if (i % 4 == 3) {
Serial.print("\n");
}
}
Serial.printf("Report kbd: %d bytes\n", sizeof(desc_hid_report_keyboard));
for (uint16_t i = 0; i < sizeof(desc_hid_report_keyboard); i++) {
Serial.print(desc_hid_report_keyboard[i], HEX);
Serial.print(" ");
if (i % 4 == 3) {
Serial.print("\n");
}
}
Serial.printf("Report joystick: %d bytes\n", sizeof(desc_hid_report_joystick));
for (uint16_t i = 0; i < sizeof(desc_hid_report_joystick); i++) {
Serial.print(desc_hid_report_joystick[i], HEX);
Serial.print(" ");
if (i % 4 == 3) {
Serial.print("\n");
}
}
#endif

//accumulate the size of all used HID report descriptors
if (WeakKeyboard) {
size += sizeof(desc_hid_report_keyboard);
}
if (WeakMouse && absMouse == false) {
size += sizeof(desc_hid_report_mouse);
} else if (WeakMouse && absMouse == true) {
size += sizeof(desc_hid_report_absmouse);
}
if (WeakJoystick) {
size += sizeof(desc_hid_report_joystick);
}

//no HID used at all
if (size == 0) {
*report_size = 0;
return;
}

//allocate the "real" HID report descriptor
*reportmap = (uint8_t *)malloc(size);
if (*reportmap) {
*report_size = size;

//now copy the descriptors

//1.) keyboard descriptor, if requested
if (WeakKeyboard) {
memcpy(*reportmap, desc_hid_report_keyboard, sizeof(desc_hid_report_keyboard));
}

//2.) mouse descriptor, if necessary. Additional offset & new array is necessary if there is a keyboard.
if (WeakMouse && absMouse == false) {
//determine if we need an offset (USB keyboard is installed)
if (WeakKeyboard) {
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(3)) };
memcpy(*reportmap + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
} else {
memcpy(*reportmap, desc_hid_report_mouse, sizeof(desc_hid_report_mouse));
}
} else if (WeakMouse && absMouse == true) {
//determine if we need an offset (USB keyboard is installed)
if (WeakKeyboard) {
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(3)) };
memcpy(*reportmap + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
} else {
memcpy(*reportmap, desc_hid_report_absmouse, sizeof(desc_hid_report_absmouse));
}
}

//3.) joystick descriptor. 2 additional checks are necessary for mouse and/or keyboard
if (WeakJoystick) {
uint8_t reportid = 1;
int offset = 0;
if (WeakKeyboard) {
reportid += 2;
offset += sizeof(desc_hid_report_keyboard);
}
if (WeakMouse && absMouse == false) {
reportid++;
offset += sizeof(desc_hid_report_mouse);
} else if (WeakMouse && absMouse == true) {
reportid++;
offset += sizeof(desc_hid_report_absmouse);
}
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(reportid)) };
memcpy(*reportmap + offset, desc_local, sizeof(desc_local));
}

//enable for debugging the final report map
#if 0
Serial.begin(115200);
Serial.printf("Final map: %d bytes\n", size);
for (uint16_t i = 0; i < size; i++) {
Serial.print(*reportmap[i], HEX);
Serial.print(" ");
if (i % 4 == 3) {
Serial.print("\n");
}
}
#endif
} else {
Serial.println("No report map pointer provided!");
}
}


//get Class of Device number for starting HID, type depends on activated libraries
uint16_t __BTGetCOD() {
//mouse only
if (__BTInstallMouse && !__BTInstallKeyboard && !__BTInstallJoystick) {
return 0x2580;
}
//keyboard only
if (__BTInstallKeyboard && !__BTInstallMouse && !__BTInstallJoystick) {
return 0x2540;
}
//joystick only
if (__BTInstallJoystick && !__BTInstallKeyboard && !__BTInstallMouse) {
return 0x2508;
}
//any other combination will return "combo device"
return 0x25C0;
}

//get Class of Device number for starting HID, type depends on activated libraries
uint16_t __BLEGetAppearance() {
//mouse only
if (__BLEInstallMouse && !__BLEInstallKeyboard && !__BLEInstallJoystick) {
return 0x03C2;
}
//keyboard only
if (__BLEInstallKeyboard && !__BLEInstallMouse && !__BLEInstallJoystick) {
return 0x03C1;
}
//joystick only
if (__BLEInstallJoystick && !__BLEInstallMouse && !__BLEInstallKeyboard) {
return 0x03C4;
}
//any other combination will return "generic HID"
return 0x03C0;
}

//keyboard report id is always 1 (compatibility with iOS)
int __BTGetKeyboardReportID() {
return 1;
}

//
int __BTGetMouseReportID() {
return __BTInstallKeyboard ? 3 : 1;
}

int __BTGetJoystickReportID() {
int i = 1;
if (__BTInstallKeyboard) {
i += 2;
}
if (__BTInstallMouse) {
i++;
}
return i;
}

int __BLEGetKeyboardReportID() {
return 1;
}

int __BLEGetMouseReportID() {
return __BLEInstallKeyboard ? 3 : 1;
}

int __BLEGetFeatureReportID() {
int feature = 1;
if (__BLEInstallKeyboard) {
feature += 2;
}
if (__BLEInstallMouse) {
feature ++;
}
if (__BLEInstallJoystick) {
feature ++;
}
return feature;
}

int __BLEGetJoystickReportID() {
int i = 1;
if (__BLEInstallKeyboard) {
i += 2;
}
if (__BLEInstallMouse) {
i++;
}
return i;
}
Loading