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, ¶m, 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, ¶m, 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, ¶m, 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, ¶m, 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