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 using gatt_operation = BtaGattQueue::gatt_operation;
24
25 constexpr uint8_t GATT_READ_CHAR = 1;
26 constexpr uint8_t GATT_READ_DESC = 2;
27 constexpr uint8_t GATT_WRITE_CHAR = 3;
28 constexpr uint8_t GATT_WRITE_DESC = 4;
29 constexpr uint8_t GATT_CONFIG_MTU = 5;
30
31 struct gatt_read_op_data {
32 GATT_READ_OP_CB cb;
33 void* cb_data;
34 };
35
36 std::unordered_map<uint16_t, std::list<gatt_operation>>
37 BtaGattQueue::gatt_op_queue;
38 std::unordered_set<uint16_t> BtaGattQueue::gatt_op_queue_executing;
39
mark_as_not_executing(uint16_t conn_id)40 void BtaGattQueue::mark_as_not_executing(uint16_t conn_id) {
41 gatt_op_queue_executing.erase(conn_id);
42 }
43
gatt_read_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)44 void BtaGattQueue::gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
45 uint16_t handle, uint16_t len,
46 uint8_t* value, void* data) {
47 gatt_read_op_data* tmp = (gatt_read_op_data*)data;
48 GATT_READ_OP_CB tmp_cb = tmp->cb;
49 void* tmp_cb_data = tmp->cb_data;
50
51 osi_free(data);
52
53 mark_as_not_executing(conn_id);
54 gatt_execute_next_op(conn_id);
55
56 if (tmp_cb) {
57 tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
58 return;
59 }
60 }
61
62 struct gatt_write_op_data {
63 GATT_WRITE_OP_CB cb;
64 void* cb_data;
65 };
66
gatt_write_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,void * data)67 void BtaGattQueue::gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
68 uint16_t handle, void* data) {
69 gatt_write_op_data* tmp = (gatt_write_op_data*)data;
70 GATT_WRITE_OP_CB tmp_cb = tmp->cb;
71 void* tmp_cb_data = tmp->cb_data;
72
73 osi_free(data);
74
75 mark_as_not_executing(conn_id);
76 gatt_execute_next_op(conn_id);
77
78 if (tmp_cb) {
79 tmp_cb(conn_id, status, handle, tmp_cb_data);
80 return;
81 }
82 }
83
84 struct gatt_configure_mtu_op_data {
85 GATT_CONFIGURE_MTU_OP_CB cb;
86 void* cb_data;
87 };
88
gatt_configure_mtu_op_finished(uint16_t conn_id,tGATT_STATUS status,void * data)89 void BtaGattQueue::gatt_configure_mtu_op_finished(uint16_t conn_id,
90 tGATT_STATUS status,
91 void* data) {
92 gatt_configure_mtu_op_data* tmp = (gatt_configure_mtu_op_data*)data;
93 GATT_CONFIGURE_MTU_OP_CB tmp_cb = tmp->cb;
94 void* tmp_cb_data = tmp->cb_data;
95
96 osi_free(data);
97
98 mark_as_not_executing(conn_id);
99 gatt_execute_next_op(conn_id);
100
101 if (tmp_cb) {
102 tmp_cb(conn_id, status, tmp_cb_data);
103 return;
104 }
105 }
106
gatt_execute_next_op(uint16_t conn_id)107 void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) {
108 APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id);
109 if (gatt_op_queue.empty()) {
110 APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
111 return;
112 }
113
114 auto map_ptr = gatt_op_queue.find(conn_id);
115 if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
116 APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
117 conn_id);
118 return;
119 }
120
121 if (gatt_op_queue_executing.count(conn_id)) {
122 APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
123 return;
124 }
125
126 gatt_op_queue_executing.insert(conn_id);
127
128 std::list<gatt_operation>& gatt_ops = map_ptr->second;
129
130 gatt_operation& op = gatt_ops.front();
131
132 if (op.type == GATT_READ_CHAR) {
133 gatt_read_op_data* data =
134 (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
135 data->cb = op.read_cb;
136 data->cb_data = op.read_cb_data;
137 BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE,
138 gatt_read_op_finished, data);
139
140 } else if (op.type == GATT_READ_DESC) {
141 gatt_read_op_data* data =
142 (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
143 data->cb = op.read_cb;
144 data->cb_data = op.read_cb_data;
145 BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE,
146 gatt_read_op_finished, data);
147
148 } else if (op.type == GATT_WRITE_CHAR) {
149 gatt_write_op_data* data =
150 (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
151 data->cb = op.write_cb;
152 data->cb_data = op.write_cb_data;
153 BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
154 std::move(op.value), GATT_AUTH_REQ_NONE,
155 gatt_write_op_finished, data);
156
157 } else if (op.type == GATT_WRITE_DESC) {
158 gatt_write_op_data* data =
159 (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
160 data->cb = op.write_cb;
161 data->cb_data = op.write_cb_data;
162 BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
163 GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
164 } else if (op.type == GATT_CONFIG_MTU) {
165 gatt_configure_mtu_op_data* data =
166 (gatt_configure_mtu_op_data*)osi_malloc(sizeof(gatt_configure_mtu_op_data));
167 data->cb = op.mtu_cb;
168 data->cb_data = op.mtu_cb_data;
169 BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] |
170 (op.value[1] << 8)),
171 gatt_configure_mtu_op_finished, data);
172 }
173
174 gatt_ops.pop_front();
175 }
176
Clean(uint16_t conn_id)177 void BtaGattQueue::Clean(uint16_t conn_id) {
178 gatt_op_queue.erase(conn_id);
179 gatt_op_queue_executing.erase(conn_id);
180 }
181
ReadCharacteristic(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)182 void BtaGattQueue::ReadCharacteristic(uint16_t conn_id, uint16_t handle,
183 GATT_READ_OP_CB cb, void* cb_data) {
184 gatt_op_queue[conn_id].push_back({.type = GATT_READ_CHAR,
185 .handle = handle,
186 .read_cb = cb,
187 .read_cb_data = cb_data});
188 gatt_execute_next_op(conn_id);
189 }
190
ReadDescriptor(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)191 void BtaGattQueue::ReadDescriptor(uint16_t conn_id, uint16_t handle,
192 GATT_READ_OP_CB cb, void* cb_data) {
193 gatt_op_queue[conn_id].push_back({.type = GATT_READ_DESC,
194 .handle = handle,
195 .read_cb = cb,
196 .read_cb_data = cb_data});
197 gatt_execute_next_op(conn_id);
198 }
199
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)200 void BtaGattQueue::WriteCharacteristic(uint16_t conn_id, uint16_t handle,
201 std::vector<uint8_t> value,
202 tGATT_WRITE_TYPE write_type,
203 GATT_WRITE_OP_CB cb, void* cb_data) {
204 gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
205 .handle = handle,
206 .write_cb = cb,
207 .write_cb_data = cb_data,
208 .write_type = write_type,
209 .value = std::move(value)});
210 gatt_execute_next_op(conn_id);
211 }
212
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)213 void BtaGattQueue::WriteDescriptor(uint16_t conn_id, uint16_t handle,
214 std::vector<uint8_t> value,
215 tGATT_WRITE_TYPE write_type,
216 GATT_WRITE_OP_CB cb, void* cb_data) {
217 gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
218 .handle = handle,
219 .write_cb = cb,
220 .write_cb_data = cb_data,
221 .write_type = write_type,
222 .value = std::move(value)});
223 gatt_execute_next_op(conn_id);
224 }
225
ConfigureMtu(uint16_t conn_id,uint16_t mtu)226 void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) {
227 LOG(INFO) << __func__ << ", mtu: " << static_cast<int>(mtu);
228 std::vector<uint8_t> value = {static_cast<uint8_t>(mtu & 0xff),
229 static_cast<uint8_t>(mtu >> 8)};
230 gatt_op_queue[conn_id].push_back({.type = GATT_CONFIG_MTU,
231 .value = std::move(value)});
232 gatt_execute_next_op(conn_id);
233 }
234