Loading system/bta/gatt/bta_gattc_queue.cc +89 −9 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "bta_gatt_queue.h" #include "os/log.h" #include "osi/include/allocator.h" #include "stack/eatt/eatt.h" using gatt_operation = BtaGattQueue::gatt_operation; using namespace bluetooth; Loading Loading @@ -115,6 +116,18 @@ struct gatt_read_multi_op_data { void* cb_data; }; #define MAX_ATT_MTU 0xffff struct gatt_read_multi_simulate_op_data { GATT_READ_MULTI_OP_CB cb; void* cb_data; tBTA_GATTC_MULTI handles; uint8_t read_index; std::array<uint8_t, MAX_ATT_MTU> values; uint16_t values_end; }; void BtaGattQueue::gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS status, tBTA_GATTC_MULTI& handles, uint16_t len, uint8_t* value, void* data) { Loading @@ -133,6 +146,51 @@ void BtaGattQueue::gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS st } } void BtaGattQueue::gatt_read_multi_op_simulate(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data_read) { gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)data_read; log::verbose("conn_id: 0x{:x} handle: 0x{:x} status: 0x{:x} len: {}", conn_id, handle, status, len); if (status == GATT_SUCCESS && ((data->values_end + 2 + len) < MAX_ATT_MTU)) { data->values[data->values_end] = (len & 0x00ff); data->values[data->values_end + 1] = (len & 0xff00) >> 8; data->values_end += 2; // concatenate all read values together std::copy(value, value + len, data->values.data() + data->values_end); data->values_end += len; if (data->read_index < data->handles.num_attr - 1) { // grab next handle and read it data->read_index++; uint16_t next_handle = data->handles.handles[data->read_index]; BTA_GATTC_ReadCharacteristic(conn_id, next_handle, GATT_AUTH_REQ_NONE, gatt_read_multi_op_simulate, data_read); return; } } // all handles read, or bad status, or values too long GATT_READ_MULTI_OP_CB tmp_cb = data->cb; void* tmp_cb_data = data->cb_data; std::array<uint8_t, MAX_ATT_MTU> value_copy = data->values; uint16_t value_len = data->values_end; auto handles = data->handles; osi_free(data_read); mark_as_not_executing(conn_id); gatt_execute_next_op(conn_id); if (tmp_cb) { tmp_cb(conn_id, status, handles, value_len, value_copy.data(), tmp_cb_data); } } void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) { log::verbose("conn_id=0x{:x}", conn_id); if (gatt_op_queue.empty()) { Loading Loading @@ -191,12 +249,36 @@ void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) { BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] | (op.value[1] << 8)), gatt_configure_mtu_op_finished, data); } else if (op.type == GATT_READ_MULTI) { if (gatt_profile_get_eatt_support_by_conn_id(conn_id)) { gatt_read_multi_op_data* data = (gatt_read_multi_op_data*)osi_malloc(sizeof(gatt_read_multi_op_data)); data->cb = op.read_multi_cb; data->cb_data = op.read_cb_data; BTA_GATTC_ReadMultiple(conn_id, op.handles, op.variable_len, GATT_AUTH_REQ_NONE, BTA_GATTC_ReadMultiple(conn_id, op.handles, true, GATT_AUTH_REQ_NONE, gatt_read_multi_op_finished, data); } else { /* This file contains just queue, and simulating reads should rather live in BTA or * stack/gatt. However, placing this logic in layers below would be significantly harder. * Having it here is a good balance - it's easy to add, and the API we expose to apps is same * as if it was in layers below. */ log::verbose("EATT not supported, simulating read multi. conn_id: 0x{:x} num_handles: {}", conn_id, op.handles.num_attr); gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)osi_malloc( sizeof(gatt_read_multi_simulate_op_data)); data->cb = op.read_multi_cb; data->cb_data = op.read_cb_data; std::fill(data->values.begin(), data->values.end(), 0); data->values_end = 0; data->handles = op.handles; data->read_index = 0; uint16_t handle = data->handles.handles[data->read_index]; BTA_GATTC_ReadCharacteristic(conn_id, handle, GATT_AUTH_REQ_NONE, gatt_read_multi_op_simulate, data); } } gatt_ops.pop_front(); Loading Loading @@ -253,11 +335,9 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) { } void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& handles, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data) { GATT_READ_MULTI_OP_CB cb, void* cb_data) { gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI, .handles = handles, .variable_len = variable_len, .read_multi_cb = cb, .read_cb_data = cb_data}); gatt_execute_next_op(conn_id); Loading system/bta/include/bta_gatt_queue.h +7 −2 Original line number Diff line number Diff line Loading @@ -44,15 +44,18 @@ public: static void WriteDescriptor(uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data); static void ConfigureMtu(uint16_t conn_id, uint16_t mtu); /* This method uses "Read Multiple Variable Length Characteristic Values". * If EATT is not enabled on remote, it would send multiple regular Characteristic Reads, and * concatenate their values into Length Value Tuple List */ static void ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data); GATT_READ_MULTI_OP_CB cb, void* cb_data); /* Holds pending GATT operations */ struct gatt_operation { uint8_t type; uint16_t handle; tBTA_GATTC_MULTI handles; bool variable_len; /* whether read multi variable len is used*/ GATT_READ_OP_CB read_cb; GATT_READ_MULTI_OP_CB read_multi_cb; void* read_cb_data; Loading @@ -77,6 +80,8 @@ private: static void gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS status, tBTA_GATTC_MULTI& handle, uint16_t len, uint8_t* value, void* data); static void gatt_read_multi_op_simulate(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data_read); // maps connection id to operations waiting for execution static std::unordered_map<uint16_t, std::list<gatt_operation>> gatt_op_queue; // contain connection ids that currently execute operations Loading system/bta/test/common/bta_gatt_queue_mock.cc +2 −3 Original line number Diff line number Diff line Loading @@ -50,8 +50,7 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) { } void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data) { GATT_READ_MULTI_OP_CB cb, void* cb_data) { bluetooth::log::assert_that(gatt_queue, "Mock GATT queue not set!"); gatt_queue->ReadMultiCharacteristic(conn_id, p_read_multi, variable_len, cb, cb_data); gatt_queue->ReadMultiCharacteristic(conn_id, p_read_multi, cb, cb_data); } system/bta/test/common/bta_gatt_queue_mock.h +2 −2 Original line number Diff line number Diff line Loading @@ -36,8 +36,8 @@ public: tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data)); MOCK_METHOD((void), ConfigureMtu, (uint16_t conn_id, uint16_t mtu)); MOCK_METHOD((void), ReadMultiCharacteristic, (uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data)); (uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, GATT_READ_MULTI_OP_CB cb, void* cb_data)); }; /** Loading system/stack/gatt/gatt_attr.cc +4 −0 Original line number Diff line number Diff line Loading @@ -996,6 +996,10 @@ bool gatt_profile_get_eatt_support(const RawAddress& remote_bda) { return false; } return gatt_profile_get_eatt_support_by_conn_id(conn_id); } bool gatt_profile_get_eatt_support_by_conn_id(uint16_t conn_id) { /* Get tcb info */ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx]; Loading Loading
system/bta/gatt/bta_gattc_queue.cc +89 −9 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "bta_gatt_queue.h" #include "os/log.h" #include "osi/include/allocator.h" #include "stack/eatt/eatt.h" using gatt_operation = BtaGattQueue::gatt_operation; using namespace bluetooth; Loading Loading @@ -115,6 +116,18 @@ struct gatt_read_multi_op_data { void* cb_data; }; #define MAX_ATT_MTU 0xffff struct gatt_read_multi_simulate_op_data { GATT_READ_MULTI_OP_CB cb; void* cb_data; tBTA_GATTC_MULTI handles; uint8_t read_index; std::array<uint8_t, MAX_ATT_MTU> values; uint16_t values_end; }; void BtaGattQueue::gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS status, tBTA_GATTC_MULTI& handles, uint16_t len, uint8_t* value, void* data) { Loading @@ -133,6 +146,51 @@ void BtaGattQueue::gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS st } } void BtaGattQueue::gatt_read_multi_op_simulate(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data_read) { gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)data_read; log::verbose("conn_id: 0x{:x} handle: 0x{:x} status: 0x{:x} len: {}", conn_id, handle, status, len); if (status == GATT_SUCCESS && ((data->values_end + 2 + len) < MAX_ATT_MTU)) { data->values[data->values_end] = (len & 0x00ff); data->values[data->values_end + 1] = (len & 0xff00) >> 8; data->values_end += 2; // concatenate all read values together std::copy(value, value + len, data->values.data() + data->values_end); data->values_end += len; if (data->read_index < data->handles.num_attr - 1) { // grab next handle and read it data->read_index++; uint16_t next_handle = data->handles.handles[data->read_index]; BTA_GATTC_ReadCharacteristic(conn_id, next_handle, GATT_AUTH_REQ_NONE, gatt_read_multi_op_simulate, data_read); return; } } // all handles read, or bad status, or values too long GATT_READ_MULTI_OP_CB tmp_cb = data->cb; void* tmp_cb_data = data->cb_data; std::array<uint8_t, MAX_ATT_MTU> value_copy = data->values; uint16_t value_len = data->values_end; auto handles = data->handles; osi_free(data_read); mark_as_not_executing(conn_id); gatt_execute_next_op(conn_id); if (tmp_cb) { tmp_cb(conn_id, status, handles, value_len, value_copy.data(), tmp_cb_data); } } void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) { log::verbose("conn_id=0x{:x}", conn_id); if (gatt_op_queue.empty()) { Loading Loading @@ -191,12 +249,36 @@ void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) { BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] | (op.value[1] << 8)), gatt_configure_mtu_op_finished, data); } else if (op.type == GATT_READ_MULTI) { if (gatt_profile_get_eatt_support_by_conn_id(conn_id)) { gatt_read_multi_op_data* data = (gatt_read_multi_op_data*)osi_malloc(sizeof(gatt_read_multi_op_data)); data->cb = op.read_multi_cb; data->cb_data = op.read_cb_data; BTA_GATTC_ReadMultiple(conn_id, op.handles, op.variable_len, GATT_AUTH_REQ_NONE, BTA_GATTC_ReadMultiple(conn_id, op.handles, true, GATT_AUTH_REQ_NONE, gatt_read_multi_op_finished, data); } else { /* This file contains just queue, and simulating reads should rather live in BTA or * stack/gatt. However, placing this logic in layers below would be significantly harder. * Having it here is a good balance - it's easy to add, and the API we expose to apps is same * as if it was in layers below. */ log::verbose("EATT not supported, simulating read multi. conn_id: 0x{:x} num_handles: {}", conn_id, op.handles.num_attr); gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)osi_malloc( sizeof(gatt_read_multi_simulate_op_data)); data->cb = op.read_multi_cb; data->cb_data = op.read_cb_data; std::fill(data->values.begin(), data->values.end(), 0); data->values_end = 0; data->handles = op.handles; data->read_index = 0; uint16_t handle = data->handles.handles[data->read_index]; BTA_GATTC_ReadCharacteristic(conn_id, handle, GATT_AUTH_REQ_NONE, gatt_read_multi_op_simulate, data); } } gatt_ops.pop_front(); Loading Loading @@ -253,11 +335,9 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) { } void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& handles, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data) { GATT_READ_MULTI_OP_CB cb, void* cb_data) { gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI, .handles = handles, .variable_len = variable_len, .read_multi_cb = cb, .read_cb_data = cb_data}); gatt_execute_next_op(conn_id); Loading
system/bta/include/bta_gatt_queue.h +7 −2 Original line number Diff line number Diff line Loading @@ -44,15 +44,18 @@ public: static void WriteDescriptor(uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data); static void ConfigureMtu(uint16_t conn_id, uint16_t mtu); /* This method uses "Read Multiple Variable Length Characteristic Values". * If EATT is not enabled on remote, it would send multiple regular Characteristic Reads, and * concatenate their values into Length Value Tuple List */ static void ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data); GATT_READ_MULTI_OP_CB cb, void* cb_data); /* Holds pending GATT operations */ struct gatt_operation { uint8_t type; uint16_t handle; tBTA_GATTC_MULTI handles; bool variable_len; /* whether read multi variable len is used*/ GATT_READ_OP_CB read_cb; GATT_READ_MULTI_OP_CB read_multi_cb; void* read_cb_data; Loading @@ -77,6 +80,8 @@ private: static void gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS status, tBTA_GATTC_MULTI& handle, uint16_t len, uint8_t* value, void* data); static void gatt_read_multi_op_simulate(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data_read); // maps connection id to operations waiting for execution static std::unordered_map<uint16_t, std::list<gatt_operation>> gatt_op_queue; // contain connection ids that currently execute operations Loading
system/bta/test/common/bta_gatt_queue_mock.cc +2 −3 Original line number Diff line number Diff line Loading @@ -50,8 +50,7 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) { } void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data) { GATT_READ_MULTI_OP_CB cb, void* cb_data) { bluetooth::log::assert_that(gatt_queue, "Mock GATT queue not set!"); gatt_queue->ReadMultiCharacteristic(conn_id, p_read_multi, variable_len, cb, cb_data); gatt_queue->ReadMultiCharacteristic(conn_id, p_read_multi, cb, cb_data); }
system/bta/test/common/bta_gatt_queue_mock.h +2 −2 Original line number Diff line number Diff line Loading @@ -36,8 +36,8 @@ public: tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data)); MOCK_METHOD((void), ConfigureMtu, (uint16_t conn_id, uint16_t mtu)); MOCK_METHOD((void), ReadMultiCharacteristic, (uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data)); (uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, GATT_READ_MULTI_OP_CB cb, void* cb_data)); }; /** Loading
system/stack/gatt/gatt_attr.cc +4 −0 Original line number Diff line number Diff line Loading @@ -996,6 +996,10 @@ bool gatt_profile_get_eatt_support(const RawAddress& remote_bda) { return false; } return gatt_profile_get_eatt_support_by_conn_id(conn_id); } bool gatt_profile_get_eatt_support_by_conn_id(uint16_t conn_id) { /* Get tcb info */ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx]; Loading