Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
77 changes: 73 additions & 4 deletions service/stacks/zephyr/sal_hid_device_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "sal_zblue.h"
#include "service_loop.h"

#define BT_HID_PROFILE_VERSION 0x0100
#define BT_HID_DEVICE_VERSION 0x0101
#define BT_HID_PARSER_VERSION 0x0111
#define BT_HID_DEVICE_SUBCLASS 0xc0
Expand All @@ -47,11 +48,22 @@
#define BT_HID_DEVICE_REPORT_DESC_SIZE 256
#define BT_HID_DEVICE_DESC_VALUE_INDEX 3

/* struct bt_hid_report field offsets (with alignment padding) */
#define BT_HID_REPORT_TYPE_OFFSET 0
#define BT_HID_REPORT_LEN_OFFSET 4
#define BT_HID_REPORT_DATA_OFFSET 8

/* Minimum data lengths for report parsing */
#define BT_HID_REPORT_HDR_SIZE 8
#define BT_HID_REPORT_MIN_RPT_ID 9
#define BT_HID_REPORT_MIN_BUF_SIZE 11

typedef struct sal_hid_connection {
struct bt_hid_device* hid_device;
bt_address_t addr;
struct bt_conn* conn;
bool le_hid;
uint8_t protocol;
} sal_hid_connection_t;

