1 /*
2  * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include "osi/allocator.h"
11 #include "btc/btc_task.h"
12 #include "btc/btc_manage.h"
13 #include "blufi_int.h"
14 #include "btc_blufi_prf.h"
15 #include "esp_log.h"
16 #include "esp_blufi_api.h"
17 
18 #include "common/bt_target.h"
19 #include "common/bt_trace.h"
20 #include "stack/bt_types.h"
21 #include "stack/gatt_api.h"
22 #include "bta/bta_api.h"
23 #include "bta/bta_gatt_api.h"
24 #include "bta_gatts_int.h"
25 #include "btc_gatt_util.h"
26 #include "btc_gatts.h"
27 
28 #include "esp_bt_defs.h"
29 #include "esp_gap_ble_api.h"
30 #include "esp_gatt_common_api.h"
31 #include "esp_bt_main.h"
32 #include "esp_bt_device.h"
33 #include "esp_err.h"
34 #include "esp_blufi.h"
35 
36 #if (BLUFI_INCLUDED == TRUE)
37 
38 static uint8_t server_if;
39 static uint16_t conn_id;
40 static uint8_t blufi_service_uuid128[32] = {
41     /* LSB <--------------------------------------------------------------------------------> MSB */
42     //first uuid, 16bit, [12],[13] is the value
43     0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
44 };
45 
46 static esp_ble_adv_data_t blufi_adv_data = {
47     .set_scan_rsp = false,
48     .include_name = true,
49     .include_txpower = true,
50     .min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
51     .max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
52     .appearance = 0x00,
53     .manufacturer_len = 0,
54     .p_manufacturer_data =  NULL,
55     .service_data_len = 0,
56     .p_service_data = NULL,
57     .service_uuid_len = 16,
58     .p_service_uuid = blufi_service_uuid128,
59     .flag = 0x6,
60 };
61 
62 static esp_ble_adv_params_t blufi_adv_params = {
63     .adv_int_min        = 0x100,
64     .adv_int_max        = 0x100,
65     .adv_type           = ADV_TYPE_IND,
66     .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
67     //.peer_addr            =
68     //.peer_addr_type       =
69     .channel_map        = ADV_CHNL_ALL,
70     .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
71 };
72 
esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event,esp_ble_gap_cb_param_t * param)73 void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
74 {
75     switch (event) {
76     case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
77         esp_ble_gap_start_advertising(&blufi_adv_params);
78         break;
79     default:
80         break;
81     }
82 }
83 
84 // static functions declare
85 static void blufi_profile_cb(tBTA_GATTS_EVT event,  tBTA_GATTS *p_data);
86 
blufi_create_service(void)87 void blufi_create_service(void)
88 {
89     if (!blufi_env.enabled) {
90         BTC_TRACE_ERROR("blufi service added error.");
91         return;
92     }
93 
94     blufi_env.srvc_inst = 0x00;
95     BTA_GATTS_CreateService(blufi_env.gatt_if, &blufi_srvc_uuid, blufi_env.srvc_inst, BLUFI_HDL_NUM, true);
96 }
97 
esp_blufi_init(void)98 uint8_t esp_blufi_init(void)
99 {
100 
101     /* register the BLUFI profile to the BTA_GATTS module*/
102     BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb);
103     return GATT_SUCCESS;
104 }
105 
blufi_profile_cb(tBTA_GATTS_EVT event,tBTA_GATTS * p_data)106 static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
107 {
108     tBTA_GATTS_RSP rsp;
109     BLUFI_TRACE_DEBUG("blufi profile cb event = %x\n", event);
110 
111     switch (event) {
112     case BTA_GATTS_REG_EVT:
113         BLUFI_TRACE_DEBUG("REG: status %d, app_uuid %04x, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.uuid.uu.uuid16, p_data->reg_oper.server_if);
114 
115         if (p_data->reg_oper.status != BTA_GATT_OK) {
116             BLUFI_TRACE_ERROR("BLUFI profile register failed\n");
117             return;
118         }
119 
120         blufi_env.gatt_if = p_data->reg_oper.server_if;
121         blufi_env.enabled = true;
122 
123         //create the blufi service to the service data base.
124         if (p_data->reg_oper.uuid.uu.uuid16 == BLUFI_APP_UUID) {
125             BLUFI_TRACE_DEBUG("%s %d\n", __func__, __LINE__);
126             blufi_create_service();
127         }
128         break;
129     case BTA_GATTS_DEREG_EVT: {
130         esp_blufi_cb_param_t param;
131         btc_msg_t msg;
132 
133         BLUFI_TRACE_DEBUG("DEREG: status %d, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.server_if);
134 
135         if (p_data->reg_oper.status != BTA_GATT_OK) {
136             BLUFI_TRACE_ERROR("BLUFI profile unregister failed\n");
137             return;
138         }
139 
140         blufi_env.enabled = false;
141 
142         msg.sig = BTC_SIG_API_CB;
143         msg.pid = BTC_PID_BLUFI;
144         msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
145         param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
146 
147         btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
148 
149         break;
150     }
151     case BTA_GATTS_READ_EVT:
152         memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
153         rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
154         rsp.attr_value.len = 1;
155         rsp.attr_value.value[0] = 0x00;
156         BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
157                           p_data->req_data.status, &rsp);
158         break;
159     case BTA_GATTS_WRITE_EVT: {
160         if (p_data->req_data.p_data->write_req.is_prep) {
161             tBTA_GATT_STATUS status = GATT_SUCCESS;
162 
163             do {
164                 if (p_data->req_data.p_data->write_req.offset > BLUFI_PREPARE_BUF_MAX_SIZE) {
165                    status = ESP_GATT_INVALID_OFFSET;
166                    break;
167                 }
168 
169                 if ((p_data->req_data.p_data->write_req.offset + p_data->req_data.p_data->write_req.len) > BLUFI_PREPARE_BUF_MAX_SIZE) {
170                    status = ESP_GATT_INVALID_ATTR_LEN;
171                    break;
172                 }
173 
174                 if (blufi_env.prepare_buf == NULL) {
175                     if (p_data->req_data.p_data->write_req.offset != 0) {
176                         status = GATT_INVALID_OFFSET;
177                         break;
178                     }
179                     blufi_env.prepare_buf = osi_malloc(BLUFI_PREPARE_BUF_MAX_SIZE);
180                     blufi_env.prepare_len = 0;
181                     if (blufi_env.prepare_buf == NULL) {
182                         BLUFI_TRACE_ERROR("Blufi prep no mem\n");
183                         status = GATT_NO_RESOURCES;
184                         break;
185                     }
186                 }
187             } while (0);
188 
189             memset(&rsp, 0, sizeof(tGATTS_RSP));
190             rsp.attr_value.handle = p_data->req_data.p_data->write_req.handle;
191             rsp.attr_value.len = p_data->req_data.p_data->write_req.len;
192             rsp.attr_value.offset = p_data->req_data.p_data->write_req.offset;
193             memcpy(rsp.attr_value.value, p_data->req_data.p_data->write_req.value, p_data->req_data.p_data->write_req.len);
194 
195             BLUFI_TRACE_DEBUG("prep write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
196 
197             BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
198                               status, &rsp);
199 
200             if (status != GATT_SUCCESS) {
201                 if (blufi_env.prepare_buf) {
202                     osi_free(blufi_env.prepare_buf);
203                     blufi_env.prepare_buf = NULL;
204                     blufi_env.prepare_len = 0;
205                 }
206                 BLUFI_TRACE_ERROR("write data error , error code 0x%x\n", status);
207                 return;
208             }
209             memcpy(blufi_env.prepare_buf + p_data->req_data.p_data->write_req.offset,
210                    p_data->req_data.p_data->write_req.value,
211                    p_data->req_data.p_data->write_req.len);
212             blufi_env.prepare_len += p_data->req_data.p_data->write_req.len;
213 
214             return;
215         } else {
216             BLUFI_TRACE_DEBUG("norm write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
217             BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
218                               p_data->req_data.status, NULL);
219         }
220 
221         if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) {
222             btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0],
223                                    p_data->req_data.p_data->write_req.len);
224         }
225         break;
226     }
227     case BTA_GATTS_EXEC_WRITE_EVT:
228         BLUFI_TRACE_DEBUG("exec write exec %d\n", p_data->req_data.p_data->exec_write);
229 
230         BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
231                           GATT_SUCCESS, NULL);
232 
233         if (blufi_env.prepare_buf && p_data->req_data.p_data->exec_write == GATT_PREP_WRITE_EXEC) {
234             btc_blufi_recv_handler(blufi_env.prepare_buf, blufi_env.prepare_len);
235         }
236 
237         if (blufi_env.prepare_buf) {
238             osi_free(blufi_env.prepare_buf);
239             blufi_env.prepare_buf = NULL;
240             blufi_env.prepare_len = 0;
241         }
242 
243         break;
244     case BTA_GATTS_MTU_EVT:
245         BLUFI_TRACE_DEBUG("MTU size %d\n", p_data->req_data.p_data->mtu);
246         blufi_env.frag_size = (p_data->req_data.p_data->mtu < BLUFI_MAX_DATA_LEN ? p_data->req_data.p_data->mtu : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
247         break;
248     case BTA_GATTS_CONF_EVT:
249         BLUFI_TRACE_DEBUG("CONFIRM EVT\n");
250         /* Nothing */
251         break;
252     case BTA_GATTS_CREATE_EVT:
253         blufi_env.handle_srvc = p_data->create.service_id;
254 
255         //add the frist blufi characteristic --> write characteristic
256         BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e,
257                                     (GATT_PERM_WRITE),
258                                     (GATT_CHAR_PROP_BIT_WRITE),
259                                     NULL, NULL);
260         break;
261     case BTA_GATTS_ADD_CHAR_EVT:
262         switch (p_data->add_result.char_uuid.uu.uuid16) {
263         case BLUFI_CHAR_P2E_UUID:  /* Phone to ESP32 */
264             blufi_env.handle_char_p2e = p_data->add_result.attr_id;
265 
266             BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_e2p,
267                                         (GATT_PERM_READ),
268                                         (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY),
269                                         NULL, NULL);
270             break;
271         case BLUFI_CHAR_E2P_UUID:  /* ESP32 to Phone */
272             blufi_env.handle_char_e2p = p_data->add_result.attr_id;
273 
274             BTA_GATTS_AddCharDescriptor (blufi_env.handle_srvc,
275                                          (GATT_PERM_READ | GATT_PERM_WRITE),
276                                          &blufi_descr_uuid_e2p,
277                                          NULL, NULL);
278             break;
279         default:
280             break;
281         }
282         break;
283     case BTA_GATTS_ADD_CHAR_DESCR_EVT: {
284         /* call init finish */
285         esp_blufi_cb_param_t param;
286         btc_msg_t msg;
287 
288         blufi_env.handle_descr_e2p = p_data->add_result.attr_id;
289         //start the blufi service after created
290         BTA_GATTS_StartService(blufi_env.handle_srvc, BTA_GATT_TRANSPORT_LE);
291 
292         msg.sig = BTC_SIG_API_CB;
293         msg.pid = BTC_PID_BLUFI;
294         msg.act = ESP_BLUFI_EVENT_INIT_FINISH;
295         param.init_finish.state = ESP_BLUFI_INIT_OK;
296 
297         btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
298         break;
299     }
300     case BTA_GATTS_CONNECT_EVT: {
301         btc_msg_t msg;
302         esp_blufi_cb_param_t param;
303 
304         //set the connection flag to true
305         BLUFI_TRACE_API("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
306                         BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
307                         p_data->conn.reason, p_data->conn.conn_id);
308 
309         memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
310         blufi_env.conn_id = p_data->conn.conn_id;
311         blufi_env.is_connected = true;
312         blufi_env.recv_seq = blufi_env.send_seq = 0;
313 
314         msg.sig = BTC_SIG_API_CB;
315         msg.pid = BTC_PID_BLUFI;
316         msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
317         memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
318         param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
319         conn_id = param.connect.conn_id;
320         server_if = p_data->conn.server_if;
321         btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
322         break;
323     }
324     case BTA_GATTS_DISCONNECT_EVT: {
325         btc_msg_t msg;
326         esp_blufi_cb_param_t param;
327 
328         blufi_env.is_connected = false;
329         //set the connection flag to true
330         BLUFI_TRACE_API("\ndevice is disconnected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
331                         BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
332                         p_data->conn.reason, p_data->conn.conn_id);
333 
334         memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
335         blufi_env.conn_id = p_data->conn.conn_id;
336         blufi_env.recv_seq = blufi_env.send_seq = 0;
337         blufi_env.sec_mode = 0x0;
338         blufi_env.offset = 0;
339 
340         if (blufi_env.aggr_buf != NULL) {
341             osi_free(blufi_env.aggr_buf);
342             blufi_env.aggr_buf = NULL;
343         }
344 
345         msg.sig = BTC_SIG_API_CB;
346         msg.pid = BTC_PID_BLUFI;
347         msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
348         memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
349         btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
350         break;
351     }
352     case BTA_GATTS_OPEN_EVT:
353         break;
354     case BTA_GATTS_CLOSE_EVT:
355         break;
356     case BTA_GATTS_CONGEST_EVT:
357         break;
358     default:
359         break;
360     }
361 }
362 
esp_blufi_send_notify(void * arg)363 void esp_blufi_send_notify(void *arg)
364 {
365     struct pkt_info *pkts = (struct pkt_info *) arg;
366     uint16_t conn_id = blufi_env.conn_id;
367     uint16_t attr_id = blufi_env.handle_char_e2p;
368     bool rsp = false;
369     BTA_GATTS_HandleValueIndication(conn_id, attr_id, pkts->pkt_len,
370                                     pkts->pkt, rsp);
371 
372 }
373 
esp_blufi_deinit(void)374 void esp_blufi_deinit(void)
375 {
376     BTA_GATTS_StopService(blufi_env.handle_srvc);
377     BTA_GATTS_DeleteService(blufi_env.handle_srvc);
378     /* register the BLUFI profile to the BTA_GATTS module*/
379     BTA_GATTS_AppDeregister(blufi_env.gatt_if);
380 }
381 
esp_blufi_adv_start(void)382 void esp_blufi_adv_start(void)
383 {
384     esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME);
385     esp_ble_gap_config_adv_data(&blufi_adv_data);
386 }
387 
esp_blufi_adv_stop(void)388 void esp_blufi_adv_stop(void)
389 {
390     esp_ble_gap_stop_advertising();
391 }
392 
esp_blufi_send_encap(void * arg)393 void esp_blufi_send_encap(void *arg)
394 {
395     struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
396 retry:
397     if (blufi_env.is_connected == false) {
398         BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
399         return;
400     }
401     if (esp_ble_get_cur_sendable_packets_num(BTC_GATT_GET_CONN_ID(blufi_env.conn_id)) > 0) {
402         btc_blufi_send_notify((uint8_t *)hdr,
403                               ((hdr->fc & BLUFI_FC_CHECK) ?
404                                hdr->data_len + sizeof(struct blufi_hdr) + 2 :
405                                hdr->data_len + sizeof(struct blufi_hdr)));
406     } else {
407         BTC_TRACE_WARNING("%s wait to send blufi custom data\n", __func__);
408         vTaskDelay(pdMS_TO_TICKS(10));
409         goto retry;
410     }
411 }
412 
esp_blufi_close(esp_gatt_if_t gatts_if,uint16_t conn_id)413 esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id)
414 {
415     ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
416     btc_msg_t msg;
417     btc_ble_gatts_args_t arg;
418     msg.sig = BTC_SIG_API_CALL;
419     msg.pid = BTC_PID_GATTS;
420     msg.act = BTC_GATTS_ACT_CLOSE;
421     arg.close.conn_id = BTC_GATT_CREATE_CONN_ID(gatts_if, conn_id);
422     return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gatts_args_t), NULL, NULL)
423             == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
424 }
425 
esp_blufi_disconnect()426 void  esp_blufi_disconnect()
427 {
428     int rc;
429     rc = esp_blufi_close(server_if, conn_id);
430     assert (rc == 0);
431 }
432 
433 #endif
434