From abc60ac82045458e64d7d09765a2bff5eb69afe4 Mon Sep 17 00:00:00 2001 From: Jacques Gagnon Date: Thu, 2 Mar 2023 20:03:06 -0500 Subject: [PATCH] [BT] Handle BLE Write report type Fixes #626 --- main/bluetooth/att.c | 10 ++++++++ main/bluetooth/att.h | 1 + main/bluetooth/att_hid.c | 51 +++++++++++++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/main/bluetooth/att.c b/main/bluetooth/att.c index e46d2531..f5883fba 100644 --- a/main/bluetooth/att.c +++ b/main/bluetooth/att.c @@ -122,6 +122,16 @@ void bt_att_cmd_write_req(uint16_t handle, uint16_t att_handle, uint8_t *data, u bt_att_cmd(handle, BT_ATT_OP_WRITE_REQ, sizeof(write_req->handle) + len); } +void bt_att_cmd_write_cmd(uint16_t handle, uint16_t att_handle, uint8_t *data, uint32_t len) { + struct bt_att_write_cmd *write_cmd = (struct bt_att_write_cmd *)bt_hci_pkt_tmp.att_data; + printf("# %s\n", __FUNCTION__); + + write_cmd->handle = att_handle; + memcpy(write_cmd->value, data, len); + + bt_att_cmd(handle, BT_ATT_OP_WRITE_CMD, sizeof(write_cmd->handle) + len); +} + void bt_att_cmd_wr_rsp(uint16_t handle) { printf("# %s\n", __FUNCTION__); diff --git a/main/bluetooth/att.h b/main/bluetooth/att.h index 9047cab5..ae204f2b 100644 --- a/main/bluetooth/att.h +++ b/main/bluetooth/att.h @@ -18,6 +18,7 @@ void bt_att_cmd_read_req(uint16_t handle, uint16_t att_handle); void bt_att_cmd_read_blob_req(uint16_t handle, uint16_t att_handle, uint16_t offset); void bt_att_cmd_read_group_req_uuid16(uint16_t handle, uint16_t start, uint16_t uuid); void bt_att_cmd_write_req(uint16_t handle, uint16_t att_handle, uint8_t *data, uint32_t len); +void bt_att_cmd_write_cmd(uint16_t handle, uint16_t att_handle, uint8_t *data, uint32_t len); void bt_att_cmd_wr_rsp(uint16_t handle); void bt_att_cmd_prep_wr_rsp(uint16_t handle, uint8_t *data, uint32_t data_len); void bt_att_cmd_exec_wr_rsp(uint16_t handle); diff --git a/main/bluetooth/att_hid.c b/main/bluetooth/att_hid.c index 631577a2..67f5693a 100644 --- a/main/bluetooth/att_hid.c +++ b/main/bluetooth/att_hid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022, Jacques Gagnon + * Copyright (c) 2019-2023, Jacques Gagnon * SPDX-License-Identifier: Apache-2.0 */ @@ -18,11 +18,19 @@ enum { BT_ATT_HID_DEVICE_NAME = 0, BT_ATT_HID_DISCOVERY, + BT_ATT_HID_CHAR_PROP, BT_ATT_HID_REPORT_MAP, BT_ATT_HID_REPORT_REF, BT_ATT_HID_REPORT_CFG, }; +struct bt_att_read_type_data { + uint16_t handle; + uint8_t char_prop; + uint16_t char_value_handle; + uint16_t uuid; +} __packed; + struct bt_att_report_ref { uint8_t report_id; uint8_t report_type; @@ -37,6 +45,7 @@ struct bt_att_group_data_uuid16 { struct bt_att_hid_report { uint8_t id; uint8_t type; + uint8_t char_prop; uint16_t report_hdl; uint16_t cfg_hdl; uint16_t ref_hdl; @@ -65,10 +74,10 @@ static int32_t bt_att_is_report_required(struct bt_att_hid_report *att_hid, stru return 0; } -static uint16_t bt_att_get_report_handle(struct bt_att_hid *hid_data, uint8_t report_id) { +static uint32_t bt_att_get_report_index(struct bt_att_hid *hid_data, uint8_t report_id) { for (uint32_t i = 0; i < HID_MAX_REPORT; i++) { if (hid_data->reports[i].id == report_id) { - return hid_data->reports[i].report_hdl; + return i; } } return 0; @@ -81,10 +90,18 @@ void bt_att_hid_init(struct bt_dev *device) { } void bt_att_write_hid_report(struct bt_dev *device, uint8_t report_id, uint8_t *data, uint32_t len) { - uint16_t att_handle = bt_att_get_report_handle(&att_hid[device->ids.id], report_id); + struct bt_att_hid *hid_data = &att_hid[device->ids.id]; + uint32_t index = bt_att_get_report_index(hid_data, report_id); + uint16_t att_handle = hid_data->reports[index].report_hdl; + uint8_t char_prop = hid_data->reports[index].char_prop; if (att_handle) { - bt_att_cmd_write_req(device->acl_handle, att_handle, data, len); + if (char_prop | BT_GATT_CHRC_WRITE) { + bt_att_cmd_write_req(device->acl_handle, att_handle, data, len); + } + else { + bt_att_cmd_write_cmd(device->acl_handle, att_handle, data, len); + } } } @@ -106,8 +123,9 @@ void bt_att_hid_hdlr(struct bt_dev *device, struct bt_hci_pkt *bt_hci_acl_pkt, u break; case BT_ATT_OP_FIND_INFO_REQ: printf("# BT_ATT_OP_FIND_INFO_REQ\n"); - device->hid_state = BT_ATT_HID_REPORT_MAP; - bt_att_cmd_read_req(device->acl_handle, hid_data->map_hdl); + device->hid_state = BT_ATT_HID_CHAR_PROP; + bt_att_cmd_read_type_req_uuid16(device->acl_handle, + hid_data->start_hdl, hid_data->end_hdl, BT_UUID_GATT_CHRC); break; } break; @@ -241,6 +259,23 @@ void bt_att_hid_hdlr(struct bt_dev *device, struct bt_hci_pkt *bt_hci_acl_pkt, u bt_att_cmd_read_group_req_uuid16(device->acl_handle, 0x0001, BT_UUID_GATT_PRIMARY); break; } + case BT_ATT_HID_CHAR_PROP: + { + const uint32_t elem_cnt = (att_len - 2) / sizeof(read_type_rsp->len); + + for (uint32_t i = 0; i < elem_cnt; i++) { + struct bt_att_read_type_data *data = (struct bt_att_read_type_data *)read_type_rsp->data; + + for (uint32_t j = 0; j < HID_MAX_REPORT; j++) { + if (hid_data->reports[j].report_hdl == data[i].handle) { + hid_data->reports[j].char_prop = data[i].char_prop; + } + } + } + + device->hid_state = BT_ATT_HID_REPORT_MAP; + bt_att_cmd_read_req(device->acl_handle, hid_data->map_hdl); + } } break; } @@ -385,7 +420,7 @@ void bt_att_hid_hdlr(struct bt_dev *device, struct bt_hci_pkt *bt_hci_acl_pkt, u break; } } - if (i >= HID_MAX_REPORT) { + if (!atomic_test_bit(&device->flags, BT_DEV_HID_INTR_READY) && i >= HID_MAX_REPORT) { atomic_set_bit(&device->flags, BT_DEV_HID_INTR_READY); bt_hid_init(device); }