1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <string.h>
16
17 #include "bta/bta_gatt_api.h"
18
19 #include "btc/btc_task.h"
20 #include "btc/btc_manage.h"
21 #include "btc_gatts.h"
22 #include "btc_gatt_util.h"
23 #include "osi/future.h"
24 #include "osi/allocator.h"
25 #include "btc/btc_main.h"
26 #include "esp_gatts_api.h"
27
28 #if (GATTS_INCLUDED == 1)
29
30 #define A2C_GATTS_EVT(_bta_event) (_bta_event) //BTA TO BTC EVT
31 #define C2A_GATTS_EVT(_btc_event) (_btc_event) //BTC TO BTA EVT
32
33 #if GATT_DYNAMIC_MEMORY == 0
34 static esp_btc_creat_tab_t btc_creat_tab_env;
35 #else
36 esp_btc_creat_tab_t *btc_creat_tab_env_ptr;
37 #endif
38
39 static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
40 uint8_t max_nb_attr);
41
btc_gatts_cb_to_app(esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if,esp_ble_gatts_cb_param_t * param)42 static inline void btc_gatts_cb_to_app(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
43 {
44 esp_gatts_cb_t btc_gatts_cb = (esp_gatts_cb_t)btc_profile_cb_get(BTC_PID_GATTS);
45 if (btc_gatts_cb) {
46 btc_gatts_cb(event, gatts_if, param);
47 }
48 }
49
btc_gatts_uuid_format_convert(esp_bt_uuid_t * dest_uuid,uint16_t src_uuid_len,uint8_t * src_uuid_p)50 static inline void btc_gatts_uuid_format_convert(esp_bt_uuid_t* dest_uuid, uint16_t src_uuid_len, uint8_t* src_uuid_p)
51 {
52 dest_uuid->len = src_uuid_len;
53 if(src_uuid_len == ESP_UUID_LEN_16){
54 dest_uuid->uuid.uuid16 = src_uuid_p[0] + (src_uuid_p[1]<<8);
55 }
56 else if(src_uuid_len == ESP_UUID_LEN_32){
57 dest_uuid->uuid.uuid32 = src_uuid_p[0] + (src_uuid_p[1]<<8) + (src_uuid_p[2]<<16) + (src_uuid_p[3]<<24);
58 }
59 else if(src_uuid_len == ESP_UUID_LEN_128){
60 memcpy(dest_uuid->uuid.uuid128, src_uuid_p, src_uuid_len);
61 }
62 else{
63 BTC_TRACE_ERROR("%s wrong uuid length %d\n", __func__, src_uuid_len);
64 }
65
66 }
67
68
btc_gatts_arg_deep_copy(btc_msg_t * msg,void * p_dest,void * p_src)69 void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
70 {
71 btc_ble_gatts_args_t *dst = (btc_ble_gatts_args_t *) p_dest;
72 btc_ble_gatts_args_t *src = (btc_ble_gatts_args_t *)p_src;
73
74 switch (msg->act) {
75 case BTC_GATTS_ACT_SEND_INDICATE: {
76 if (src->send_ind.value && (src->send_ind.value_len > 0)) {
77 dst->send_ind.value = (uint8_t *) osi_malloc(src->send_ind.value_len);
78 if (dst->send_ind.value) {
79 memcpy(dst->send_ind.value, src->send_ind.value, src->send_ind.value_len);
80 } else {
81 BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
82 }
83 } else {
84 dst->send_ind.value = NULL;
85 if (src->send_ind.value) {
86 BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
87 }
88 }
89 break;
90 }
91 case BTC_GATTS_ACT_SEND_RESPONSE: {
92 if (src->send_rsp.rsp) {
93 dst->send_rsp.rsp = (esp_gatt_rsp_t *) osi_malloc(sizeof(esp_gatt_rsp_t));
94 if (dst->send_rsp.rsp) {
95 memcpy(dst->send_rsp.rsp, src->send_rsp.rsp, sizeof(esp_gatt_rsp_t));
96 } else {
97 BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
98 }
99 }
100 break;
101
102 }
103 case BTC_GATTS_ACT_ADD_CHAR: {
104 if (src->add_char.char_val.attr_value && (src->add_char.char_val.attr_len > 0)) {
105 dst->add_char.char_val.attr_value = (uint8_t *) osi_malloc(src->add_char.char_val.attr_len);
106 if (dst->add_char.char_val.attr_value) {
107 memcpy(dst->add_char.char_val.attr_value, src->add_char.char_val.attr_value,
108 src->add_char.char_val.attr_len);
109 } else {
110 BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
111 }
112 } else {
113 dst->add_char.char_val.attr_value = NULL;
114 if (src->add_char.char_val.attr_value) {
115 BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
116 }
117 }
118 break;
119 }
120 case BTC_GATTS_ACT_ADD_CHAR_DESCR: {
121 if (src->add_descr.descr_val.attr_value && (src->add_descr.descr_val.attr_len > 0)) {
122 dst->add_descr.descr_val.attr_value = (uint8_t *) osi_malloc(src->add_descr.descr_val.attr_len);
123 if (dst->add_descr.descr_val.attr_value) {
124 memcpy(dst->add_descr.descr_val.attr_value, src->add_descr.descr_val.attr_value,
125 src->add_descr.descr_val.attr_len);
126 } else {
127 BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
128 }
129 } else {
130 dst->add_descr.descr_val.attr_value = NULL;
131 if (src->add_descr.descr_val.attr_value) {
132 BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
133 }
134 }
135 break;
136 }
137 case BTC_GATTS_ACT_CREATE_ATTR_TAB: {
138 uint8_t num_attr = src->create_attr_tab.max_nb_attr;
139 if (src->create_attr_tab.gatts_attr_db && (num_attr > 0)) {
140 dst->create_attr_tab.gatts_attr_db = (esp_gatts_attr_db_t *) osi_malloc(sizeof(esp_gatts_attr_db_t) * num_attr);
141 if (dst->create_attr_tab.gatts_attr_db) {
142 memcpy(dst->create_attr_tab.gatts_attr_db, src->create_attr_tab.gatts_attr_db,
143 sizeof(esp_gatts_attr_db_t) * num_attr);
144 } else {
145 BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
146 }
147 } else {
148 BTC_TRACE_ERROR("%s %d, NULL data", __func__, msg->act);
149 }
150 break;
151 }
152 case BTC_GATTS_ACT_SET_ATTR_VALUE: {
153 if (src->set_attr_val.value && (src->set_attr_val.length > 0)) {
154 dst->set_attr_val.value = (uint8_t *) osi_malloc(src->set_attr_val.length);
155 if (dst->set_attr_val.value) {
156 memcpy(dst->set_attr_val.value, src->set_attr_val.value, src->set_attr_val.length);
157 } else {
158 BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
159 }
160 } else {
161 dst->set_attr_val.value = NULL;
162 if (src->set_attr_val.value) {
163 BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
164 } else {
165 BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act);
166 }
167 }
168 break;
169 }
170 default:
171 BTC_TRACE_DEBUG("%s Unhandled deep copy %d\n", __func__, msg->act);
172 break;
173 }
174
175 }
176
btc_gatts_arg_deep_free(btc_msg_t * msg)177 void btc_gatts_arg_deep_free(btc_msg_t *msg)
178 {
179 btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg;
180
181 switch (msg->act) {
182 case BTC_GATTS_ACT_SEND_INDICATE: {
183 if (arg->send_ind.value) {
184 osi_free(arg->send_ind.value);
185 }
186 break;
187 }
188 case BTC_GATTS_ACT_SEND_RESPONSE: {
189 if (arg->send_rsp.rsp) {
190 osi_free(arg->send_rsp.rsp);
191 }
192 break;
193 }
194 case BTC_GATTS_ACT_ADD_CHAR:{
195 if (arg->add_char.char_val.attr_value != NULL) {
196 osi_free(arg->add_char.char_val.attr_value);
197 }
198 break;
199 }
200 case BTC_GATTS_ACT_ADD_CHAR_DESCR:{
201 if (arg->add_descr.descr_val.attr_value != NULL){
202 osi_free(arg->add_descr.descr_val.attr_value);
203 }
204 break;
205 }
206 case BTC_GATTS_ACT_CREATE_ATTR_TAB:{
207 if (arg->create_attr_tab.gatts_attr_db != NULL){
208 osi_free(arg->create_attr_tab.gatts_attr_db);
209 }
210 break;
211 }
212 case BTC_GATTS_ACT_SET_ATTR_VALUE:{
213 if (arg->set_attr_val.value != NULL){
214 osi_free(arg->set_attr_val.value);
215 }
216 }
217 break;
218
219 default:
220 BTC_TRACE_DEBUG("%s Unhandled deep free %d\n", __func__, msg->act);
221 break;
222 }
223
224 }
225
btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t * gatts_attr_db,esp_gatt_if_t gatts_if,uint8_t max_nb_attr,uint8_t srvc_inst_id)226 static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
227 esp_gatt_if_t gatts_if,
228 uint8_t max_nb_attr,
229 uint8_t srvc_inst_id)
230 {
231 uint16_t uuid = 0;
232 future_t *future_p;
233 esp_ble_gatts_cb_param_t param;
234 param.add_attr_tab.status = ESP_GATT_OK;
235 param.add_attr_tab.num_handle = max_nb_attr;
236
237 if (param.add_attr_tab.status != ESP_GATT_OK) {
238 btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m);
239 //reset the env after sent the data to app
240 memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
241 return;
242 }
243
244 // Check the attribute table is valid or not
245 if ((param.add_attr_tab.status = btc_gatts_check_valid_attr_tab(gatts_attr_db, max_nb_attr)) != ESP_GATT_OK) {
246 //sent the callback event to the application
247 btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m);
248 return;
249 }
250
251
252 //set the attribute table create service flag to true
253 btc_creat_tab_env.is_tab_creat_svc = true;
254 btc_creat_tab_env.num_handle = max_nb_attr;
255 for(int i = 0; i < max_nb_attr; i++){
256 if(gatts_attr_db[i].att_desc.uuid_length == ESP_UUID_LEN_16){
257 uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]);
258 }
259 else{
260 continue;
261 }
262 future_p = future_new();
263 if (future_p == NULL) {
264 BTC_TRACE_ERROR("%s failed:no mem\n", __func__);
265 return ;
266 }
267 btc_creat_tab_env.complete_future = future_p;
268 btc_creat_tab_env.handle_idx = i;
269 switch(uuid)
270 {
271 case ESP_GATT_UUID_PRI_SERVICE:{
272 tBTA_GATT_SRVC_ID srvc_id;
273 esp_gatt_srvc_id_t esp_srvc_id;
274
275 esp_srvc_id.id.inst_id = srvc_inst_id;
276 btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length,
277 gatts_attr_db[i].att_desc.value);
278
279 btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
280 if (btc_creat_tab_env.is_use_svc != true) {
281 BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid,
282 srvc_inst_id, max_nb_attr, true);
283 btc_creat_tab_env.is_use_svc = true;
284 } else {
285 BTC_TRACE_ERROR("Each service table can only created one primary service.");
286 param.add_attr_tab.status = ESP_GATT_ERROR;
287 btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m);
288 //reset the env after sent the data to app
289 memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
290 return;
291 }
292
293 if (future_await(future_p) == FUTURE_FAIL) {
294 BTC_TRACE_ERROR("%s failed\n", __func__);
295 return;
296 }
297 break;
298 }
299 case ESP_GATT_UUID_SEC_SERVICE:{
300 tBTA_GATT_SRVC_ID srvc_id;
301 esp_gatt_srvc_id_t esp_srvc_id;
302
303 esp_srvc_id.id.inst_id = srvc_inst_id;
304 btc_gatts_uuid_format_convert(&esp_srvc_id.id.uuid,gatts_attr_db[i].att_desc.length,
305 gatts_attr_db[i].att_desc.value);
306 btc_to_bta_srvc_id(&srvc_id, &esp_srvc_id);
307 if (btc_creat_tab_env.is_use_svc != true) {
308 BTA_GATTS_CreateService(gatts_if, &srvc_id.id.uuid,
309 srvc_inst_id, max_nb_attr, false);
310 btc_creat_tab_env.is_use_svc = true;
311 } else {
312 BTC_TRACE_ERROR("Each service table can only created one secondary service.");
313 param.add_attr_tab.status = ESP_GATT_ERROR;
314 btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m);
315 //reset the env after sent the data to app
316 memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
317 return;
318 }
319 if (future_await(future_p) == FUTURE_FAIL) {
320 BTC_TRACE_ERROR("%s failed\n", __func__);
321 return;
322 }
323 break;
324 }
325 case ESP_GATT_UUID_INCLUDE_SERVICE:{
326 esp_gatts_incl_svc_desc_t *incl_svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value;
327
328 if(incl_svc_desc!= NULL){
329 if(btc_creat_tab_env.svc_start_hdl != 0){
330 BTA_GATTS_AddIncludeService(btc_creat_tab_env.svc_start_hdl,
331 incl_svc_desc->start_hdl);
332
333 if (future_await(future_p) == FUTURE_FAIL) {
334 BTC_TRACE_ERROR("%s failed\n", __func__);
335 return;
336 }
337 }
338 }
339 break;
340 }
341 case ESP_GATT_UUID_CHAR_DECLARE:{
342 uint16_t svc_hal = 0;
343 tBT_UUID bta_char_uuid;
344 tGATT_ATTR_VAL attr_val;
345 esp_bt_uuid_t uuid_temp;
346 tBTA_GATT_PERM perm;
347 tBTA_GATTS_ATTR_CONTROL control;
348 uint8_t char_property;
349
350 if(btc_creat_tab_env.svc_start_hdl != 0){
351 svc_hal = btc_creat_tab_env.svc_start_hdl;
352 if((gatts_attr_db[i].att_desc.value) == NULL){
353 BTC_TRACE_ERROR("%s Characteristic declaration should not be NULL\n", __func__);
354 }
355 else{
356 char_property = (uint8_t)(*(uint8_t*)(gatts_attr_db[i].att_desc.value));
357 perm = gatts_attr_db[i+1].att_desc.perm;
358 attr_val.attr_len = gatts_attr_db[i+1].att_desc.length;
359 attr_val.attr_max_len = gatts_attr_db[i+1].att_desc.max_length;
360 btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i+1].att_desc.uuid_length,gatts_attr_db[i+1].att_desc.uuid_p);
361 btc_to_bta_uuid(&bta_char_uuid, &uuid_temp);
362 attr_val.attr_val = gatts_attr_db[i+1].att_desc.value;
363 control.auto_rsp = gatts_attr_db[i+1].attr_control.auto_rsp;
364 BTA_GATTS_AddCharacteristic (svc_hal, &bta_char_uuid,
365 perm, char_property, &attr_val, &control);
366
367 if (future_await(future_p) == FUTURE_FAIL) {
368 BTC_TRACE_ERROR("%s failed\n", __func__);
369 return;
370 }
371 }
372 }
373
374 break;
375 }
376 case ESP_GATT_UUID_CHAR_EXT_PROP:
377 case ESP_GATT_UUID_CHAR_DESCRIPTION:
378 case ESP_GATT_UUID_CHAR_CLIENT_CONFIG:
379 case ESP_GATT_UUID_CHAR_SRVR_CONFIG:
380 case ESP_GATT_UUID_CHAR_PRESENT_FORMAT:
381 case ESP_GATT_UUID_CHAR_AGG_FORMAT:
382 case ESP_GATT_UUID_CHAR_VALID_RANGE:
383 case ESP_GATT_UUID_EXT_RPT_REF_DESCR:
384 case ESP_GATT_UUID_RPT_REF_DESCR:
385 case ESP_GATT_UUID_NUM_DIGITALS_DESCR:
386 case ESP_GATT_UUID_VALUE_TRIGGER_DESCR:
387 case ESP_GATT_UUID_ENV_SENSING_CONFIG_DESCR:
388 case ESP_GATT_UUID_ENV_SENSING_MEASUREMENT_DESCR:
389 case ESP_GATT_UUID_ENV_SENSING_TRIGGER_DESCR:
390 case ESP_GATT_UUID_TIME_TRIGGER_DESCR: {
391 uint16_t svc_hal = btc_creat_tab_env.svc_start_hdl;
392 tBT_UUID bta_char_uuid;
393 esp_bt_uuid_t uuid_temp;
394 tGATT_ATTR_VAL attr_val;
395 tBTA_GATT_PERM perm = gatts_attr_db[i].att_desc.perm;
396 tBTA_GATTS_ATTR_CONTROL control;
397
398 if(svc_hal != 0){
399 attr_val.attr_len = gatts_attr_db[i].att_desc.length;
400 attr_val.attr_max_len = gatts_attr_db[i].att_desc.max_length;
401 attr_val.attr_val = gatts_attr_db[i].att_desc.value;
402 btc_gatts_uuid_format_convert(&uuid_temp, gatts_attr_db[i].att_desc.uuid_length,
403 gatts_attr_db[i].att_desc.uuid_p);
404 btc_to_bta_uuid(&bta_char_uuid, &uuid_temp);
405 control.auto_rsp = gatts_attr_db[i].attr_control.auto_rsp;
406 BTA_GATTS_AddCharDescriptor(svc_hal, perm, &bta_char_uuid, &attr_val, &control);
407
408 if (future_await(future_p) == FUTURE_FAIL) {
409 BTC_TRACE_ERROR("%s failed\n", __func__);
410 return;
411 }
412 }
413 break;
414 }
415 default:
416 future_free(future_p);
417 break;
418 }
419
420
421 }
422
423 param.add_attr_tab.handles = btc_creat_tab_env.handles;
424 memcpy(¶m.add_attr_tab.svc_uuid, &btc_creat_tab_env.svc_uuid, sizeof(esp_bt_uuid_t));
425
426 param.add_attr_tab.svc_inst_id = srvc_inst_id;
427
428 btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m);
429 //reset the env after sent the data to app
430 memset(&btc_creat_tab_env, 0, sizeof(esp_btc_creat_tab_t));
431
432 //set the flag value to false after the service is created.
433 btc_creat_tab_env.is_tab_creat_svc = false;
434 }
435
btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t * gatts_attr_db,uint8_t max_nb_attr)436 static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
437 uint8_t max_nb_attr)
438 {
439 uint8_t svc_num = 0;
440 uint16_t uuid = 0;
441
442 for(int i = 0; i < max_nb_attr; i++) {
443 if(gatts_attr_db[i].att_desc.uuid_length != ESP_UUID_LEN_16) {
444 continue;
445 }
446
447 uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]);
448 switch(uuid) {
449 case ESP_GATT_UUID_PRI_SERVICE:
450 case ESP_GATT_UUID_SEC_SERVICE:
451 if (++svc_num > 1) {
452 BTC_TRACE_ERROR("Each service table can only created one primary service or secondary service.");
453 return ESP_GATT_ERROR;
454 }
455 break;
456 case ESP_GATT_UUID_INCLUDE_SERVICE: {
457 esp_gatts_incl_svc_desc_t *svc_desc = (esp_gatts_incl_svc_desc_t *)gatts_attr_db[i].att_desc.value;
458 if(svc_desc == NULL) {
459 BTC_TRACE_ERROR("%s, The include service attribute should not be NULL.", __func__);
460 return ESP_GATT_INVALID_PDU;
461 } else if((svc_desc->start_hdl == 0) || (svc_desc->end_hdl == 0) ||
462 (svc_desc->start_hdl == svc_desc->end_hdl)) {
463 BTC_TRACE_ERROR("%s, The include service attribute handle is invalid, start_hanlde = %d, end_handle = %d",\
464 __func__, svc_desc->start_hdl, svc_desc->end_hdl);
465 return ESP_GATT_INVALID_HANDLE;
466 }
467 break;
468 }
469 case ESP_GATT_UUID_CHAR_DECLARE:
470 if((gatts_attr_db[i].att_desc.value) == NULL) {
471 BTC_TRACE_ERROR("%s, Characteristic declaration should not be NULL.", __func__);
472 return ESP_GATT_INVALID_PDU;
473 }
474
475 if(gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_16 &&
476 gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_32 &&
477 gatts_attr_db[i+1].att_desc.uuid_length != ESP_UUID_LEN_128) {
478 BTC_TRACE_ERROR("%s, The Charateristic uuid length = %d is invalid", __func__,\
479 gatts_attr_db[i+1].att_desc.uuid_length);
480 return ESP_GATT_INVALID_ATTR_LEN;
481 }
482
483 if(gatts_attr_db[i+1].att_desc.uuid_length == ESP_UUID_LEN_16) {
484 uuid = (gatts_attr_db[i+1].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i+1].att_desc.uuid_p[0]);
485 if(uuid == ESP_GATT_UUID_CHAR_DECLARE || uuid == ESP_GATT_UUID_CHAR_EXT_PROP ||
486 uuid == ESP_GATT_UUID_CHAR_DESCRIPTION || uuid == ESP_GATT_UUID_CHAR_CLIENT_CONFIG ||
487 uuid == ESP_GATT_UUID_CHAR_SRVR_CONFIG || uuid == ESP_GATT_UUID_CHAR_PRESENT_FORMAT ||
488 uuid == ESP_GATT_UUID_CHAR_AGG_FORMAT || uuid == ESP_GATT_UUID_CHAR_VALID_RANGE ||
489 uuid == ESP_GATT_UUID_EXT_RPT_REF_DESCR || uuid == ESP_GATT_UUID_RPT_REF_DESCR) {
490 BTC_TRACE_ERROR("%s, The charateristic value uuid = %d is invalid", __func__, uuid);
491 return ESP_GATT_INVALID_PDU;
492 }
493 }
494 break;
495 default:
496 break;
497 }
498 }
499
500 return ESP_GATT_OK;
501 }
502
btc_gatts_get_attr_value(uint16_t attr_handle,uint16_t * length,uint8_t ** value)503 esp_gatt_status_t btc_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, uint8_t **value)
504 {
505
506 return BTA_GetAttributeValue(attr_handle, length, value);
507 }
508
509
btc_gatts_cb_param_copy_req(btc_msg_t * msg,void * p_dest,void * p_src)510 static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_src)
511 {
512 uint16_t event = msg->act;
513
514 tBTA_GATTS *p_dest_data = (tBTA_GATTS *) p_dest;
515 tBTA_GATTS *p_src_data = (tBTA_GATTS *) p_src;
516
517 if (!p_src_data || !p_dest_data) {
518 return;
519 }
520
521 // Copy basic structure first
522 memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTS));
523
524 // Allocate buffer for request data if necessary
525 switch (event) {
526 case BTA_GATTS_READ_EVT:
527 case BTA_GATTS_WRITE_EVT:
528 case BTA_GATTS_EXEC_WRITE_EVT:
529 case BTA_GATTS_MTU_EVT:
530 p_dest_data->req_data.p_data = osi_malloc(sizeof(tBTA_GATTS_REQ_DATA));
531 if (p_dest_data->req_data.p_data != NULL) {
532 memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
533 sizeof(tBTA_GATTS_REQ_DATA));
534 } else {
535 BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
536 }
537 break;
538
539 default:
540 break;
541 }
542 }
543
btc_gatts_cb_param_copy_free(btc_msg_t * msg,tBTA_GATTS * p_data)544 static void btc_gatts_cb_param_copy_free(btc_msg_t *msg, tBTA_GATTS *p_data)
545 {
546 uint16_t event = msg->act;
547
548 switch (event) {
549 case BTA_GATTS_READ_EVT:
550 case BTA_GATTS_WRITE_EVT:
551 case BTA_GATTS_EXEC_WRITE_EVT:
552 case BTA_GATTS_MTU_EVT:
553 if (p_data && p_data->req_data.p_data) {
554 osi_free(p_data->req_data.p_data);
555 }
556 break;
557 case BTA_GATTS_CONF_EVT:
558 break;
559 default:
560 break;
561 }
562 }
563
564
btc_gatts_inter_cb(tBTA_GATTS_EVT event,tBTA_GATTS * p_data)565 static void btc_gatts_inter_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
566 {
567 bt_status_t status;
568 btc_msg_t msg;
569
570 msg.sig = BTC_SIG_API_CB;
571 msg.pid = BTC_PID_GATTS;
572 msg.act = event;
573 if(btc_creat_tab_env.is_tab_creat_svc && btc_creat_tab_env.complete_future) {
574 switch(event) {
575 case BTA_GATTS_CREATE_EVT: {
576 //save the service handle to the btc module after used
577 //the attribute table method to creat a service
578 bta_to_btc_uuid(&btc_creat_tab_env.svc_uuid, &p_data->create.uuid);
579 uint8_t index = btc_creat_tab_env.handle_idx;
580 btc_creat_tab_env.svc_start_hdl = p_data->create.service_id;
581 btc_creat_tab_env.handles[index] = p_data->create.service_id;
582 break;
583 }
584 case BTA_GATTS_ADD_INCL_SRVC_EVT: {
585 uint8_t index = btc_creat_tab_env.handle_idx;
586 btc_creat_tab_env.handles[index] = p_data->add_result.attr_id;
587 break;
588 }
589 case BTA_GATTS_ADD_CHAR_EVT: {
590 uint8_t index = btc_creat_tab_env.handle_idx;
591 btc_creat_tab_env.handles[index] = p_data->add_result.attr_id - 1;
592 btc_creat_tab_env.handles[index+1] = p_data->add_result.attr_id;
593 break;
594 }
595 case BTA_GATTS_ADD_CHAR_DESCR_EVT: {
596 uint8_t index = btc_creat_tab_env.handle_idx;
597 btc_creat_tab_env.handles[index] = p_data->add_result.attr_id;
598 break;
599 }
600 default:
601 break;
602 }
603
604 future_ready(btc_creat_tab_env.complete_future, FUTURE_SUCCESS);
605 return;
606 }
607 status = btc_transfer_context(&msg, p_data,
608 sizeof(tBTA_GATTS), btc_gatts_cb_param_copy_req);
609
610 if (status != BT_STATUS_SUCCESS) {
611 BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
612 }
613 }
614
btc_gatts_call_handler(btc_msg_t * msg)615 void btc_gatts_call_handler(btc_msg_t *msg)
616 {
617 btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg;
618
619 switch (msg->act) {
620 case BTC_GATTS_ACT_APP_REGISTER: {
621 tBT_UUID uuid;
622
623 uuid.len = LEN_UUID_16;
624 uuid.uu.uuid16 = arg->app_reg.app_id;
625
626 BTA_GATTS_AppRegister(&uuid, btc_gatts_inter_cb);
627
628 break;
629 }
630 case BTC_GATTS_ACT_APP_UNREGISTER:
631 BTA_GATTS_AppDeregister(arg->app_unreg.gatts_if);
632 break;
633 case BTC_GATTS_ACT_CREATE_SERVICE: {
634 tBTA_GATT_SRVC_ID srvc_id;
635 btc_to_bta_srvc_id(&srvc_id, &arg->create_srvc.service_id);
636 BTA_GATTS_CreateService(arg->create_srvc.gatts_if, &srvc_id.id.uuid,
637 srvc_id.id.inst_id, arg->create_srvc.num_handle,
638 srvc_id.is_primary);
639 break;
640 }
641 case BTC_GATTS_ACT_CREATE_ATTR_TAB:
642 btc_gatts_act_create_attr_tab(arg->create_attr_tab.gatts_attr_db,
643 arg->create_attr_tab.gatts_if,
644 arg->create_attr_tab.max_nb_attr,
645 arg->create_attr_tab.srvc_inst_id);
646 break;
647 case BTC_GATTS_ACT_DELETE_SERVICE:
648 BTA_GATTS_DeleteService(arg->delete_srvc.service_handle);
649 break;
650 case BTC_GATTS_ACT_START_SERVICE:
651 BTA_GATTS_StartService(arg->start_srvc.service_handle, BTA_GATT_TRANSPORT_LE);
652 break;
653 case BTC_GATTS_ACT_STOP_SERVICE:
654 BTA_GATTS_StopService(arg->stop_srvc.service_handle);
655 break;
656 case BTC_GATTS_ACT_ADD_INCLUDE_SERVICE:
657 BTA_GATTS_AddIncludeService(arg->add_incl_srvc.service_handle, arg->add_incl_srvc.included_service_handle);
658 break;
659 case BTC_GATTS_ACT_ADD_CHAR: {
660 tBT_UUID uuid;
661 btc_to_bta_uuid(&uuid, &arg->add_char.char_uuid);
662
663 BTA_GATTS_AddCharacteristic(arg->add_char.service_handle, &uuid,
664 arg->add_char.perm, arg->add_char.property,
665 (tGATT_ATTR_VAL *)&arg->add_char.char_val,
666 (tBTA_GATTS_ATTR_CONTROL *)&arg->add_char.attr_control);
667 break;
668 }
669 case BTC_GATTS_ACT_ADD_CHAR_DESCR: {
670 tBT_UUID uuid;
671 btc_to_bta_uuid(&uuid, &arg->add_descr.descr_uuid);
672 BTA_GATTS_AddCharDescriptor(arg->add_descr.service_handle, arg->add_descr.perm, &uuid,
673 (tBTA_GATT_ATTR_VAL *)&arg->add_descr.descr_val,
674 (tBTA_GATTS_ATTR_CONTROL *)&arg->add_descr.attr_control);
675 break;
676 }
677 case BTC_GATTS_ACT_SEND_INDICATE:
678 BTA_GATTS_HandleValueIndication(arg->send_ind.conn_id, arg->send_ind.attr_handle,
679 arg->send_ind.value_len, arg->send_ind.value, arg->send_ind.need_confirm);
680 break;
681 case BTC_GATTS_ACT_SEND_RESPONSE: {
682 esp_ble_gatts_cb_param_t param;
683 esp_gatt_rsp_t *p_rsp = arg->send_rsp.rsp;
684
685 if (p_rsp) {
686 tBTA_GATTS_RSP rsp_struct;
687 btc_to_bta_response(&rsp_struct, p_rsp);
688 BTA_GATTS_SendRsp(arg->send_rsp.conn_id, arg->send_rsp.trans_id,
689 arg->send_rsp.status, &rsp_struct);
690 param.rsp.handle = rsp_struct.attr_value.handle;
691 } else {
692 BTA_GATTS_SendRsp(arg->send_rsp.conn_id, arg->send_rsp.trans_id,
693 arg->send_rsp.status, NULL);
694 }
695
696 param.rsp.status = 0;
697 btc_gatts_cb_to_app(ESP_GATTS_RESPONSE_EVT, BTC_GATT_GET_GATT_IF(arg->send_rsp.conn_id), ¶m);
698 break;
699 }
700 case BTC_GATTS_ACT_SET_ATTR_VALUE:
701 BTA_SetAttributeValue(arg->set_attr_val.handle, arg->set_attr_val.length,
702 arg->set_attr_val.value);
703 break;
704 case BTC_GATTS_ACT_OPEN: {
705 // Ensure device is in inquiry database
706 tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE;
707
708 //TODO : implement address type and device type
709 #if 0
710 if (_get_address_type(arg->remote_bda, &addr_type) &&
711 btif_get_device_type(arg->remote_bda, &device_type) &&
712 device_type != BT_DEVICE_TYPE_BREDR) {
713 BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type);
714 }
715 #else
716 //BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type);
717 #endif
718 /*
719 not support background connection
720 // Mark background connections
721 if (!arg->open.is_direct) {
722 BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL);
723 }
724 */
725
726 transport = BTA_GATT_TRANSPORT_LE;
727
728 // Connect!
729 BTA_GATTS_Open(arg->open.gatts_if, arg->open.remote_bda,
730 arg->open.is_direct, transport);
731 break;
732 }
733 case BTC_GATTS_ACT_CLOSE:
734 // TODO : implement cancel open
735 // Cancel pending foreground/background connections
736 //BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, 1);
737 //BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, 0);
738
739 // Close active connection
740 if (arg->close.conn_id != 0) {
741 BTA_GATTS_Close(arg->close.conn_id);
742 }
743
744 break;
745 case BTC_GATTS_ACT_SEND_SERVICE_CHANGE: {
746 BD_ADDR remote_bda;
747 memcpy(remote_bda, arg->send_service_change.remote_bda, BD_ADDR_LEN);
748 BTA_GATTS_SendServiceChangeIndication(arg->send_service_change.gatts_if, remote_bda);
749 break;
750 }
751 default:
752 break;
753 }
754 btc_gatts_arg_deep_free(msg);
755 }
756
btc_gatts_cb_handler(btc_msg_t * msg)757 void btc_gatts_cb_handler(btc_msg_t *msg)
758 {
759 esp_ble_gatts_cb_param_t param;
760 tBTA_GATTS *p_data = (tBTA_GATTS *)msg->arg;
761 esp_gatt_if_t gatts_if;
762
763 switch (msg->act) {
764 case BTA_GATTS_REG_EVT: {
765 gatts_if = p_data->reg_oper.server_if;
766 param.reg.status = p_data->reg_oper.status;
767 param.reg.app_id = p_data->reg_oper.uuid.uu.uuid16;
768
769 btc_gatts_cb_to_app(ESP_GATTS_REG_EVT, gatts_if, ¶m);
770 break;
771 }
772 case BTA_GATTS_DEREG_EVT: {
773 gatts_if = p_data->reg_oper.server_if;
774 btc_gatts_cb_to_app(ESP_GATTS_UNREG_EVT, gatts_if, NULL);
775 break;
776 }
777 case BTA_GATTS_READ_EVT: {
778 gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
779 param.read.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
780 param.read.trans_id = p_data->req_data.trans_id;
781 memcpy(param.read.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
782 param.read.handle = p_data->req_data.p_data->read_req.handle;
783 param.read.offset = p_data->req_data.p_data->read_req.offset;
784 param.read.is_long = p_data->req_data.p_data->read_req.is_long;
785
786 param.read.need_rsp = p_data->req_data.p_data->read_req.need_rsp;
787 btc_gatts_cb_to_app(ESP_GATTS_READ_EVT, gatts_if, ¶m);
788 break;
789 }
790 case BTA_GATTS_WRITE_EVT: {
791 gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
792 param.write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
793 param.write.trans_id = p_data->req_data.trans_id;
794 memcpy(param.write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
795 if (p_data->req_data.p_data == NULL) {
796 break;
797 }
798 param.write.handle = p_data->req_data.p_data->write_req.handle;
799 param.write.offset = p_data->req_data.p_data->write_req.offset;
800 param.write.need_rsp = p_data->req_data.p_data->write_req.need_rsp;
801 param.write.is_prep = p_data->req_data.p_data->write_req.is_prep;
802 param.write.len = p_data->req_data.p_data->write_req.len;
803 param.write.value = p_data->req_data.p_data->write_req.value;
804
805 btc_gatts_cb_to_app(ESP_GATTS_WRITE_EVT, gatts_if, ¶m);
806
807 break;
808 }
809 case BTA_GATTS_EXEC_WRITE_EVT: {
810 gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
811 param.exec_write.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
812 param.exec_write.trans_id = p_data->req_data.trans_id;
813 memcpy(param.exec_write.bda, p_data->req_data.remote_bda, ESP_BD_ADDR_LEN);
814 if (p_data->req_data.p_data == NULL) {
815 break;
816 }
817 param.exec_write.exec_write_flag = p_data->req_data.p_data->exec_write;
818
819 btc_gatts_cb_to_app(ESP_GATTS_EXEC_WRITE_EVT, gatts_if, ¶m);
820 break;
821 }
822 case BTA_GATTS_MTU_EVT:
823 gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
824 param.mtu.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
825 param.mtu.mtu = p_data->req_data.p_data->mtu;
826
827 btc_gatts_cb_to_app(ESP_GATTS_MTU_EVT, gatts_if, ¶m);
828 break;
829 case BTA_GATTS_CONF_EVT:
830 gatts_if = BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id);
831 param.conf.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
832 param.conf.status = p_data->req_data.status;
833 param.conf.handle = p_data->req_data.handle;
834
835 if (p_data->req_data.status != ESP_GATT_OK && p_data->req_data.value){
836 param.conf.len = p_data->req_data.data_len;
837 param.conf.value = p_data->req_data.value;
838 }else{
839 param.conf.len = 0;
840 }
841 btc_gatts_cb_to_app(ESP_GATTS_CONF_EVT, gatts_if, ¶m);
842 break;
843 case BTA_GATTS_CREATE_EVT:
844 gatts_if = p_data->create.server_if;
845 param.create.status = p_data->create.status;
846 param.create.service_handle = p_data->create.service_id;
847 param.create.service_id.is_primary = p_data->create.is_primary;
848 param.create.service_id.id.inst_id = p_data->create.svc_instance;
849 bta_to_btc_uuid(¶m.create.service_id.id.uuid, &p_data->create.uuid);
850
851 btc_gatts_cb_to_app(ESP_GATTS_CREATE_EVT, gatts_if, ¶m);
852 break;
853 case BTA_GATTS_ADD_INCL_SRVC_EVT:
854 gatts_if = p_data->add_result.server_if;
855 param.add_incl_srvc.status = p_data->add_result.status;
856 param.add_incl_srvc.attr_handle = p_data->add_result.attr_id;
857 param.add_incl_srvc.service_handle = p_data->add_result.service_id;
858
859 btc_gatts_cb_to_app(ESP_GATTS_ADD_INCL_SRVC_EVT, gatts_if, ¶m);
860 break;
861 case BTA_GATTS_ADD_CHAR_EVT:
862 gatts_if = p_data->add_result.server_if;
863 param.add_char.status = p_data->add_result.status;
864 param.add_char.attr_handle = p_data->add_result.attr_id;
865 param.add_char.service_handle = p_data->add_result.service_id;
866 bta_to_btc_uuid(¶m.add_char.char_uuid, &p_data->add_result.char_uuid);
867
868 btc_gatts_cb_to_app(ESP_GATTS_ADD_CHAR_EVT, gatts_if, ¶m);
869 break;
870 case BTA_GATTS_ADD_CHAR_DESCR_EVT:
871 gatts_if = p_data->add_result.server_if;
872 param.add_char_descr.status = p_data->add_result.status;
873 param.add_char_descr.attr_handle = p_data->add_result.attr_id;
874 param.add_char_descr.service_handle = p_data->add_result.service_id;
875 bta_to_btc_uuid(¶m.add_char_descr.descr_uuid, &p_data->add_result.char_uuid);
876
877 btc_gatts_cb_to_app(ESP_GATTS_ADD_CHAR_DESCR_EVT, gatts_if, ¶m);
878 break;
879 case BTA_GATTS_DELELTE_EVT:
880 gatts_if = p_data->srvc_oper.server_if;
881 param.del.status = p_data->srvc_oper.status;
882 param.del.service_handle = p_data->srvc_oper.service_id;
883
884 btc_gatts_cb_to_app(ESP_GATTS_DELETE_EVT, gatts_if, ¶m);
885 break;
886 case BTA_GATTS_START_EVT:
887 gatts_if = p_data->srvc_oper.server_if;
888 param.start.status = p_data->srvc_oper.status;
889 param.start.service_handle = p_data->srvc_oper.service_id;
890
891 btc_gatts_cb_to_app(ESP_GATTS_START_EVT, gatts_if, ¶m);
892 break;
893 case BTA_GATTS_STOP_EVT:
894 gatts_if = p_data->srvc_oper.server_if;
895 param.stop.status = p_data->srvc_oper.status;
896 param.stop.service_handle = p_data->srvc_oper.service_id;
897
898 btc_gatts_cb_to_app(ESP_GATTS_STOP_EVT, gatts_if, ¶m);
899 break;
900 case BTA_GATTS_CONNECT_EVT:
901 gatts_if = p_data->conn.server_if;
902 param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
903 param.connect.link_role = p_data->conn.link_role;
904 memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN);
905 param.connect.conn_params.interval = p_data->conn.conn_params.interval;
906 param.connect.conn_params.latency = p_data->conn.conn_params.latency;
907 param.connect.conn_params.timeout = p_data->conn.conn_params.timeout;
908 btc_gatts_cb_to_app(ESP_GATTS_CONNECT_EVT, gatts_if, ¶m);
909 break;
910 case BTA_GATTS_DISCONNECT_EVT:
911 gatts_if = p_data->conn.server_if;
912 param.disconnect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
913 param.disconnect.reason = p_data->conn.reason;
914 memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN);
915
916 btc_gatts_cb_to_app(ESP_GATTS_DISCONNECT_EVT, gatts_if, ¶m);
917 break;
918 case BTA_GATTS_OPEN_EVT:
919 gatts_if = p_data->open.server_if;
920 param.open.status = p_data->open.status;
921
922 btc_gatts_cb_to_app(BTA_GATTS_OPEN_EVT, gatts_if, ¶m);
923 break;
924 case BTA_GATTS_CANCEL_OPEN_EVT:
925 gatts_if = p_data->cancel_open.server_if;
926 param.cancel_open.status = p_data->cancel_open.status;
927
928 btc_gatts_cb_to_app(BTA_GATTS_CANCEL_OPEN_EVT, gatts_if, ¶m);
929 break;
930
931 case BTA_GATTS_CLOSE_EVT:
932 gatts_if = BTC_GATT_GET_GATT_IF(p_data->close.conn_id);
933 param.close.status = p_data->close.status;
934 param.close.conn_id = BTC_GATT_GET_CONN_ID(p_data->close.conn_id);
935
936 btc_gatts_cb_to_app(BTA_GATTS_CLOSE_EVT, gatts_if, ¶m);
937 break;
938 case BTA_GATTS_SEND_SERVICE_CHANGE_EVT:
939 gatts_if = p_data->service_change.server_if;
940 param.service_change.status = p_data->service_change.status;
941 btc_gatts_cb_to_app(ESP_GATTS_SEND_SERVICE_CHANGE_EVT, gatts_if, ¶m);
942 break;
943 case BTA_GATTS_LISTEN_EVT:
944 // do nothing
945 break;
946 case BTA_GATTS_CONGEST_EVT:
947 gatts_if = BTC_GATT_GET_GATT_IF(p_data->congest.conn_id);
948 param.congest.conn_id = BTC_GATT_GET_CONN_ID(p_data->congest.conn_id);
949 param.congest.congested = p_data->congest.congested;
950 btc_gatts_cb_to_app(ESP_GATTS_CONGEST_EVT, gatts_if, ¶m);
951 break;
952 case BTA_GATTS_SET_ATTR_VAL_EVT:
953 gatts_if = p_data->attr_val.server_if;
954 param.set_attr_val.srvc_handle = p_data->attr_val.service_id;
955 param.set_attr_val.attr_handle = p_data->attr_val.attr_id;
956 param.set_attr_val.status = p_data->attr_val.status;
957 btc_gatts_cb_to_app(ESP_GATTS_SET_ATTR_VAL_EVT, gatts_if, ¶m);
958 break;
959 default:
960 // do nothing
961 break;
962 }
963
964 btc_gatts_cb_param_copy_free(msg, p_data);
965 }
966
btc_congest_callback(tBTA_GATTS * param)967 void btc_congest_callback(tBTA_GATTS *param)
968 {
969 esp_ble_gatts_cb_param_t esp_param;
970 esp_gatt_if_t gatts_if = BTC_GATT_GET_GATT_IF(param->congest.conn_id);
971 esp_param.congest.conn_id = BTC_GATT_GET_CONN_ID(param->congest.conn_id);
972 esp_param.congest.congested = param->congest.congested;
973 btc_gatts_cb_to_app(ESP_GATTS_CONGEST_EVT, gatts_if, &esp_param);
974 }
975
976 #endif ///GATTS_INCLUDED
977