1 /*
2 * Copyright 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "bta_gatt_queue.h"
18
19 #include <list>
20 #include <unordered_map>
21 #include <unordered_set>
22
23 #include "osi/include/allocator.h"
24
25 #include <base/logging.h>
26
27 using gatt_operation = BtaGattQueue::gatt_operation;
28
29 constexpr uint8_t GATT_READ_CHAR = 1;
30 constexpr uint8_t GATT_READ_DESC = 2;
31 constexpr uint8_t GATT_WRITE_CHAR = 3;
32 constexpr uint8_t GATT_WRITE_DESC = 4;
33 constexpr uint8_t GATT_CONFIG_MTU = 5;
34
35 struct gatt_read_op_data {
36 GATT_READ_OP_CB cb;
37 void* cb_data;
38 };
39
40 std::unordered_map<uint16_t, std::list<gatt_operation>>
41 BtaGattQueue::gatt_op_queue;
42 std::unordered_set<uint16_t> BtaGattQueue::gatt_op_queue_executing;
43
mark_as_not_executing(uint16_t conn_id)44 void BtaGattQueue::mark_as_not_executing(uint16_t conn_id) {
45 gatt_op_queue_executing.erase(conn_id);
46 }
47
gatt_read_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)48 void BtaGattQueue::gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
49 uint16_t handle, uint16_t len,
50 uint8_t* value, void* data) {
51 gatt_read_op_data* tmp = (gatt_read_op_data*)data;
52 GATT_READ_OP_CB tmp_cb = tmp->cb;
53 void* tmp_cb_data = tmp->cb_data;
54
55 osi_free(data);
56
57 mark_as_not_executing(conn_id);
58 gatt_execute_next_op(conn_id);
59
60 if (tmp_cb) {
61 tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
62 return;
63 }
64 }
65
66 struct gatt_write_op_data {
67 GATT_WRITE_OP_CB cb;
68 void* cb_data;
69 };
70
gatt_write_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * data)71 void BtaGattQueue::gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
72 uint16_t handle, uint16_t len,
73 const uint8_t* value, void* data) {
74 gatt_write_op_data* tmp = (gatt_write_op_data*)data;
75 GATT_WRITE_OP_CB tmp_cb = tmp->cb;
76 void* tmp_cb_data = tmp->cb_data;
77
78 osi_free(data);
79
80 mark_as_not_executing(conn_id);
81 gatt_execute_next_op(conn_id);
82
83 if (tmp_cb) {
84 tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
85 return;
86 }
87 }
88
89 struct gatt_configure_mtu_op_data {
90 GATT_CONFIGURE_MTU_OP_CB cb;
91 void* cb_data;
92 };
93
gatt_configure_mtu_op_finished(uint16_t conn_id,tGATT_STATUS status,void * data)94 void BtaGattQueue::gatt_configure_mtu_op_finished(uint16_t conn_id,
95 tGATT_STATUS status,
96 void* data) {
97 gatt_configure_mtu_op_data* tmp = (gatt_configure_mtu_op_data*)data;
98 GATT_CONFIGURE_MTU_OP_CB tmp_cb = tmp->cb;
99 void* tmp_cb_data = tmp->cb_data;
100
101 osi_free(data);
102
103 mark_as_not_executing(conn_id);
104 gatt_execute_next_op(conn_id);
105
106 if (tmp_cb) {
107 tmp_cb(conn_id, status, tmp_cb_data);
108 return;
109 }
110 }
111
gatt_execute_next_op(uint16_t conn_id)112 void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) {
113 APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id);
114 if (gatt_op_queue.empty()) {
115 APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
116 return;
117 }
118
119 auto map_ptr = gatt_op_queue.find(conn_id);
120 if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
121 APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
122 conn_id);
123 return;
124 }
125
126 if (gatt_op_queue_executing.count(conn_id)) {
127 APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
128 return;
129 }
130
131 gatt_op_queue_executing.insert(conn_id);
132
133 std::list<gatt_operation>& gatt_ops = map_ptr->second;
134
135 gatt_operation& op = gatt_ops.front();
136
137 if (op.type == GATT_READ_CHAR) {
138 gatt_read_op_data* data =
139 (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
140 data->cb = op.read_cb;
141 data->cb_data = op.read_cb_data;
142 BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE,
143 gatt_read_op_finished, data);
144
145 } else if (op.type == GATT_READ_DESC) {
146 gatt_read_op_data* data =
147 (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
148 data->cb = op.read_cb;
149 data->cb_data = op.read_cb_data;
150 BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE,
151 gatt_read_op_finished, data);
152
153 } else if (op.type == GATT_WRITE_CHAR) {
154 gatt_write_op_data* data =
155 (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
156 data->cb = op.write_cb;
157 data->cb_data = op.write_cb_data;
158 BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
159 std::move(op.value), GATT_AUTH_REQ_NONE,
160 gatt_write_op_finished, data);
161
162 } else if (op.type == GATT_WRITE_DESC) {
163 gatt_write_op_data* data =
164 (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
165 data->cb = op.write_cb;
166 data->cb_data = op.write_cb_data;
167 BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
168 GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
169 } else if (op.type == GATT_CONFIG_MTU) {
170 gatt_configure_mtu_op_data* data =
171 (gatt_configure_mtu_op_data*)osi_malloc(sizeof(gatt_configure_mtu_op_data));
172 data->cb = op.mtu_cb;
173 data->cb_data = op.mtu_cb_data;
174 BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] |
175 (op.value[1] << 8)),
176 gatt_configure_mtu_op_finished, data);
177 }
178
179 gatt_ops.pop_front();
180 }
181
Clean(uint16_t conn_id)182 void BtaGattQueue::Clean(uint16_t conn_id) {
183 gatt_op_queue.erase(conn_id);
184 gatt_op_queue_executing.erase(conn_id);
185 }
186
ReadCharacteristic(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)187 void BtaGattQueue::ReadCharacteristic(uint16_t conn_id, uint16_t handle,
188 GATT_READ_OP_CB cb, void* cb_data) {
189 gatt_op_queue[conn_id].push_back({.type = GATT_READ_CHAR,
190 .handle = handle,
191 .read_cb = cb,
192 .read_cb_data = cb_data});
193 gatt_execute_next_op(conn_id);
194 }
195
ReadDescriptor(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)196 void BtaGattQueue::ReadDescriptor(uint16_t conn_id, uint16_t handle,
197 GATT_READ_OP_CB cb, void* cb_data) {
198 gatt_op_queue[conn_id].push_back({.type = GATT_READ_DESC,
199 .handle = handle,
200 .read_cb = cb,
201 .read_cb_data = cb_data});
202 gatt_execute_next_op(conn_id);
203 }
204
WriteCharacteristic(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)205 void BtaGattQueue::WriteCharacteristic(uint16_t conn_id, uint16_t handle,
206 std::vector<uint8_t> value,
207 tGATT_WRITE_TYPE write_type,
208 GATT_WRITE_OP_CB cb, void* cb_data) {
209 gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
210 .handle = handle,
211 .write_cb = cb,
212 .write_cb_data = cb_data,
213 .write_type = write_type,
214 .value = std::move(value)});
215 gatt_execute_next_op(conn_id);
216 }
217
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)218 void BtaGattQueue::WriteDescriptor(uint16_t conn_id, uint16_t handle,
219 std::vector<uint8_t> value,
220 tGATT_WRITE_TYPE write_type,
221 GATT_WRITE_OP_CB cb, void* cb_data) {
222 gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
223 .handle = handle,
224 .write_cb = cb,
225 .write_cb_data = cb_data,
226 .write_type = write_type,
227 .value = std::move(value)});
228 gatt_execute_next_op(conn_id);
229 }
230
ConfigureMtu(uint16_t conn_id,uint16_t mtu)231 void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) {
232 LOG(INFO) << __func__ << ", mtu: " << static_cast<int>(mtu);
233 std::vector<uint8_t> value = {static_cast<uint8_t>(mtu & 0xff),
234 static_cast<uint8_t>(mtu >> 8)};
235 gatt_op_queue[conn_id].push_back({.type = GATT_CONFIG_MTU,
236 .value = std::move(value)});
237 gatt_execute_next_op(conn_id);
238 }
239