2 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
20 //#include "bluedroid_test.h"
21 #include "bta/bta_api.h"
22 #include "bta/bta_gatt_api.h"
23 #include "device/controller.h"
26 #include "common/bt_trace.h"
27 #include "stack/btm_api.h"
28 #include "stack/bt_types.h"
31 #if BLE_INCLUDED == true
33 #define BA_MAX_CHAR_NUM 1
34 #define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1)
35 /*max 3 descriptors, 1 desclaration and 1 value*/
37 #ifndef BATTER_LEVEL_PROP
38 #define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)
41 #ifndef BATTER_LEVEL_PERM
42 #define BATTER_LEVEL_PERM (GATT_PERM_READ)
45 #define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
46 #define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
47 esp_gatts_if_t server_if;
49 tBATTERY_CB battery_cb;
50 tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ;
51 tBA_REG_INFO ba_reg_info;
52 UINT8 attr_handle_bit = 0x00;
54 extern tDIS_CB dis_cb;
55 esp_bt_uuid_t bas_uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
56 /******************************************************************************
57 ** Function bas_gatts_callback
59 ** Description battery service register callback function
60 *******************************************************************************/
61 static void bas_gatts_callback(esp_gatts_evt_t event, tBTA_GATTS *p_data)
64 case ESP_GATTS_REG_EVT: {
65 esp_gatt_status_t status = p_data->reg_oper.status;
66 server_if = p_data->reg_oper.server_if;
67 BTC_TRACE_ERROR("BAS register completed: event=%d, status=%d, server_if=%d\n",
68 event, status, server_if);
71 bas_init(server_if, app_id);
73 tDIS_ATTR_MASK mask = 0x01ff;
74 DIS_Init(server_if, mask);
79 case ESP_GATTS_CONNECT_EVT: {
80 BTC_TRACE_ERROR("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
81 BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
82 p_data->conn.reason, p_data->conn.conn_id);
83 /*return whether the remote device is currently connected*/
84 int is_connected = BTA_DmGetConnectionState(p_data->conn.remote_bda);
85 BTC_TRACE_ERROR("is_connected=%d\n", is_connected);
89 /*create service callback*/
90 case ESP_GATTS_CREATE_EVT: {
91 BTC_TRACE_ERROR("create service:server_if=%d,service_id=0x%x,service_uuid=0x%x\n",
92 p_data->create.server_if, p_data->create.service_id,
93 p_data->create.uuid.uu.uuid16);
94 UINT16 service_uuid = p_data->create.uuid.uu.uuid16;
95 UINT16 service_id = p_data->create.service_id;
96 if (service_uuid == 0x180f) {
97 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_BATTERY_LEVEL}};
98 bas_AddChar(service_id, &uuid);
100 if (service_uuid == 0x180a) {
101 dis_cb.service_handle = service_id;
102 dis_cb.max_handle = service_id + DIS_MAX_ATTR_NUM;
103 dis_AddChar(service_id);
109 case ESP_GATTS_ADD_CHAR_EVT: {
110 BTC_TRACE_ERROR("create characteristic:server_if=%d,service_id=0x%x,char_uuid=0x%x\n",
111 p_data->add_result.server_if, p_data->add_result.service_id,
112 p_data->add_result.char_uuid.uu.uuid16);
113 UINT16 char_uuid = p_data->add_result.char_uuid.uu.uuid16;
114 UINT16 service_id = p_data->add_result.service_id;
115 if (char_uuid == GATT_UUID_BATTERY_LEVEL) {
116 bas_AddCharDescr(service_id, p_data->add_result.attr_id);
118 if (char_uuid == GATT_UUID_SYSTEM_ID | GATT_UUID_MODEL_NUMBER_STR | GATT_UUID_PNP_ID |
119 GATT_UUID_SERIAL_NUMBER_STR | GATT_UUID_FW_VERSION_STR | GATT_UUID_HW_VERSION_STR |
120 GATT_UUID_SW_VERSION_STR | GATT_UUID_MANU_NAME | GATT_UUID_IEEE_DATA) {
122 case GATT_UUID_SYSTEM_ID:
123 dis_cb.dis_attr[0].handle = service_id; break;
124 case GATT_UUID_MODEL_NUMBER_STR:
125 dis_cb.dis_attr[1].handle = service_id; break;
126 case GATT_UUID_SERIAL_NUMBER_STR:
127 dis_cb.dis_attr[2].handle = service_id; break;
128 case GATT_UUID_FW_VERSION_STR:
129 dis_cb.dis_attr[3].handle = service_id; break;
130 case GATT_UUID_HW_VERSION_STR:
131 dis_cb.dis_attr[4].handle = service_id; break;
132 case GATT_UUID_SW_VERSION_STR:
133 dis_cb.dis_attr[5].handle = service_id; break;
134 case GATT_UUID_MANU_NAME:
135 dis_cb.dis_attr[6].handle = service_id; break;
136 case GATT_UUID_IEEE_DATA:
137 dis_cb.dis_attr[7].handle = service_id; break;
138 case GATT_UUID_PNP_ID:
139 dis_cb.dis_attr[8].handle = service_id; break;
145 case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
147 BTC_TRACE_ERROR("create descriptor:server_if=%d,service_id=0x%x,attr_id=0x%x,char_uuid=0x%x\n",
148 p_data->add_result.server_if, p_data->add_result.service_id,
149 p_data->add_result.attr_id, p_data->add_result.char_uuid.uu.uuid16);
150 bas_AddCharDescr(p_data->add_result.service_id, p_data->add_result.attr_id);
154 case ESP_GATTS_START_EVT: {
155 BTC_TRACE_ERROR("start service:server_if=%d,service_id=0x%x\n", p_data->srvc_oper.server_if,
156 p_data->srvc_oper.service_id);
157 bas_service_cmpl(p_data->srvc_oper.service_id, p_data->srvc_oper.status);
159 /*start advertising*/
160 //if(p_data->srvc_oper.status == GATT_SUCCESS)
161 // BTA_GATTS_Listen(server_if, true, NULL);
162 // BTA_GATTC_Broadcast(client_if, true); //non-connectable
166 case ESP_GATTS_READ_EVT: {
167 UINT32 trans_id = p_data->req_data.trans_id;
168 UINT16 conn_id = p_data->req_data.conn_id;
169 UINT16 handle = p_data->req_data.p_data->read_req.handle;
170 bool is_long = p_data->req_data.p_data->read_req.is_long;
171 BTC_TRACE_ERROR("read request:event=0x%x,handle=0x%x,trans_id=0x%x,conn_id=0x%x\n",
172 event, handle, trans_id, conn_id);
174 if (dis_valid_handle_range(handle)) {
176 p_value.handle = handle;
177 p_value.conn_id = conn_id;
178 p_value.offset = p_data->req_data.p_data->read_req.offset;
179 dis_s_read_attr_value(p_data->req_data.p_data, &p_value, trans_id, conn_id);
181 bas_s_read_attr_value(p_data->req_data.p_data, trans_id, conn_id);
186 case ESP_GATTS_WRITE_EVT: {
188 UINT32 trans_id = p_data->req_data.trans_id;
189 UINT16 conn_id = p_data->req_data.conn_id;
190 UINT16 handle = p_data->req_data.p_data->write_req.handle;
191 BTC_TRACE_ERROR("write request:event=0x%x,handle=0x%x,trans_id=0x%x,conn_id=0x%x\n",
192 event, handle, trans_id, conn_id);
193 bas_s_write_attr_value(p_data->req_data.p_data, trans_id, conn_id,
194 p_data->req_data.remote_bda);
198 case ESP_GATTS_EXEC_WRITE_EVT: {
199 UINT32 trans_id = p_data->req_data.trans_id;
200 UINT16 conn_id = p_data->req_data.conn_id;
201 UINT8 exec_write = p_data->req_data.p_data->exec_write;
202 BTC_TRACE_ERROR("execute write request:event=0x%x,exce_write=0x%x,trans_id=0x%x,conn_id=0x%x\n",
203 event, exec_write, trans_id, conn_id);
207 case ESP_GATTS_MTU_EVT: {
208 UINT32 trans_id = p_data->req_data.trans_id;
209 UINT16 conn_id = p_data->req_data.conn_id;
210 UINT16 mtu = p_data->req_data.p_data->mtu;
211 BTC_TRACE_ERROR("exchange mtu request:event=0x%x,mtu=0x%x,trans_id=0x%x,conn_id=0x%x\n",
212 event, mtu, trans_id, conn_id);
216 case ESP_GATTS_CFM_EVT: {
218 UINT32 trans_id = p_data->req_data.trans_id;
219 UINT16 conn_id = p_data->req_data.conn_id;
220 BTC_TRACE_ERROR("configue request:trans_id=0x%x,conn_id=0x%x\n",
226 BTC_TRACE_ERROR("unsettled event: %d\n", event);
231 /******************************************************************************
232 ** Function bas_callback
234 ** Description battery service callback for client request
235 *******************************************************************************/
236 static void bas_callback(UINT32 trans_id, UINT16 conn_id, UINT8 app_id,
237 UINT8 event, tBA_WRITE_DATA *p_data)
240 tGATT_STATUS st = ESP_GATT_OK;
242 case BA_READ_LEVEL_REQ : {
243 BTC_TRACE_ERROR("read battery level\n");
244 p_rsp.ba_level = 60; //battery level
245 Battery_Rsp(trans_id, conn_id, app_id, st, event, &p_rsp);
249 case BA_READ_PRE_FMT_REQ : {
250 BTC_TRACE_ERROR("read presentation format\n");
254 case BA_READ_CLT_CFG_REQ : {
255 BTC_TRACE_ERROR("read client characteristic configuration request\n");
256 p_rsp.clt_cfg = 0x0001; //notification
257 Battery_Rsp(trans_id, conn_id, app_id, st, event, &p_rsp);
261 case BA_READ_RPT_REF_REQ : {
262 BTC_TRACE_ERROR("read report reference descriptor\n");
266 /*battery level notify*/
267 case BA_WRITE_CLT_CFG_REQ : {
268 BTC_TRACE_ERROR("write client characteristic configuration request\n");
269 Battery_Rsp(trans_id, conn_id, app_id, st, event, NULL);
271 int battery_level = 50;
272 Battery_Notify(conn_id, app_id, p_data->remote_bda, battery_level);
282 /*****************************************************************************
283 ** Function bas_s_read_attr_value
285 ** Description it will be called when client sends a read request
286 ******************************************************************************/
287 void bas_s_read_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id)
290 tBA_INST *p_inst = &battery_cb.battery_inst[0];
292 esp_gatt_status_t st = ESP_GATT_NOT_FOUND;
293 UINT16 handle = p_data->read_req.handle;
296 for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) {
297 // read battery level
298 if (handle == p_inst->ba_level_hdl ||
299 handle == p_inst->clt_cfg_hdl ||
300 handle == p_inst->rpt_ref_hdl ||
301 handle == p_inst->pres_fmt_hdl) {
302 if (p_data->read_req.is_long) {
303 st = ESP_GATT_NOT_LONG;
306 if (p_inst->p_cback) {
307 if (handle == p_inst->ba_level_hdl) {
308 p_inst->pending_evt = BA_READ_LEVEL_REQ;
310 if (handle == p_inst->clt_cfg_hdl) {
311 p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
313 if (handle == p_inst->pres_fmt_hdl) {
314 p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
316 if (handle == p_inst->rpt_ref_hdl) {
317 p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
320 // p_inst->pending_clcb_idx = clcb_idx;
321 p_inst->pending_handle = handle;
322 //act = SRVC_ACT_PENDING;
323 (*p_inst->p_cback)(trans_id, conn_id, p_inst->app_id, p_inst->pending_evt, NULL);
324 } else { /* application is not registered */
325 st = ESP_GATT_ERR_UNLIKELY;
329 /* else attribute not found */
333 /*****************************************************************************
334 ** Function bas_s_write_attr_value
336 ** Description it will be called when client sends a write request
337 ******************************************************************************/
338 void bas_s_write_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id, BD_ADDR bd_addr)
341 UINT8 *p = p_data->write_req.value;
342 tBA_INST *p_inst = &battery_cb.battery_inst[0];
344 esp_gatt_status_t st = ESP_GATT_NOT_FOUND;
345 UINT16 handle = p_data->write_req.handle;
348 for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) {
349 if (handle == p_inst->clt_cfg_hdl) {
350 memcpy(cfg.remote_bda, bd_addr, BD_ADDR_LEN);
351 STREAM_TO_UINT16(cfg.clt_cfg, p);
353 if (p_inst->p_cback) {
354 p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
355 p_inst->pending_handle = handle;
356 cfg.need_rsp = p_data->write_req.need_rsp;
357 (*p_inst->p_cback)(trans_id, conn_id, p_inst->app_id, p_inst->pending_evt, &cfg);
358 } else { /* all other handle is not writable */
359 st = ESP_GATT_WRITE_NOT_PERMIT;
366 /***************************************************************
368 ** Function bas_register
370 ** Description register app for battery service
372 ****************************************************************/
373 void bas_register(void)
375 esp_ble_gatts_app_register(&bas_uuid, bas_gatts_callback);
378 /***************************************************************
382 ** Description register battery service
384 ****************************************************************/
385 void bas_init(tBTA_GATTS_IF gatt_if, UINT16 app_id)
390 ba_reg_info.is_pri = true;
391 ba_reg_info.ba_level_descr = BA_LEVEL_NOTIFY;
392 ba_reg_info.transport = GATT_TRANSPORT_LE;
393 ba_reg_info.p_cback = bas_callback;
394 if (battery_cb.inst_id == BA_MAX_INT_NUM) {
395 GATT_TRACE_ERROR("MAX battery service has been reached\n");
399 p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
401 BTC_TRACE_ERROR("create battery service\n");
402 BTC_TRACE_ERROR("inst_id=%d\n", battery_cb.inst_id);
403 esp_ble_gatts_create_srvc (gatt_if, &bas_uuid, battery_cb.inst_id ,
404 BA_MAX_ATTR_NUM, ba_reg_info.is_pri);
406 battery_cb.inst_id ++;
408 p_inst->app_id = app_id;
409 p_inst->p_cback = ba_reg_info.p_cback;
413 /***************************************************************
415 ** Function bas_AddChar
417 ** Description add characteristic for battery service
419 ****************************************************************/
420 void bas_AddChar(UINT16 service_id, tBT_UUID *char_uuid)
422 if (ba_reg_info.ba_level_descr & BA_LEVEL_NOTIFY) {
423 prop |= GATT_CHAR_PROP_BIT_NOTIFY;
425 attr_handle_bit = 0x01;
426 esp_ble_gatts_add_char(service_id, char_uuid, BATTER_LEVEL_PERM, prop);
430 /***************************************************************
432 ** Function bas_AddCharDescr
434 ** Description add descriptor for battery service if needed
436 ****************************************************************/
437 void bas_AddCharDescr(UINT16 service_id, UINT16 attr_id)
440 uuid.len = LEN_UUID_16;
442 battery_cb.inst_id --;
443 tBA_INST *p_inst = &battery_cb.battery_inst[battery_cb.inst_id++];
444 /*store the attribute handles*/
445 if (attr_handle_bit == 0x01) {
446 p_inst->ba_level_hdl = attr_id;
447 } else if (attr_handle_bit == 0x02) {
448 p_inst->clt_cfg_hdl = attr_id;
449 } else if (attr_handle_bit == 0x04) {
450 p_inst->pres_fmt_hdl = attr_id;
451 } else if (attr_handle_bit == 0x08) {
452 p_inst->rpt_ref_hdl = attr_id;
456 if (ba_reg_info.ba_level_descr != 0) {
457 if (ba_reg_info.ba_level_descr & BA_LEVEL_NOTIFY) {
458 uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
459 ba_reg_info.ba_level_descr &= 0xfe;
460 attr_handle_bit = 0x02;
461 esp_ble_gatts_add_char_descr(service_id, (GATT_PERM_READ | GATT_PERM_WRITE), &uuid);
465 /* need presentation format descriptor? */
466 if (ba_reg_info.ba_level_descr & BA_LEVEL_PRE_FMT) {
467 uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
468 esp_ble_gatts_add_char_descr(service_id, GATT_PERM_READ, &uuid);
469 ba_reg_info.ba_level_descr &= 0xfd;
470 attr_handle_bit = 0x04;
473 /* need report reference format descriptor? */
474 if (ba_reg_info.ba_level_descr & BA_LEVEL_RPT_REF) {
475 uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
476 ba_reg_info.ba_level_descr &= 0xfb;
477 esp_ble_gatts_add_char_descr(service_id, GATT_PERM_READ, &uuid);
478 attr_handle_bit = 0x08;
484 esp_ble_gatts_start_srvc(service_id);
489 /***************************************************************
491 ** Function bas_service_cmpl
493 ** Description create battery service complete
495 ****************************************************************/
496 void bas_service_cmpl(UINT16 service_id, esp_gatt_status_t status)
498 if (status != ESP_GATT_OK) {
499 battery_cb.inst_id --;
500 esp_ble_gatts_dele_srvc(service_id);
504 /*******************************************************************************
506 ** Function Battery_Rsp
508 ** Description Respond to a battery service request
510 *******************************************************************************/
511 void Battery_Rsp (UINT32 trans_id, UINT16 conn_id, UINT8 app_id,
512 esp_gatt_status_t st, UINT8 event, tBA_RSP_DATA *p_rsp)
514 tBA_INST *p_inst = &battery_cb.battery_inst[0];
519 while (i < BA_MAX_INT_NUM) {
520 if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) {
526 if (i == BA_MAX_INT_NUM) {
530 memset(&rsp, 0, sizeof(tGATTS_RSP));
532 if (p_inst->pending_evt == event) {
534 case BA_READ_CLT_CFG_REQ:
535 rsp.attr_value.handle = p_inst->pending_handle;
536 rsp.attr_value.len = 2;
537 pp = rsp.attr_value.value;
538 UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
539 esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
540 //srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
543 case BA_READ_LEVEL_REQ:
544 rsp.attr_value.handle = p_inst->pending_handle;
545 rsp.attr_value.len = 1;
546 pp = rsp.attr_value.value;
547 UINT8_TO_STREAM(pp, p_rsp->ba_level);
548 esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
549 //srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
552 case BA_WRITE_CLT_CFG_REQ:
553 esp_ble_gatts_send_rsp(conn_id, trans_id, st, NULL);
554 //srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
557 case BA_READ_RPT_REF_REQ:
558 rsp.attr_value.handle = p_inst->pending_handle;
559 rsp.attr_value.len = 2;
560 pp = rsp.attr_value.value;
561 UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
562 UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
563 esp_ble_gatts_send_rsp(conn_id, trans_id, st, &rsp);
564 //srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
570 // p_inst->pending_clcb_idx = 0;
571 p_inst->pending_evt = 0;
572 p_inst->pending_handle = 0;
576 /*******************************************************************************
578 ** Function Battery_Notify
580 ** Description Send battery level notification
582 *******************************************************************************/
583 void Battery_Notify (UINT16 conn_id, UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level)
585 tBA_INST *p_inst = &battery_cb.battery_inst[0];
588 while (i < BA_MAX_INT_NUM) {
589 if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) {
595 if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) {
598 esp_ble_gatts_hdl_val_indica(conn_id, p_inst->ba_level_hdl, 1, &battery_level, false);
599 //srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);