typedef struct sal_bt_hid_device_mgr {
Expand Down Expand Up @@ -92,7 +104,7 @@ static struct bt_sdp_attribute hid_attrs_template[] = {
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_HID_SVCLASS) },
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(BT_HID_DEVICE_VERSION) }) })),
BT_SDP_ARRAY_16(BT_HID_PROFILE_VERSION) }) })),
BT_SDP_LIST(
BT_SDP_ATTR_ADD_PROTO_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 15),
Expand All @@ -110,6 +122,9 @@ static struct bt_sdp_attribute hid_attrs_template[] = {
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_PROTO_HID) }) }) })),
BT_SDP_SERVICE_NAME("HID CONTROL"),
{ BT_SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(BT_HID_DEVICE_VERSION) } },
{ BT_SDP_ATTR_HID_PARSER_VERSION,
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(BT_HID_PARSER_VERSION) } },
Expand Down Expand Up @@ -156,6 +171,12 @@ static struct bt_sdp_attribute hid_attrs_template[] = {
BT_SDP_ARRAY_16(BT_HID_LANG_ID_OFFSET),
}),
})),
{ BT_SDP_ATTR_HID_NORMALLY_CONNECTABLE,
{ BT_SDP_TYPE_SIZE(BT_SDP_BOOL),
BT_SDP_ARRAY_8(0x01) } },
{ BT_SDP_ATTR_HID_PROFILE_VERSION,
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(BT_HID_PROFILE_VERSION) } },
{ BT_SDP_ATTR_HID_BOOT_DEVICE,
{ BT_SDP_TYPE_SIZE(BT_SDP_BOOL),
BT_SDP_ARRAY_8(0x01) } },
Expand Down Expand Up @@ -238,6 +259,7 @@ static sal_hid_connection_t* hid_connection_new(bt_address_t* addr, struct bt_co

memcpy(&hid_conn->addr, addr, sizeof(bt_address_t));
hid_conn->conn = conn;
hid_conn->protocol = BT_HID_PROTOCOL_REPORT_MODE;
bt_conn_ref(conn);

return hid_conn;
Expand Down Expand Up @@ -466,9 +488,15 @@ static void hid_disconnected_callback(struct bt_hid_device* hid)
void hid_set_report_callback(struct bt_hid_device* hid, const uint8_t* data, uint16_t len)
{
sal_hid_connection_t* hid_conn;
bt_address_t addr;

BT_LOGD("hid:%p set report cb, len:%d", hid, len);

if (!data || len < 1) {
BT_LOGE("hid:%p set report data invalid, data:%p len:%d", hid, data, len);
return;
}

hid_conn_lock();
hid_conn = hid_find_connections_by_device(hid);
if (!hid_conn) {
Expand All @@ -477,16 +505,27 @@ void hid_set_report_callback(struct bt_hid_device* hid, const uint8_t* data, uin
return;
}

memcpy(&addr, &hid_conn->addr, sizeof(bt_address_t));
hid_conn_unlock();
hid_device_on_set_report(&hid_conn->addr, data[0], len - 1, (uint8_t*)&data[1]);
hid_device_on_set_report(&addr, data[0], len - 1, (uint8_t*)&data[1]);
Comment thread
EListenX marked this conversation as resolved.
}

void hid_get_report_callback(struct bt_hid_device* hid, const uint8_t* data, uint16_t len)
{
sal_hid_connection_t* hid_conn;
bt_address_t addr;
uint8_t rpt_type;
uint8_t rpt_id = 0;
uint16_t buffer_size = 0;
int rpt_len;

BT_LOGD("hid:%p get report cb, len:%d", hid, len);

if (len < BT_HID_REPORT_HDR_SIZE) {
BT_LOGE("hid:%p get report data too short: %d", hid, len);
return;
}

hid_conn_lock();
hid_conn = hid_find_connections_by_device(hid);
if (!hid_conn) {
Expand All @@ -495,13 +534,40 @@ void hid_get_report_callback(struct bt_hid_device* hid, const uint8_t* data, uin
return;
}

memcpy(&addr, &hid_conn->addr, sizeof(bt_address_t));
hid_conn_unlock();
hid_device_on_get_report(&hid_conn->addr, data[0], data[1], data[2]);

/* data points to struct bt_hid_report:
* uint8_t type; (offset BT_HID_REPORT_TYPE_OFFSET)
* int len; (offset BT_HID_REPORT_LEN_OFFSET, due to alignment)
* uint8_t data[]; (offset BT_HID_REPORT_DATA_OFFSET)
*/
rpt_type = data[BT_HID_REPORT_TYPE_OFFSET];
memcpy(&rpt_len, &data[BT_HID_REPORT_LEN_OFFSET], sizeof(int));

if (rpt_len >= 1 && len >= BT_HID_REPORT_MIN_RPT_ID) {
Comment thread
EListenX marked this conversation as resolved.
rpt_id = data[BT_HID_REPORT_DATA_OFFSET];
}

if (rpt_len >= 3 && len >= BT_HID_REPORT_MIN_BUF_SIZE) {
buffer_size = data[BT_HID_REPORT_DATA_OFFSET + 1] | (data[BT_HID_REPORT_DATA_OFFSET + 2] << 8);
}

hid_device_on_get_report(&addr, rpt_type, rpt_id, buffer_size);
}

void hid_set_protocol_callback(struct bt_hid_device* hid, uint8_t protocol)
{
sal_hid_connection_t* hid_conn;

BT_LOGD("hid:%p set protocol:%d, ", hid, protocol);

hid_conn_lock();
hid_conn = hid_find_connections_by_device(hid);
if (hid_conn) {
hid_conn->protocol = protocol;
}
hid_conn_unlock();
}

typedef struct {
Expand Down Expand Up @@ -645,6 +711,7 @@ void hid_get_protocol_callback(struct bt_hid_device* hid)
{
hid_send_data_param_t* params;
sal_hid_connection_t* hid_conn;
uint8_t protocol;

BT_LOGD("hid:%p get protocol", hid);

Expand All @@ -656,6 +723,8 @@ void hid_get_protocol_callback(struct bt_hid_device* hid)
return;
}

protocol = hid_conn->protocol;

params = zalloc(sizeof(hid_send_data_param_t));
if (!params) {
hid_conn_unlock();
Expand All @@ -665,7 +734,7 @@ void hid_get_protocol_callback(struct bt_hid_device* hid)

memcpy(&params->addr, &hid_conn->addr, sizeof(bt_address_t));
params->type = BT_HID_REPORT_TYPE_OTHER;
params->data[0] = BT_HID_PROTOCOL_REPORT_MODE;
params->data[0] = protocol;
params->len = sizeof(uint8_t);
hid_conn_unlock();

Expand Down
15 changes: 12 additions & 3 deletions tools/hid_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,27 +202,36 @@ static void hidd_connection_state_cb(void* cookie, bt_address_t* addr, bool le_h
static void hidd_get_report_cb(void* cookie, bt_address_t* addr, uint8_t rpt_type,
uint8_t rpt_id, uint16_t buffer_size)
{
extern bt_instance_t* g_bttool_ins;
uint8_t rpt_data[] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
char addr_str[BT_ADDR_STR_LENGTH] = { 0 };

bt_addr_ba2str(addr, addr_str);
PRINT("%s, addr:%s, buffer size: %d", __func__, addr_str, buffer_size);
PRINT("%s, addr:%s, rpt_type:%d, rpt_id:%d, buffer size: %d",
__func__, addr_str, rpt_type, rpt_id, buffer_size);

/* Only report ID 0x01 and 0x02 are valid per HID descriptor */
if (rpt_id != 0x01 && rpt_id != 0x02) {
Comment thread
EListenX marked this conversation as resolved.
bt_hid_device_report_error(g_bttool_ins, addr, HID_STATUS_HANDSHAKE_INVALID_REPORT_ID);
return;
}

if (rpt_id != 0)
rpt_data[0] = rpt_id;

bt_hid_device_response_report(cookie, addr, rpt_type, rpt_data, sizeof(rpt_data));
bt_hid_device_response_report(g_bttool_ins, addr, rpt_type, rpt_data, sizeof(rpt_data));
}

static void hidd_set_report_cb(void* cookie, bt_address_t* addr, uint8_t rpt_type,
uint16_t rpt_size, uint8_t* rpt_data)
{
extern bt_instance_t* g_bttool_ins;
char addr_str[BT_ADDR_STR_LENGTH] = { 0 };

bt_addr_ba2str(addr, addr_str);
PRINT("%s, addr:%s, report type: %d", __func__, addr_str, rpt_type);
lib_dumpbuffer("report data:", rpt_data, rpt_size);
bt_hid_device_report_error(cookie, addr, HID_STATUS_OK);
bt_hid_device_report_error(g_bttool_ins, addr, HID_STATUS_OK);
}

static void hidd_receive_report_cb(void* cookie, bt_address_t* addr, uint8_t rpt_type,
Expand Down
Loading