1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
72
73
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
132
133
134
135
136
137
138
139
140
141
142
143
147
148
149
152
153
156
157
158
159
160
161
164
167
175
183
190
192
193
194
195
196
197
198
199
204
205
213
214
215
216
217
218
219
220
221
222
225
226
230
233
234
235
236
237
238
239
240
241
242
243
244
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
299
300
301
302
303
304
305
306
307
311
312
313
314
315
316
319
320
321
322
323
324
325
326
327
328
333
336
338
339
340
341
342
343
344
345
346
347
348
349
350
353
354
356
357
358
359
360
361
362
363
364
367
368
369
374
376
380
382
391
397
398
399
400
401
402
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
447
448
449
450
451
452
453
454
455
459
460
461
462
463
464
467
468
469
470
471
472
473
474
475
480
483
485
486
487
488
489
490
491
492
493
494
495
496
497
500
501
503
504
505
506
507
508
509
510
511
512
513
514
519
521
525
527
534
540
541
542
543
544
545
546
548
549
550
551
552
553
554
564
565
567
578
579
580
581
582
583
587
588
592
593
597
598
602
603
606
607
608
611
612
613
614
615
616
617
620
621
622
623
624
625
634
635
636
649
650
651
652
656
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
698
699
700
701
704
705
706
707
708
709
713
714
715
716
720
721
725
726
727
728
729
730
734
735
739
740
741
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
/* ... */
/* ... */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "bt_app_core.h"
#include "bt_app_av.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_bt_api.h"
#include "esp_a2dp_api.h"
#include "esp_avrc_api.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_gatt_common_api.h"23 includes
#define BT_BLE_COEX_TAG "BT_BLE_COEX"
#define BTDM_DEVICE_NAME "ESP_COEX_BTDM_DEMO"
#define BLE_ADV_NAME "ESP_COEX_BLE_DEMO"
#define GATTS_SERVICE_UUID_A 0x00FF
#define GATTS_CHAR_UUID_A 0xFF01
#define GATTS_DESCR_UUID_A 0x3333
#define GATTS_NUM_HANDLE_A 4
#define GATTS_SERVICE_UUID_B 0x00EE
#define GATTS_CHAR_UUID_B 0xEE01
#define GATTS_DESCR_UUID_B 0x2222
#define GATTS_NUM_HANDLE_B 4
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
#define PREPARE_BUF_MAX_SIZE 1024
#define PROFILE_NUM 2
#define PROFILE_A_APP_ID 0
#define PROFILE_B_APP_ID 116 defines
enum {
BT_APP_EVT_STACK_UP = 0,
}{ ... };
typedef struct {
uint8_t *prepare_buf;
int prepare_len;
}{ ... } prepare_type_env_t;
static prepare_type_env_t a_prepare_write_env;
static prepare_type_env_t b_prepare_write_env;
static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
static uint8_t ble_char_value_str[] = {0x11, 0x22, 0x33};
esp_gatt_char_prop_t a_property = 0;
esp_gatt_char_prop_t b_property = 0;
esp_attr_value_t gatts_initial_char_val = {
.attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX,
.attr_len = sizeof(ble_char_value_str),
.attr_value = ble_char_value_str,
}{...};
static esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x060,
.adv_int_max = 0x060,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
}{...};
struct gatts_profile_inst {
esp_gatts_cb_t gatts_cb;
uint16_t gatts_if;
uint16_t app_id;
uint16_t conn_id;
uint16_t service_handle;
esp_gatt_srvc_id_t service_id;
uint16_t char_handle;
esp_bt_uuid_t char_uuid;
esp_gatt_perm_t perm;
esp_gatt_char_prop_t property;
uint16_t descr_handle;
esp_bt_uuid_t descr_uuid;
}{ ... };
static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
[PROFILE_A_APP_ID] = {
.gatts_cb = gatts_profile_a_event_handler,
.gatts_if = ESP_GATT_IF_NONE,
}{...},
[PROFILE_B_APP_ID] = {
.gatts_cb = gatts_profile_b_event_handler,
.gatts_if = ESP_GATT_IF_NONE,
}{...},
}{...};
static void ble_init_adv_data(const char *name)
{
int len = strlen(name);
uint8_t raw_adv_data[len+5];
raw_adv_data[0] = 2;
raw_adv_data[1] = ESP_BT_EIR_TYPE_FLAGS;
raw_adv_data[2] = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT);
raw_adv_data[3] = len + 1;
raw_adv_data[4] = ESP_BLE_AD_TYPE_NAME_CMPL;
for (int i = 0;i < len;i++)
{
raw_adv_data[i+5] = *(name++);
}{...}
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
if (raw_adv_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "config raw adv data failed, error code = 0x%x ", raw_adv_ret);
}{...}
esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_adv_data, sizeof(raw_adv_data));
if (raw_scan_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "config raw scan rsp data failed, error code = 0x%x", raw_scan_ret);
}{...}
}{ ... }
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
break;...
case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
esp_ble_gap_start_advertising(&adv_params);
break;...
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(BT_BLE_COEX_TAG, "Advertising start failed");
}{...}else {
ESP_LOGI(BT_BLE_COEX_TAG, "Start adv successfully");
}
break;...
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(BT_BLE_COEX_TAG, "Advertising stop failed");
}{...}
else {
ESP_LOGI(BT_BLE_COEX_TAG, "Stop adv successfully");
}{...}
break;...
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "update connection params status = %d, conn_int = %d, latency = %d, timeout = %d",
param->update_conn_params.status,
param->update_conn_params.conn_int,
param->update_conn_params.latency,
param->update_conn_params.timeout);
break;...
default:
break;...
}{...}
}{ ... }
void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
esp_gatt_status_t status = ESP_GATT_OK;
if (param->write.need_rsp){
if (param->write.is_prep) {
if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_OFFSET;
}{...} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_ATTR_LEN;
}{...}
if (status == ESP_GATT_OK && prepare_write_env->prepare_buf == NULL) {
prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE*sizeof(uint8_t));
prepare_write_env->prepare_len = 0;
if (prepare_write_env->prepare_buf == NULL) {
ESP_LOGE(BT_BLE_COEX_TAG, "Gatt_server prep no mem");
status = ESP_GATT_NO_RESOURCES;
}{...}
}{...}
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
if (gatt_rsp) {
gatt_rsp->attr_value.len = param->write.len;
gatt_rsp->attr_value.handle = param->write.handle;
gatt_rsp->attr_value.offset = param->write.offset;
gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
if (response_err != ESP_OK){
ESP_LOGE(BT_BLE_COEX_TAG, "Send response error\n");
}{...}
free(gatt_rsp);
}{...} else {
ESP_LOGE(BT_BLE_COEX_TAG, "%s, malloc failed", __func__);
status = ESP_GATT_NO_RESOURCES;
}{...}
if (status != ESP_GATT_OK){
return;
}{...}
memcpy(prepare_write_env->prepare_buf + param->write.offset,
param->write.value,
param->write.len);
prepare_write_env->prepare_len += param->write.len;
}{...}else{
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL);
}
}{...}
}{ ... }
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC){
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
}{...}else{
ESP_LOGI(BT_BLE_COEX_TAG,"ESP_GATT_PREP_WRITE_CANCEL");
}
if (prepare_write_env->prepare_buf) {
free(prepare_write_env->prepare_buf);
prepare_write_env->prepare_buf = NULL;
}{...}
prepare_write_env->prepare_len = 0;
}{ ... }
static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
switch (event) {
case ESP_GATTS_REG_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "REGISTER_APP_EVT, status %d, app_id %d", param->reg.status, param->reg.app_id);
esp_ble_gap_config_local_privacy(true);
gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_A;
ble_init_adv_data(BLE_ADV_NAME);
esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_A);
break;...
case ESP_GATTS_READ_EVT: {
ESP_LOGI(BT_BLE_COEX_TAG, "GATT_READ_EVT, conn_id %d, trans_id %"PRIu32", handle %d", param->read.conn_id, param->read.trans_id, param->read.handle);
esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
rsp.attr_value.len = 4;
rsp.attr_value.value[0] = 0xde;
rsp.attr_value.value[1] = 0xed;
rsp.attr_value.value[2] = 0xbe;
rsp.attr_value.value[3] = 0xef;
esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
ESP_GATT_OK, &rsp);
break;
}{...}
... case ESP_GATTS_WRITE_EVT: {
ESP_LOGI(BT_BLE_COEX_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %"PRIu32", handle %d", param->write.conn_id, param->write.trans_id, param->write.handle);
if (!param->write.is_prep){
ESP_LOGI(BT_BLE_COEX_TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len);
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, param->write.value, param->write.len);
if (gl_profile_tab[PROFILE_A_APP_ID].descr_handle == param->write.handle && param->write.len == 2){
uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001){
if (a_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY){
ESP_LOGI(BT_BLE_COEX_TAG, "notify enable");
uint8_t notify_data[15];
for (int i = 0; i < sizeof(notify_data); ++i)
{
notify_data[i] = i%0xff;
}{...}
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(notify_data), notify_data, false);
}{...}
}{...}else if (descr_value == 0x0002){
if (a_property & ESP_GATT_CHAR_PROP_BIT_INDICATE){
ESP_LOGI(BT_BLE_COEX_TAG, "indicate enable");
uint8_t indicate_data[15];
for (int i = 0; i < sizeof(indicate_data); ++i)
{
indicate_data[i] = i%0xff;
}{...}
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
sizeof(indicate_data), indicate_data, true);
}{...}
}{...}
else if (descr_value == 0x0000){
ESP_LOGI(BT_BLE_COEX_TAG, "notify/indicate disable ");
}{...}else{
ESP_LOGE(BT_BLE_COEX_TAG, "unknown descr value");
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, param->write.value, param->write.len);
}
}{...}
}{...}
example_write_event_env(gatts_if, &a_prepare_write_env, param);
break;
}{...}
... case ESP_GATTS_EXEC_WRITE_EVT:
ESP_LOGI(BT_BLE_COEX_TAG,"ESP_GATTS_EXEC_WRITE_EVT");
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
example_exec_write_event_env(&a_prepare_write_env, param);
break;...
case ESP_GATTS_MTU_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
break;...
case ESP_GATTS_UNREG_EVT:
break;...
case ESP_GATTS_CREATE_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d", param->create.status, param->create.service_handle);
gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle;
gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_A;
esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle);
a_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
esp_err_t add_char_ret = esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
a_property,
&gatts_initial_char_val, NULL);
if (add_char_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "add char failed, error code = 0x%x",add_char_ret);
}{...}
break;...
case ESP_GATTS_ADD_INCL_SRVC_EVT:
break;...
case ESP_GATTS_ADD_CHAR_EVT: {
ESP_LOGI(BT_BLE_COEX_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d",
param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle;
gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
esp_err_t add_descr_ret = esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
if (add_descr_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "add char descr failed, error code = 0x%x", add_descr_ret);
}{...}
break;
}{...}
... case ESP_GATTS_ADD_CHAR_DESCR_EVT:
gl_profile_tab[PROFILE_A_APP_ID].descr_handle = param->add_char_descr.attr_handle;
ESP_LOGI(BT_BLE_COEX_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d",
param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;...
case ESP_GATTS_DELETE_EVT:
break;...
case ESP_GATTS_START_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "SERVICE_START_EVT, status %d, service_handle %d",
param->start.status, param->start.service_handle);
break;...
case ESP_GATTS_STOP_EVT:
break;...
case ESP_GATTS_CONNECT_EVT: {
esp_ble_conn_update_params_t conn_params = {0};
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
break;
}{...}
... case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_GATTS_DISCONNECT_EVT");
esp_ble_gap_start_advertising(&adv_params);
break;...
case ESP_GATTS_CONF_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_GATTS_CONF_EVT, status %d", param->conf.status);
if (param->conf.status != ESP_GATT_OK){
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, param->conf.value, param->conf.len);
}{...}
break;...
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
default:
break;...
}{...}
}{ ... }
static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
switch (event) {
case ESP_GATTS_REG_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "REGISTER_APP_EVT, status %d, app_id %d", param->reg.status, param->reg.app_id);
gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true;
gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00;
gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_B;
esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_B);
break;...
case ESP_GATTS_READ_EVT: {
ESP_LOGI(BT_BLE_COEX_TAG, "GATT_READ_EVT, conn_id %d, trans_id %"PRIu32", handle %d", param->read.conn_id, param->read.trans_id, param->read.handle);
esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
rsp.attr_value.len = 4;
rsp.attr_value.value[0] = 0xde;
rsp.attr_value.value[1] = 0xed;
rsp.attr_value.value[2] = 0xbe;
rsp.attr_value.value[3] = 0xef;
esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
ESP_GATT_OK, &rsp);
break;
}{...}
... case ESP_GATTS_WRITE_EVT: {
ESP_LOGI(BT_BLE_COEX_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %"PRIu32", handle %d", param->write.conn_id, param->write.trans_id, param->write.handle);
if (!param->write.is_prep){
ESP_LOGI(BT_BLE_COEX_TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len);
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, param->write.value, param->write.len);
if (gl_profile_tab[PROFILE_B_APP_ID].descr_handle == param->write.handle && param->write.len == 2){
uint16_t descr_value= param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001){
if (b_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY){
ESP_LOGI(BT_BLE_COEX_TAG, "notify enable");
uint8_t notify_data[15];
for (int i = 0; i < sizeof(notify_data); ++i)
{
notify_data[i] = i%0xff;
}{...}
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_B_APP_ID].char_handle,
sizeof(notify_data), notify_data, false);
}{...}
}{...}else if (descr_value == 0x0002){
if (b_property & ESP_GATT_CHAR_PROP_BIT_INDICATE){
ESP_LOGI(BT_BLE_COEX_TAG, "indicate enable");
uint8_t indicate_data[15];
for (int i = 0; i < sizeof(indicate_data); ++i)
{
indicate_data[i] = i%0xff;
}{...}
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_B_APP_ID].char_handle,
sizeof(indicate_data), indicate_data, true);
}{...}
}{...}
else if (descr_value == 0x0000){
ESP_LOGI(BT_BLE_COEX_TAG, "notify/indicate disable ");
}{...}else{
ESP_LOGE(BT_BLE_COEX_TAG, "unknown value");
}
}{...}
}{...}
example_write_event_env(gatts_if, &b_prepare_write_env, param);
break;
}{...}
... case ESP_GATTS_EXEC_WRITE_EVT:
ESP_LOGI(BT_BLE_COEX_TAG,"ESP_GATTS_EXEC_WRITE_EVT");
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
example_exec_write_event_env(&b_prepare_write_env, param);
break;...
case ESP_GATTS_MTU_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
break;...
case ESP_GATTS_UNREG_EVT:
break;...
case ESP_GATTS_CREATE_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d", param->create.status, param->create.service_handle);
gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle;
gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_B;
esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle);
b_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
esp_err_t add_char_ret =esp_ble_gatts_add_char( gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
b_property,
NULL, NULL);
if (add_char_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "add char failed, error code = 0x%x",add_char_ret);
}{...}
break;...
case ESP_GATTS_ADD_INCL_SRVC_EVT:
break;...
case ESP_GATTS_ADD_CHAR_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d",
param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle;
gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
NULL, NULL);
break;...
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
gl_profile_tab[PROFILE_B_APP_ID].descr_handle = param->add_char_descr.attr_handle;
ESP_LOGI(BT_BLE_COEX_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d",
param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;...
case ESP_GATTS_DELETE_EVT:
break;...
case ESP_GATTS_START_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "SERVICE_START_EVT, status %d, service_handle %d",
param->start.status, param->start.service_handle);
break;...
case ESP_GATTS_STOP_EVT:
break;...
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:",
param->connect.conn_id,
param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2],
param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]);
gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id;
break;...
case ESP_GATTS_CONF_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_GATTS_CONF_EVT status %d", param->conf.status);
if (param->conf.status != ESP_GATT_OK){
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, param->conf.value, param->conf.len);
}{...}
break;...
case ESP_GATTS_DISCONNECT_EVT:
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
default:
break;...
}{...}
}{ ... }
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
gl_profile_tab[param->reg.app_id].gatts_if = gatts_if;
}{...} else {
ESP_LOGI(BT_BLE_COEX_TAG, "Reg app failed, app_id %04x, status %d",
param->reg.app_id,
param->reg.status);
return;
}{...}
}{...}
/* ... */
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
if (gatts_if == ESP_GATT_IF_NONE ||
gatts_if == gl_profile_tab[idx].gatts_if) {
if (gl_profile_tab[idx].gatts_cb) {
gl_profile_tab[idx].gatts_cb(event, gatts_if, param);
}{...}
}{...}
}{...}
}{...} while (0);
}{ ... }
static void ble_gatts_init(void)
{
esp_err_t ret = esp_ble_gatts_register_callback(gatts_event_handler);
if (ret){
ESP_LOGE(BT_BLE_COEX_TAG, "gatts register error, error code = 0x%x", ret);
return;
}{...}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(BT_BLE_COEX_TAG, "gap register error, error code = 0x%x", ret);
return;
}{...}
ret = esp_ble_gatts_app_register(PROFILE_A_APP_ID);
if (ret){
ESP_LOGE(BT_BLE_COEX_TAG, "gatts app register error, error code = 0x%x", ret);
return;
}{...}
ret = esp_ble_gatts_app_register(PROFILE_B_APP_ID);
if (ret){
ESP_LOGE(BT_BLE_COEX_TAG, "gatts app register error, error code = 0x%x", ret);
return;
}{...}
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
if (local_mtu_ret){
ESP_LOGE(BT_BLE_COEX_TAG, "set local MTU failed, error code = 0x%x", local_mtu_ret);
}{...}
}{ ... }
/* ... */
static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
/* ... */
static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
switch (event) {
case ESP_BT_GAP_AUTH_CMPL_EVT: {
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(BT_BLE_COEX_TAG, "authentication success: %s", param->auth_cmpl.device_name);
ESP_LOG_BUFFER_HEX(BT_BLE_COEX_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
}{...} else {
ESP_LOGE(BT_BLE_COEX_TAG, "authentication failed, status: %d", param->auth_cmpl.stat);
}{...}
break;
}{...}
#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
case ESP_BT_GAP_CFM_REQ_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %"PRIu32, param->cfm_req.num_val);
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
break;
...
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey: %"PRIu32, param->key_notif.passkey);
break;
...
case ESP_BT_GAP_KEY_REQ_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;/* ... */
#endif
case ESP_BT_GAP_MODE_CHG_EVT:
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode: %d", param->mode_chg.mode);
break;
...
default: {
ESP_LOGI(BT_BLE_COEX_TAG, "event: %d", event);
break;
}{...}
... }{...}
}{ ... }
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
{
ESP_LOGD(BT_BLE_COEX_TAG, "%s event: %d", __func__, event);
switch (event) {
case BT_APP_EVT_STACK_UP: {
esp_bt_gap_set_device_name(BTDM_DEVICE_NAME);
esp_ble_gap_set_device_name(BTDM_DEVICE_NAME);
esp_bt_gap_register_callback(bt_app_gap_cb);
assert(esp_avrc_ct_init() == ESP_OK);
esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
assert(esp_avrc_tg_init() == ESP_OK);
esp_avrc_tg_register_callback(bt_app_rc_tg_cb);
esp_avrc_rn_evt_cap_mask_t evt_set = {0};
esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
assert(esp_a2d_sink_init() == ESP_OK);
esp_a2d_register_callback(&bt_app_a2d_cb);
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
esp_a2d_sink_get_delay_value();
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
break;
}{...}
...
default:
ESP_LOGE(BT_BLE_COEX_TAG, "%s unhandled event: %d", __func__, event);
break;...
}{...}
}{ ... }
/* ... */
void app_main(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}{...}
ESP_ERROR_CHECK(err);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(BT_BLE_COEX_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(err));
return;
}{...}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_BTDM)) != ESP_OK) {
ESP_LOGE(BT_BLE_COEX_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(err));
return;
}{...}
esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == false)
bluedroid_cfg.ssp_en = false;
#endif
if ((err = esp_bluedroid_init_with_cfg(&bluedroid_cfg)) != ESP_OK) {
ESP_LOGE(BT_BLE_COEX_TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(err));
return;
}{...}
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(BT_BLE_COEX_TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(err));
return;
}{...}
#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));/* ... */
#endif
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_set_pin(pin_type, 4, pin_code);
bt_app_task_start_up();
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
ble_gatts_init();
}{ ... }