1 /*
2 * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8
9 #include "btc_spp.h"
10 #include "btc/btc_manage.h"
11 #include "btc/btc_task.h"
12 #include "bta/bta_jv_api.h"
13 #include "common/bt_trace.h"
14 #include "osi/allocator.h"
15 #include "esp_spp_api.h"
16 #include "osi/list.h"
17 #include "freertos/ringbuf.h"
18 #include "osi/mutex.h"
19 #include "osi/alarm.h"
20 #include <sys/errno.h>
21 #include <sys/lock.h>
22 #include <sys/fcntl.h>
23 #include "esp_vfs.h"
24 #include "esp_vfs_dev.h"
25 #include "stack/port_api.h"
26 #include "freertos/FreeRTOS.h"
27 #include "freertos/event_groups.h"
28
29 #include "btc/btc_task.h"
30 #include "stack/btu.h"
31
32 #if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
33
34 #define SLOT_WRITE_BIT(i) (1UL << (i - 1))
35 #define SLOT_CLOSE_BIT(i) (1UL << (i + MAX_RFC_PORTS - 1))
36 #define VFS_WRITE_TIMEOUT (40 * 1000)
37 #define SLOT_TX_QUEUE_SIZE 10
38 #define SLOT_TX_QUEUE_LOW_WM 4
39 #define SLOT_TX_DATA_HIGH_WM (SLOT_TX_QUEUE_SIZE * BTA_JV_DEF_RFC_MTU)
40 #define VFS_CLOSE_TIMEOUT (20 * 1000)
41
42 typedef struct {
43 bool peer_fc; /* true if flow control is set based on peer's request */
44 bool user_fc; /* true if flow control is set based on user's request */
45 fixed_queue_t *queue; /* Queue of buffers waiting to be sent */
46 uint32_t data_size; /* Number of data bytes in the queue */
47 } slot_data_t;
48
49 typedef struct {
50 bool connected;
51 bool is_server;
52 bool is_writing;
53 uint8_t serial;
54 uint8_t scn;
55 uint8_t max_session;
56 uint16_t mtu;
57 uint16_t credit_rx;
58 uint16_t write_data_len;
59 uint32_t id;
60 uint32_t sdp_handle;
61 uint32_t rfc_handle;
62 uint32_t rfc_port_handle;
63 int fd;
64 uint8_t *write_data;
65 osi_alarm_t *close_alarm;
66 void *alarm_arg;
67 esp_spp_role_t role;
68 esp_spp_sec_t security;
69 esp_bd_addr_t addr;
70 slot_data_t rx;
71 union {
72 slot_data_t tx;
73 RingbufHandle_t ringbuf_write;
74 };
75 uint8_t service_uuid[16];
76 char service_name[ESP_SPP_SERVER_NAME_MAX + 1];
77 } spp_slot_t;
78
79 typedef struct {
80 uint16_t tx_buffer_size;
81 spp_slot_t *spp_slots[MAX_RFC_PORTS + 1];
82 uint32_t spp_slot_id;
83 esp_spp_mode_t spp_mode;
84 osi_mutex_t spp_slot_mutex;
85 EventGroupHandle_t tx_event_group;
86 esp_vfs_id_t spp_vfs_id;
87 } spp_local_param_t;
88
89 #if SPP_DYNAMIC_MEMORY == FALSE
90 static spp_local_param_t spp_local_param;
91 #else
92 static spp_local_param_t *spp_local_param_ptr;
93 #define spp_local_param (*spp_local_param_ptr)
94 #endif
95
96 static void btc_spp_vfs_register(void);
97 static void btc_spp_vfs_unregister(void);
98
spp_osi_free(void * p)99 static void spp_osi_free(void *p)
100 {
101 osi_free(p);
102 }
103
104 #if SPP_DYNAMIC_MEMORY == FALSE
105 #define is_spp_init() (spp_local_param.spp_slot_mutex != NULL)
106 #else
107 #define is_spp_init() (&spp_local_param != NULL && spp_local_param.spp_slot_mutex != NULL)
108 #endif
109
init_slot_data(slot_data_t * slot_data,size_t queue_size)110 static int init_slot_data(slot_data_t *slot_data, size_t queue_size)
111 {
112 memset(slot_data, 0, sizeof(slot_data_t));
113 if ((slot_data->queue = fixed_queue_new(queue_size)) == NULL) {
114 return -1;
115 }
116 slot_data->data_size = 0;
117 return 0;
118 }
119
free_slot_data(slot_data_t * slot_data)120 static void free_slot_data(slot_data_t *slot_data)
121 {
122 fixed_queue_free(slot_data->queue, spp_osi_free);
123 slot_data->queue = NULL;
124 }
125
spp_malloc_slot(void)126 static spp_slot_t *spp_malloc_slot(void)
127 {
128 uint8_t err_no = 0;
129 spp_slot_t **slot = NULL;
130 if (++spp_local_param.spp_slot_id == 0) {
131 spp_local_param.spp_slot_id = 1;
132 }
133 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
134 slot = &spp_local_param.spp_slots[i];
135 if ((*slot) == NULL) {
136 if (((*slot) = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t))) == NULL) {
137 return NULL;
138 }
139 (*slot)->id = spp_local_param.spp_slot_id;
140 (*slot)->serial = i;
141 (*slot)->sdp_handle = 0;
142 (*slot)->rfc_handle = 0;
143 (*slot)->rfc_port_handle = 0;
144 (*slot)->fd = -1;
145 (*slot)->connected = false;
146 (*slot)->is_server = false;
147 (*slot)->mtu = 0;
148 (*slot)->credit_rx = BTA_JV_MAX_CREDIT_NUM;
149 (*slot)->write_data = NULL;
150 (*slot)->write_data_len = 0;
151 (*slot)->is_writing = false;
152 (*slot)->close_alarm = NULL;
153 (*slot)->alarm_arg = NULL;
154 /* clear the old event bits */
155 if (spp_local_param.tx_event_group) {
156 xEventGroupClearBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(i) | SLOT_CLOSE_BIT(i));
157 }
158
159 if (init_slot_data(&(*slot)->rx, QUEUE_SIZE_MAX)) {
160 BTC_TRACE_ERROR("%s unable to malloc rx queue!", __func__);
161 err_no = 1;
162 goto err;
163 }
164 if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
165 if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
166 BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
167 err_no = 2;
168 goto err;
169 }
170 } else {
171 if (((*slot)->ringbuf_write = xRingbufferCreate(spp_local_param.tx_buffer_size, RINGBUF_TYPE_BYTEBUF)) == NULL) {
172 BTC_TRACE_ERROR("%s write ringbuffer create error!", __func__);
173 err_no = 2;
174 goto err;
175 }
176 if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &(*slot)->fd) != ESP_OK) {
177 BTC_TRACE_ERROR("%s unable to register fd!", __func__);
178 err_no = 3;
179 goto err;
180 }
181 }
182 return (*slot);
183 }
184 }
185
186 return NULL;
187 err:
188 switch (err_no) {
189 case 3:
190 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
191 vRingbufferDelete((*slot)->ringbuf_write);
192 }
193 case 2:
194 free_slot_data(&(*slot)->rx);
195 case 1:
196 osi_free((*slot));
197 (*slot) = NULL;
198 break;
199 default:
200 break;
201 }
202 return (*slot);
203 }
204
spp_find_slot_by_id(uint32_t id)205 static spp_slot_t *spp_find_slot_by_id(uint32_t id)
206 {
207 spp_slot_t *slot = NULL;
208 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
209 slot = spp_local_param.spp_slots[i];
210 if (slot != NULL && slot->id == id) {
211 return slot;
212 }
213 }
214 return NULL;
215 }
216
spp_find_slot_by_handle(uint32_t handle)217 static spp_slot_t *spp_find_slot_by_handle(uint32_t handle)
218 {
219 spp_slot_t *slot = NULL;
220 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
221 slot = spp_local_param.spp_slots[i];
222 if (slot != NULL && slot->rfc_handle == handle) {
223 return slot;
224 }
225 }
226 return NULL;
227 }
228
spp_find_slot_by_fd(int fd)229 static spp_slot_t *spp_find_slot_by_fd(int fd)
230 {
231 spp_slot_t *slot = NULL;
232 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
233 slot = spp_local_param.spp_slots[i];
234 if (slot != NULL && slot->fd == fd) {
235 return slot;
236 }
237 }
238 return NULL;
239 }
240
spp_find_slot_by_scn(uint32_t scn)241 static spp_slot_t *spp_find_slot_by_scn(uint32_t scn)
242 {
243 spp_slot_t *slot = NULL;
244 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
245 slot = spp_local_param.spp_slots[i];
246 if (slot != NULL && slot->is_server && slot->scn == (uint8_t)scn) {
247 return slot;
248 }
249 }
250 return NULL;
251 }
252
close_timeout_handler(void * arg)253 static void close_timeout_handler(void *arg)
254 {
255 btc_msg_t msg;
256 bt_status_t status;
257 spp_slot_t *slot = (spp_slot_t *)arg;
258
259 msg.sig = BTC_SIG_API_CB;
260 msg.pid = BTC_PID_SPP;
261 msg.act = BTA_JV_RFCOMM_CLOSE_EVT;
262
263 status = btc_transfer_context(&msg, slot->alarm_arg, sizeof(tBTA_JV), NULL, NULL);
264
265 if (slot->alarm_arg) {
266 osi_free(slot->alarm_arg);
267 slot->alarm_arg = NULL;
268 }
269
270 if (status != BT_STATUS_SUCCESS) {
271 BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
272 }
273 }
274
spp_free_slot(spp_slot_t * slot)275 static void spp_free_slot(spp_slot_t *slot)
276 {
277 if (!slot) {
278 return;
279 }
280 spp_local_param.spp_slots[slot->serial] = NULL;
281 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
282 (void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd);
283 xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
284 vRingbufferDelete(slot->ringbuf_write);
285 } else {
286 free_slot_data(&slot->tx);
287 }
288 free_slot_data(&slot->rx);
289 if (slot->close_alarm) {
290 osi_alarm_free(slot->close_alarm);
291 if (slot->alarm_arg) {
292 osi_free(slot->alarm_arg);
293 slot->alarm_arg = NULL;
294 }
295 }
296 osi_free(slot);
297 }
298
spp_free_pending_slots(void)299 static void spp_free_pending_slots(void)
300 {
301 spp_slot_t *slot = NULL;
302 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
303 slot = spp_local_param.spp_slots[i];
304 if (slot) {
305 BTC_TRACE_WARNING("%s found slot(rfc_handle=0x%x) pending to close, close it now!", __func__, slot->rfc_handle);
306 spp_free_slot(slot);
307 }
308 }
309 }
310
btc_spp_cb_to_app(esp_spp_cb_event_t event,esp_spp_cb_param_t * param)311 static inline void btc_spp_cb_to_app(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
312 {
313 esp_spp_cb_t btc_spp_cb = (esp_spp_cb_t)btc_profile_cb_get(BTC_PID_SPP);
314 if (btc_spp_cb) {
315 btc_spp_cb(event, param);
316 }
317 }
318
btc_create_server_fail_cb(void)319 static void btc_create_server_fail_cb(void)
320 {
321 esp_spp_cb_param_t param;
322 param.start.status = ESP_SPP_FAILURE;
323 param.start.handle = 0;
324 param.start.sec_id = 0;
325 param.start.scn = BTC_SPP_INVALID_SCN;
326 param.start.use_co = FALSE;
327 btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
328 }
329
btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event,tBTA_JV * p_data,void * user_data)330 static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
331 {
332 bt_status_t status;
333 btc_msg_t msg;
334 void *new_user_data = NULL;
335 uint32_t id = (uintptr_t)user_data, id_temp = 0;
336 spp_slot_t *slot = NULL, *slot_new = NULL;
337
338 if (!is_spp_init()) {
339 BTC_TRACE_WARNING("%s SPP have been deinit, incoming events ignore!\n", __func__);
340 return new_user_data;
341 }
342 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
343 switch (event) {
344 case BTA_JV_RFCOMM_START_EVT:
345 slot = spp_find_slot_by_id(id);
346 if (!slot) {
347 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
348 p_data->rfc_start.status = ESP_SPP_NO_CONNECTION;
349 break;
350 }
351 slot->rfc_handle = p_data->rfc_start.handle;
352 slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_start.handle);
353 break;
354 case BTA_JV_RFCOMM_SRV_OPEN_EVT:
355 slot = p_data->rfc_srv_open.handle ? spp_find_slot_by_id(id) : spp_find_slot_by_scn((uint32_t)user_data);
356 if (!slot) {
357 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
358 p_data->rfc_srv_open.status = ESP_SPP_NO_CONNECTION;
359 break;
360 }
361
362 if (!p_data->rfc_srv_open.handle) {
363 /* match with the exist server solt */
364 slot->rfc_handle = p_data->rfc_srv_open.new_listen_handle;
365 slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot->rfc_handle);
366 } else {
367 slot_new = spp_malloc_slot();
368 if (!slot_new) {
369 BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
370 p_data->rfc_srv_open.status = ESP_SPP_NO_RESOURCE;
371 break;
372 }
373 slot_new->connected = true;
374 slot_new->security = slot->security;
375 slot_new->role = slot->role;
376 slot_new->scn = slot->scn;
377 slot_new->max_session = slot->max_session;
378 strcpy(slot_new->service_name, slot->service_name);
379 slot_new->sdp_handle = slot->sdp_handle;
380 slot_new->mtu = p_data->rfc_srv_open.peer_mtu;
381 slot_new->rfc_handle = p_data->rfc_srv_open.handle;
382 slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot_new->rfc_handle);
383 BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN);
384
385 if (p_data->rfc_srv_open.new_listen_handle) {
386 slot->rfc_handle = p_data->rfc_srv_open.new_listen_handle;
387 slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot->rfc_handle);
388 } else {
389 /* means lower layer can alloc port */
390 slot->rfc_handle = 0;
391 slot->rfc_port_handle = 0;
392 }
393 /* swap slot id */
394 id_temp = slot->id;
395 slot->id = slot_new->id;
396 slot_new->id = id_temp;
397 }
398 new_user_data = (void *)(uintptr_t)slot->id;
399 break;
400 case BTA_JV_RFCOMM_CL_INIT_EVT:
401 slot = spp_find_slot_by_id(id);
402 if (!slot) {
403 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
404 p_data->rfc_cl_init.status = ESP_SPP_FAILURE;
405 break;
406 }
407
408 if (p_data->rfc_cl_init.status == BTA_JV_SUCCESS) {
409 slot->rfc_handle = p_data->rfc_cl_init.handle;
410 } else {
411 spp_free_slot(slot);
412 }
413 break;
414 case BTA_JV_RFCOMM_OPEN_EVT:
415 slot = spp_find_slot_by_id(id);
416 if (!slot) {
417 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
418 p_data->rfc_open.status = ESP_SPP_NO_CONNECTION;
419 break;
420 }
421 slot->connected = true;
422 slot->rfc_handle = p_data->rfc_open.handle;
423 slot->mtu = p_data->rfc_open.peer_mtu;
424 slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_open.handle);
425 BTA_JvSetPmProfile(p_data->rfc_open.handle, BTA_JV_PM_ID_1, BTA_JV_CONN_OPEN);
426 break;
427 case BTA_JV_RFCOMM_DATA_IND_EVT:
428 break;
429 case BTA_JV_FREE_SCN_EVT:
430 if (user_data) {
431 id = ((tBTA_JV_FREE_SCN_USER_DATA *)user_data)->slot_id;
432 slot = spp_find_slot_by_id(id);
433 if (slot) {
434 spp_free_slot(slot);
435 } else {
436 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
437 p_data->free_scn.status = ESP_SPP_NO_CONNECTION;
438 }
439 osi_free(user_data);
440 }
441 break;
442 default:
443 break;
444 }
445 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
446 msg.sig = BTC_SIG_API_CB;
447 msg.pid = BTC_PID_SPP;
448 msg.act = event;
449
450
451 status = btc_transfer_context(&msg, p_data,
452 sizeof(tBTA_JV), NULL, NULL);
453
454 if (status != BT_STATUS_SUCCESS) {
455 BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
456 }
457 return new_user_data;
458 }
459
btc_spp_dm_inter_cb(tBTA_JV_EVT event,tBTA_JV * p_data,void * user_data)460 static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
461 {
462 bt_status_t status;
463 btc_msg_t msg;
464
465 uint32_t id = (uintptr_t)user_data;
466 spp_slot_t *slot = NULL;
467 switch (event) {
468 case BTA_JV_GET_SCN_EVT:
469 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
470 slot = spp_find_slot_by_id(id);
471 if (!slot) {
472 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
473 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
474 break;
475 }
476 if (p_data->scn == 0) {
477 btc_create_server_fail_cb();
478 spp_free_slot(slot);
479 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
480 BTC_TRACE_ERROR("%s unable to get scn, start server fail!", __func__);
481 break;
482 }
483
484 slot->scn = p_data->scn;
485 BTA_JvCreateRecordByUser(slot->service_name, slot->scn, (void *)slot->id);
486 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
487 break;
488 case BTA_JV_CREATE_RECORD_EVT:
489 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
490 slot = spp_find_slot_by_id(id);
491 if (!slot) {
492 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
493 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
494 break;
495 }
496 if (p_data->create_rec.status == BTA_JV_SUCCESS) {
497 slot->sdp_handle = p_data->create_rec.handle;
498 BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn,
499 slot->max_session, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id);
500 } else {
501 BTC_TRACE_ERROR("%s unable to create record, start server fail!", __func__);
502 btc_create_server_fail_cb();
503 tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
504 if (user_data) {
505 user_data->server_status = BTA_JV_SERVER_START_FAILED;
506 user_data->slot_id = slot->id;
507 } else {
508 BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
509 assert(0);
510 }
511 BTA_JvFreeChannel(slot->scn, BTA_JV_CONN_TYPE_RFCOMM,
512 (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
513 }
514 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
515 break;
516 default:
517 msg.sig = BTC_SIG_API_CB;
518 msg.pid = BTC_PID_SPP;
519 msg.act = event;
520
521 status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL, NULL);
522
523 if (status != BT_STATUS_SUCCESS) {
524 BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
525 }
526 break;
527 }
528 }
529
btc_spp_init(btc_spp_args_t * arg)530 static void btc_spp_init(btc_spp_args_t *arg)
531 {
532 esp_spp_status_t ret = ESP_SPP_SUCCESS;
533 do {
534 if (is_spp_init()) {
535 BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__);
536 ret = ESP_SPP_NEED_DEINIT;
537 break;
538 }
539
540 #if SPP_DYNAMIC_MEMORY == TRUE
541 if ((spp_local_param_ptr = (spp_local_param_t *)osi_malloc(sizeof(spp_local_param_t))) == NULL) {
542 BTC_TRACE_ERROR("%s malloc failed\n", __func__);
543 ret = ESP_SPP_NO_RESOURCE;
544 break;
545 }
546 memset((void *)spp_local_param_ptr, 0, sizeof(spp_local_param_t));
547 #endif
548
549 if (osi_mutex_new(&spp_local_param.spp_slot_mutex) != 0) {
550 BTC_TRACE_ERROR("%s osi_mutex_new failed\n", __func__);
551 #if SPP_DYNAMIC_MEMORY == TRUE
552 osi_free(spp_local_param_ptr);
553 spp_local_param_ptr = NULL;
554 #endif
555 ret = ESP_SPP_NO_RESOURCE;
556 break;
557 }
558 if ((spp_local_param.tx_event_group = xEventGroupCreate()) == NULL) {
559 BTC_TRACE_ERROR("%s create tx_event_group failed\n", __func__);
560 osi_mutex_free(&spp_local_param.spp_slot_mutex);
561 #if SPP_DYNAMIC_MEMORY == TRUE
562 osi_free(spp_local_param_ptr);
563 spp_local_param_ptr = NULL;
564 #endif
565 ret = ESP_SPP_NO_RESOURCE;
566 break;
567 }
568 if (arg->init.mode == ESP_SPP_MODE_VFS) {
569 spp_local_param.spp_vfs_id = -1;
570 }
571 spp_local_param.spp_mode = arg->init.mode;
572 spp_local_param.spp_slot_id = 0;
573 spp_local_param.tx_buffer_size = arg->init.tx_buffer_size;
574 BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
575 BTA_JvRfcommConfig(arg->init.enable_l2cap_ertm);
576 } while (0);
577
578 if (ret != ESP_SPP_SUCCESS) {
579 esp_spp_cb_param_t param;
580 param.init.status = ret;
581 btc_spp_cb_to_app(ESP_SPP_INIT_EVT, ¶m);
582 }
583 }
584
btc_spp_uninit(void)585 static void btc_spp_uninit(void)
586 {
587 esp_spp_status_t ret = ESP_SPP_SUCCESS;
588 do {
589 if (!is_spp_init()) {
590 BTC_TRACE_ERROR("%s SPP has not been initiated, shall init first!", __func__);
591 ret = ESP_SPP_NEED_INIT;
592 break;
593 }
594 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
595 // first, remove all connection
596 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
597 if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->is_server) {
598 BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (void *)spp_local_param.spp_slots[i]->id);
599 }
600 }
601 // second, remove all server
602 for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
603 if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->is_server) {
604 if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
605 BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
606 }
607
608 if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
609 BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
610 (void *)spp_local_param.spp_slots[i]->id);
611 }
612
613 tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
614 if (user_data) {
615 user_data->server_status = BTA_JV_SERVER_RUNNING;
616 user_data->slot_id = spp_local_param.spp_slots[i]->id;
617 } else {
618 BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
619 assert(0);
620 }
621 BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
622 (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
623 }
624 }
625 BTA_JvDisable((tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb);
626 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
627 } while(0);
628
629 if (ret != ESP_SPP_SUCCESS) {
630 esp_spp_cb_param_t param;
631 param.uninit.status = ret;
632 btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, ¶m);
633 }
634 }
635
btc_spp_start_discovery(btc_spp_args_t * arg)636 static void btc_spp_start_discovery(btc_spp_args_t *arg)
637 {
638 esp_spp_status_t ret = ESP_SPP_SUCCESS;
639 do {
640 if (!is_spp_init()) {
641 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
642 ret = ESP_SPP_NEED_INIT;
643 break;
644 }
645 BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL);
646 } while (0);
647
648 if (ret != ESP_SPP_SUCCESS) {
649 esp_spp_cb_param_t param;
650 param.disc_comp.status = ret;
651 param.disc_comp.scn_num = 0xff;
652 memset(param.disc_comp.scn, 0xff, ESP_SPP_MAX_SCN);
653 btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m);
654 }
655 }
656
btc_spp_connect(btc_spp_args_t * arg)657 static void btc_spp_connect(btc_spp_args_t *arg)
658 {
659 esp_spp_status_t ret = ESP_SPP_SUCCESS;
660 do {
661 if (!is_spp_init()) {
662 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
663 ret = ESP_SPP_NEED_INIT;
664 break;
665 }
666 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
667 spp_slot_t *slot = spp_malloc_slot();
668 if (!slot) {
669 BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
670 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
671 ret = ESP_SPP_NO_RESOURCE;
672 break;
673 }
674 slot->security = arg->connect.sec_mask;
675 slot->role = arg->connect.role;
676 slot->scn = arg->connect.remote_scn;
677
678 memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN);
679 BTA_JvRfcommConnect(arg->connect.sec_mask, arg->connect.role, arg->connect.remote_scn,
680 arg->connect.peer_bd_addr, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id);
681 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
682 } while (0);
683
684 if (ret != ESP_SPP_SUCCESS) {
685 esp_spp_cb_param_t param;
686 param.open.status = ret;
687 param.open.handle = 0;
688 param.open.fd = -1;
689 memset(param.open.rem_bda, 0, ESP_BD_ADDR_LEN);
690 btc_spp_cb_to_app(ESP_SPP_OPEN_EVT, ¶m);
691 }
692 }
693
btc_spp_disconnect(btc_spp_args_t * arg)694 static void btc_spp_disconnect(btc_spp_args_t *arg)
695 {
696 esp_spp_status_t ret = ESP_SPP_SUCCESS;
697 do {
698 if (!is_spp_init()) {
699 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
700 ret = ESP_SPP_NEED_INIT;
701 break;
702 }
703 spp_slot_t *slot = NULL;
704 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
705 slot = spp_find_slot_by_handle(arg->disconnect.handle);
706 if (!slot || (slot && !slot->connected)) {
707 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
708 if (!slot) {
709 BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
710 } else {
711 BTC_TRACE_ERROR("%s RFCOMM has been disconnected already!", __func__);
712 }
713 ret = ESP_SPP_NO_CONNECTION;
714 break;
715 }
716 BTA_JvRfcommClose(arg->disconnect.handle, (void *)slot->id);
717 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
718 } while(0);
719
720 if (ret != ESP_SPP_SUCCESS) {
721 esp_spp_cb_param_t param;
722 param.close.status = ret;
723 param.close.port_status = PORT_ERR_MAX;
724 param.close.handle = 0;
725 param.close.async = FALSE;
726 btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
727 }
728 }
729
btc_spp_start_srv(btc_spp_args_t * arg)730 static void btc_spp_start_srv(btc_spp_args_t *arg)
731 {
732 esp_spp_status_t ret = ESP_SPP_SUCCESS;
733 do {
734 if (!is_spp_init()) {
735 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
736 ret = ESP_SPP_NEED_INIT;
737 break;
738 }
739 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
740 spp_slot_t *slot = spp_malloc_slot();
741 if (!slot) {
742 BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
743 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
744 ret = ESP_SPP_NO_RESOURCE;
745 break;
746 }
747 /**
748 * make this slot become a listening slot
749 */
750 slot->is_server = true;
751 slot->security = arg->start_srv.sec_mask;
752 slot->role = arg->start_srv.role;
753 slot->scn = arg->start_srv.local_scn;
754 slot->max_session = arg->start_srv.max_session;
755 strcpy(slot->service_name, arg->start_srv.name);
756
757 BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void *)slot->id, arg->start_srv.local_scn);
758 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
759 } while(0);
760
761 if (ret != ESP_SPP_SUCCESS) {
762 esp_spp_cb_param_t param;
763 param.start.status = ret;
764 param.start.handle = 0;
765 param.start.sec_id = 0;
766 param.start.scn = BTC_SPP_INVALID_SCN;
767 param.start.use_co = FALSE;
768 btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
769 }
770 }
771
btc_spp_stop_srv(btc_spp_args_t * arg)772 static void btc_spp_stop_srv(btc_spp_args_t *arg)
773 {
774 esp_spp_status_t ret = ESP_SPP_SUCCESS;
775 bool is_remove_all = false;
776 uint8_t i, j, srv_cnt = 0;
777 uint8_t *srv_scn_arr = NULL;
778 if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) {
779 is_remove_all = true;
780 }
781
782 do {
783 if (!is_spp_init()) {
784 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
785 ret = ESP_SPP_NEED_INIT;
786 break;
787 }
788 srv_scn_arr = osi_malloc(MAX_RFC_PORTS);
789 if (srv_scn_arr == NULL) {
790 BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__);
791 ret = ESP_SPP_NO_RESOURCE;
792 break;
793 }
794
795 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
796 // [1] find all unconnected server
797 for (i = 1; i <= MAX_RFC_PORTS; i++) {
798 if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected &&
799 spp_local_param.spp_slots[i]->sdp_handle > 0) {
800 if (is_remove_all) {
801 srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
802 } else if (spp_local_param.spp_slots[i]->scn == arg->stop_srv.scn) {
803 srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
804 break;
805 }
806 }
807 }
808 if (srv_cnt == 0) {
809 if (is_remove_all) {
810 BTC_TRACE_ERROR("%s can not find any server!\n", __func__);
811 } else {
812 BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.scn);
813 }
814 ret = ESP_SPP_NO_SERVER;
815 break;
816 }
817
818 // [2] remove all local related connection
819 for (j = 0; j < srv_cnt; j++) {
820 for (i = 1; i <= MAX_RFC_PORTS; i++) {
821 if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->is_server &&
822 spp_local_param.spp_slots[i]->sdp_handle > 0 &&
823 spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
824 BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (void *)spp_local_param.spp_slots[i]->id);
825 }
826 }
827 }
828
829 // [3] remove all server
830 for (j = 0; j < srv_cnt; j++) {
831 for (i = 1; i <= MAX_RFC_PORTS; i++) {
832 if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->is_server &&
833 spp_local_param.spp_slots[i]->sdp_handle > 0 &&
834 spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
835 if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
836 BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
837 }
838
839 if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
840 BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
841 (void *)spp_local_param.spp_slots[i]->id);
842 }
843
844 tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
845 if (user_data) {
846 user_data->server_status = BTA_JV_SERVER_RUNNING;
847 user_data->slot_id = spp_local_param.spp_slots[i]->id;
848 } else {
849 BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
850 assert(0);
851 }
852 BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
853 (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
854 }
855 }
856 }
857 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
858 } while (0);
859
860 if (ret != ESP_SPP_SUCCESS) {
861 esp_spp_cb_param_t param;
862 param.srv_stop.status = ret;
863 param.srv_stop.scn = BTC_SPP_INVALID_SCN;
864 btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
865 }
866
867 if (srv_scn_arr) {
868 osi_free(srv_scn_arr);
869 srv_scn_arr = NULL;
870 }
871 }
872
btc_spp_write(btc_spp_args_t * arg)873 static void btc_spp_write(btc_spp_args_t *arg)
874 {
875 esp_spp_status_t ret = ESP_SPP_SUCCESS;
876
877 do {
878 if (!is_spp_init()) {
879 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
880 ret = ESP_SPP_NEED_INIT;
881 break;
882 }
883 spp_slot_t *slot = NULL;
884 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
885 slot = spp_find_slot_by_handle(arg->write.handle);
886 if (!slot || (slot && !slot->connected)) {
887 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
888 if (!slot) {
889 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
890 } else {
891 BTC_TRACE_ERROR("%s RFCOMM has been disconnected already!", __func__);
892 }
893 ret = ESP_SPP_NO_CONNECTION;
894 break;
895 }
896 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
897 if (slot->is_writing) {
898 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
899 return;
900 }
901 size_t item_size = 0;
902 uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
903 if (item_size > 0) {
904 slot->write_data = data;
905 slot->write_data_len = item_size;
906 slot->is_writing = true;
907 BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data);
908 }
909 } else {
910 if (fixed_queue_enqueue(slot->tx.queue, arg->write.p_data, 0)) {
911 BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
912 } else {
913 ret = ESP_SPP_NO_RESOURCE;
914 }
915 }
916 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
917 } while (0);
918
919 if (ret != ESP_SPP_SUCCESS && spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
920 esp_spp_cb_param_t param;
921 param.write.status = ret;
922 param.write.handle = 0;
923 param.write.len = -1;
924 param.write.cong = false;
925 btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m);
926 }
927 }
928
929
btc_spp_arg_deep_copy(btc_msg_t * msg,void * p_dest,void * p_src)930 void btc_spp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
931 {
932 btc_spp_args_t *dst = (btc_spp_args_t *) p_dest;
933 btc_spp_args_t *src = (btc_spp_args_t *) p_src;
934
935 switch (msg->act) {
936 case BTC_SPP_ACT_START_DISCOVERY:
937 dst->start_discovery.p_uuid_list = (tSDP_UUID *)osi_malloc(src->start_discovery.num_uuid * sizeof(tSDP_UUID));
938 if (dst->start_discovery.p_uuid_list) {
939 memcpy(dst->start_discovery.p_uuid_list, src->start_discovery.p_uuid_list, src->start_discovery.num_uuid * sizeof(tSDP_UUID));
940 } else if (src->start_discovery.num_uuid == 0) {
941 BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
942 } else {
943 BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
944 }
945 break;
946 case BTC_SPP_ACT_WRITE:
947 dst->write.p_data = (uint8_t *)osi_malloc(src->write.len);
948 if (dst->write.p_data) {
949 memcpy(dst->write.p_data, src->write.p_data, src->write.len);
950 } else if (src->write.len == 0) {
951 BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
952 } else {
953 BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
954 }
955 break;
956 default:
957 break;
958 }
959 }
960
btc_spp_arg_deep_free(btc_msg_t * msg)961 void btc_spp_arg_deep_free(btc_msg_t *msg)
962 {
963 btc_spp_args_t *arg = (btc_spp_args_t *)msg->arg;
964
965 switch (msg->act) {
966 case BTC_SPP_ACT_START_DISCOVERY:
967 if (arg->start_discovery.p_uuid_list) {
968 osi_free(arg->start_discovery.p_uuid_list);
969 }
970 break;
971 default:
972 break;
973 }
974 }
975
btc_spp_call_handler(btc_msg_t * msg)976 void btc_spp_call_handler(btc_msg_t *msg)
977 {
978 btc_spp_args_t *arg = (btc_spp_args_t *)(msg->arg);
979 switch (msg->act) {
980 case BTC_SPP_ACT_INIT:
981 btc_spp_init(arg);
982 break;
983 case BTC_SPP_ACT_UNINIT:
984 btc_spp_uninit();
985 break;
986 case BTC_SPP_ACT_START_DISCOVERY:
987 btc_spp_start_discovery(arg);
988 break;
989 case BTC_SPP_ACT_CONNECT:
990 btc_spp_connect(arg);
991 break;
992 case BTC_SPP_ACT_DISCONNECT:
993 btc_spp_disconnect(arg);
994 break;
995 case BTC_SPP_ACT_START_SRV:
996 btc_spp_start_srv(arg);
997 break;
998 case BTC_SPP_ACT_STOP_SRV:
999 btc_spp_stop_srv(arg);
1000 break;
1001 case BTC_SPP_ACT_WRITE:
1002 btc_spp_write(arg);
1003 break;
1004 case BTC_SPP_ACT_VFS_REGISTER:
1005 btc_spp_vfs_register();
1006 break;
1007 case BTC_SPP_ACT_VFS_UNREGISTER:
1008 btc_spp_vfs_unregister();
1009 break;
1010 default:
1011 BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act);
1012 break;
1013 }
1014 btc_spp_arg_deep_free(msg);
1015 }
1016
btc_spp_cb_handler(btc_msg_t * msg)1017 void btc_spp_cb_handler(btc_msg_t *msg)
1018 {
1019 esp_spp_cb_param_t param;
1020 tBTA_JV *p_data = (tBTA_JV *)msg->arg;
1021 spp_slot_t *slot = NULL;
1022 uint8_t serial = 0;
1023 uint8_t event = msg->act;
1024
1025 switch (event) {
1026 case BTA_JV_ENABLE_EVT:
1027 param.init.status = p_data->status;
1028 btc_spp_cb_to_app(ESP_SPP_INIT_EVT, ¶m);
1029 break;
1030 case BTA_JV_DISCOVERY_COMP_EVT:
1031 param.disc_comp.status = p_data->disc_comp.status;
1032 param.disc_comp.scn_num = p_data->disc_comp.scn_num;
1033 memcpy(param.disc_comp.scn, p_data->disc_comp.scn, p_data->disc_comp.scn_num);
1034 memcpy(param.disc_comp.service_name, p_data->disc_comp.service_name,
1035 p_data->disc_comp.scn_num * sizeof(const char *));
1036 btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m);
1037 break;
1038 case BTA_JV_RFCOMM_CL_INIT_EVT:
1039 param.cl_init.status = p_data->rfc_cl_init.status;
1040 param.cl_init.handle = p_data->rfc_cl_init.handle;
1041 param.cl_init.sec_id = p_data->rfc_cl_init.sec_id;
1042 param.cl_init.use_co = p_data->rfc_cl_init.use_co;
1043 btc_spp_cb_to_app(ESP_SPP_CL_INIT_EVT, ¶m);
1044 break;
1045 case BTA_JV_RFCOMM_OPEN_EVT:
1046 do {
1047 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
1048 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1049 slot = spp_find_slot_by_handle(p_data->rfc_open.handle);
1050 if (!slot) {
1051 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1052 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
1053 param.open.status = ESP_SPP_NO_CONNECTION;
1054 break;
1055 }
1056 param.open.fd = slot->fd;
1057 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1058 } else {
1059 param.open.fd = -1;
1060 }
1061 param.open.status = p_data->rfc_open.status;
1062 } while (0);
1063 param.open.handle = p_data->rfc_open.handle;
1064 memcpy(param.open.rem_bda, p_data->rfc_open.rem_bda, ESP_BD_ADDR_LEN);
1065 btc_spp_cb_to_app(ESP_SPP_OPEN_EVT, ¶m);
1066 break;
1067 case BTA_JV_RFCOMM_START_EVT:
1068 param.start.status = p_data->rfc_start.status;
1069 param.start.handle = p_data->rfc_start.handle;
1070 param.start.sec_id = p_data->rfc_start.sec_id;
1071 param.start.scn = p_data->rfc_start.scn;
1072 param.start.use_co = p_data->rfc_start.use_co;
1073 btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
1074 break;
1075 case BTA_JV_RFCOMM_SRV_OPEN_EVT:
1076 if (p_data->rfc_srv_open.handle) {
1077 do {
1078 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
1079 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1080 slot = spp_find_slot_by_handle(p_data->rfc_srv_open.handle);
1081 if (!slot) {
1082 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1083 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
1084 param.srv_open.status = ESP_SPP_NO_CONNECTION;
1085 break;
1086 }
1087 param.srv_open.fd = slot->fd;
1088 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1089 } else {
1090 param.srv_open.fd = -1;
1091 }
1092 param.srv_open.status = p_data->rfc_srv_open.status;
1093 } while (0);
1094 param.srv_open.handle = p_data->rfc_srv_open.handle;
1095 param.srv_open.new_listen_handle = p_data->rfc_srv_open.new_listen_handle;
1096 memcpy(param.srv_open.rem_bda, p_data->rfc_srv_open.rem_bda, ESP_BD_ADDR_LEN);
1097 btc_spp_cb_to_app(ESP_SPP_SRV_OPEN_EVT, ¶m);
1098 }
1099 break;
1100 case BTA_JV_RFCOMM_WRITE_EVT:
1101 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1102 slot = spp_find_slot_by_handle(p_data->rfc_write.handle);
1103 if (!slot) {
1104 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!, handle:%d", __func__, p_data->rfc_write.handle);
1105 }
1106 if (spp_local_param.spp_mode == ESP_SPP_MODE_CB){
1107 param.write.status = slot ? p_data->rfc_write.status : ESP_SPP_NO_CONNECTION;
1108 param.write.handle = p_data->rfc_write.handle;
1109 param.write.len = p_data->rfc_write.len;
1110 param.write.cong = p_data->rfc_write.cong;
1111 btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m);
1112 if (slot) {
1113 osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
1114 }
1115 } else {
1116 if (slot) {
1117 size_t item_size = 0;
1118 size_t items_waiting = 0;
1119 serial = slot->serial;
1120 if (p_data->rfc_write.status == BTA_JV_SUCCESS) {
1121 vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
1122 slot->write_data = NULL;
1123 slot->is_writing = false;
1124 slot->write_data_len = 0;
1125 vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting);
1126 if (spp_local_param.tx_buffer_size > items_waiting) {
1127 xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
1128 }
1129 if (items_waiting == 0) {
1130 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1131 break;
1132 }
1133 if (!p_data->rfc_write.cong) {
1134 uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
1135 if (item_size > 0) {
1136 slot->write_data = data;
1137 slot->write_data_len = item_size;
1138 slot->is_writing = true;
1139 BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, item_size, data);
1140 }
1141 }
1142 } else {
1143 if (!p_data->rfc_write.old_cong) {
1144 // PORT_WriteDataCO failed
1145 BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", slot->write_data,
1146 p_data->rfc_write.handle);
1147 } else {
1148 // need rewrite
1149 if (!p_data->rfc_write.cong && slot->connected) {
1150 slot->is_writing = true;
1151 BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, slot->write_data_len, slot->write_data);
1152 } else {
1153 slot->is_writing = false;
1154 }
1155 }
1156 }
1157 }
1158 }
1159 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1160 break;
1161 case BTA_JV_RFCOMM_CLOSE_EVT:
1162 param.close.status = BTA_JV_SUCCESS;
1163 param.close.port_status = p_data->rfc_close.port_status;
1164 param.close.handle = p_data->rfc_close.handle;
1165 param.close.async = p_data->rfc_close.async;
1166 if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
1167 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1168 slot = spp_find_slot_by_handle(p_data->rfc_close.handle);
1169 if (!slot) {
1170 param.close.status = ESP_SPP_NO_CONNECTION;
1171 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1172 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
1173 break;
1174 }
1175 spp_free_slot(slot);
1176 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1177 btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
1178 } else {
1179 bool need_call = true;
1180 do {
1181 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1182 slot = spp_find_slot_by_handle(p_data->rfc_close.handle);
1183 if (!slot) {
1184 param.close.status = ESP_SPP_NO_CONNECTION;
1185 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1186 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
1187 break;
1188 }
1189 // if rx still has data, delay free slot
1190 if (slot->close_alarm == NULL && slot->rx.queue && fixed_queue_length(slot->rx.queue) > 0) {
1191 tBTA_JV *p_arg = NULL;
1192 if ((p_arg = osi_malloc(sizeof(tBTA_JV))) == NULL) {
1193 param.close.status = ESP_SPP_NO_RESOURCE;
1194 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1195 BTC_TRACE_ERROR("%s unable to malloc slot close_alarm arg!", __func__);
1196 break;
1197 }
1198 memcpy(p_arg, p_data, sizeof(tBTA_JV));
1199 slot->alarm_arg = (void *)p_arg;
1200 if ((slot->close_alarm =
1201 osi_alarm_new("slot", close_timeout_handler, (void *)slot, VFS_CLOSE_TIMEOUT)) == NULL) {
1202 osi_free(p_arg);
1203 slot->alarm_arg = NULL;
1204 param.close.status = ESP_SPP_NO_RESOURCE;
1205 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1206 BTC_TRACE_ERROR("%s unable to malloc slot close_alarm!", __func__);
1207 break;
1208 }
1209 if (osi_alarm_set(slot->close_alarm, VFS_CLOSE_TIMEOUT) != OSI_ALARM_ERR_PASS) {
1210 osi_free(p_arg);
1211 slot->alarm_arg = NULL;
1212 osi_alarm_free(slot->close_alarm);
1213 param.close.status = ESP_SPP_BUSY;
1214 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1215 BTC_TRACE_ERROR("%s set slot close_alarm failed!", __func__);
1216 break;
1217 }
1218 BTC_TRACE_WARNING("%s slot rx data will be discard in %d milliseconds!",
1219 __func__, VFS_CLOSE_TIMEOUT);
1220 slot->connected = false;
1221 need_call = false;
1222 }
1223 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1224 } while (0);
1225
1226 if (need_call) {
1227 btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
1228 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1229 spp_free_slot(slot);
1230 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1231 }
1232 }
1233 break;
1234 case BTA_JV_RFCOMM_CONG_EVT:
1235 if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
1236 param.cong.status = p_data->rfc_cong.status;
1237 param.cong.handle = p_data->rfc_cong.handle;
1238 param.cong.cong = p_data->rfc_cong.cong;
1239 btc_spp_cb_to_app(ESP_SPP_CONG_EVT, ¶m);
1240 } else {
1241 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1242 slot = spp_find_slot_by_handle(p_data->rfc_cong.handle);
1243 if (!slot) {
1244 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1245 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
1246 break;
1247 }
1248 if (!p_data->rfc_cong.cong && !slot->is_writing) {
1249 if (slot->write_data == NULL && slot->write_data_len == 0) {
1250 size_t item_size = 0;
1251 uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
1252 if (item_size > 0) {
1253 slot->write_data = data;
1254 slot->write_data_len = item_size;
1255 slot->is_writing = true;
1256 BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, item_size, data);
1257 }
1258 } else {
1259 slot->is_writing = true;
1260 BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, slot->write_data_len, slot->write_data);
1261 }
1262 }
1263 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1264 }
1265 break;
1266 case BTA_JV_RFCOMM_DATA_IND_EVT:
1267 do {
1268 BT_HDR *p_buf;
1269 UINT16 count = 0;
1270 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1271 slot = spp_find_slot_by_handle(p_data->data_ind.handle);
1272 if (!slot) {
1273 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1274 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
1275 break;
1276 }
1277 serial = slot->serial;
1278 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1279
1280 while (1) {
1281 // get incoming_data from slot incoming list
1282 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1283 if ((slot = spp_local_param.spp_slots[serial]) != NULL &&
1284 slot->rfc_handle == p_data->data_ind.handle &&
1285 fixed_queue_length(slot->rx.queue) > 0) {
1286 p_buf = (BT_HDR *)fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT);
1287 } else {
1288 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1289 break;
1290 }
1291 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1292
1293 // invoke callback
1294 if (p_buf) {
1295 count += 1;
1296 param.data_ind.status = ESP_SPP_SUCCESS;
1297 param.data_ind.handle = p_data->data_ind.handle;
1298 param.data_ind.len = p_buf->len;
1299 param.data_ind.data = p_buf->data + p_buf->offset;
1300 btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, ¶m);
1301 BTC_TRACE_DEBUG("data cb to app: len %d\n", p_buf->len);
1302 osi_free(p_buf);
1303 }
1304 }
1305 if (count != 0) {
1306 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1307 slot->credit_rx += count;
1308 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1309 BTA_JvRfcommFlowControl(p_data->data_ind.handle, count);
1310 BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
1311 }
1312 } while (0);
1313 break;
1314 case BTA_JV_FREE_SCN_EVT:
1315 if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) {
1316 param.srv_stop.status = p_data->free_scn.status;
1317 param.srv_stop.scn = p_data->free_scn.scn;
1318 btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
1319 }
1320 break;
1321 case BTA_JV_DISABLE_EVT:
1322 param.uninit.status = ESP_SPP_SUCCESS;
1323 spp_free_pending_slots();
1324 BTA_JvFree();
1325 osi_mutex_free(&spp_local_param.spp_slot_mutex);
1326 if (spp_local_param.tx_event_group) {
1327 vEventGroupDelete(spp_local_param.tx_event_group);
1328 spp_local_param.tx_event_group = NULL;
1329 }
1330 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
1331 if (spp_local_param.spp_vfs_id != -1) {
1332 esp_vfs_unregister_with_id(spp_local_param.spp_vfs_id);
1333 spp_local_param.spp_vfs_id = -1;
1334 }
1335 }
1336 #if SPP_DYNAMIC_MEMORY == TRUE
1337 osi_free(spp_local_param_ptr);
1338 spp_local_param_ptr = NULL;
1339 #endif
1340 btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, ¶m);
1341 break;
1342 default:
1343 BTC_TRACE_DEBUG("%s: Unhandled event (%d)!", __FUNCTION__, msg->act);
1344 break;
1345 }
1346
1347 }
1348
bta_co_rfc_data_incoming(void * user_data,BT_HDR * p_buf)1349 int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
1350 {
1351 int ret = 1;
1352 bt_status_t status;
1353 tBTA_JV p_data;
1354 btc_msg_t msg;
1355 msg.sig = BTC_SIG_API_CB;
1356 msg.pid = BTC_PID_SPP;
1357 msg.act = BTA_JV_RFCOMM_DATA_IND_EVT;
1358
1359 uint32_t id = (uintptr_t)user_data;
1360 if (!is_spp_init()) {
1361 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
1362 return -1;
1363 }
1364 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1365 spp_slot_t *slot = spp_find_slot_by_id(id);
1366 if (!slot) {
1367 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1368 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
1369 return -1;
1370 }
1371 p_data.data_ind.handle = slot->rfc_handle;
1372 p_data.data_ind.p_buf = NULL;
1373
1374 if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
1375 size_t rx_len = fixed_queue_length(slot->rx.queue);
1376 fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
1377 if (rx_len == 0) {
1378 BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, rx_len);
1379 status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_JV), NULL, NULL);
1380 assert(status == BT_STATUS_SUCCESS);
1381 }
1382 } else {
1383 fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
1384 }
1385 if (--slot->credit_rx == 0) {
1386 BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
1387 ret = 0; // reserved for other flow control
1388 }
1389 if (slot->credit_rx > BTA_JV_MAX_CREDIT_NUM) {
1390 BTC_TRACE_WARNING("%s credit %d", __func__, slot->credit_rx);
1391 assert(0);
1392 }
1393 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1394 return ret;
1395 }
1396
bta_co_rfc_data_outgoing_size(void * user_data,int * size)1397 int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
1398 {
1399 return 1;
1400 }
1401
bta_co_rfc_data_outgoing(void * user_data,uint8_t * buf,uint16_t size)1402 int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
1403 {
1404 return 1;
1405 }
1406
spp_send_data_to_btc(uint32_t handle,int len,uint8_t * p_data,esp_spp_mode_t spp_mode)1407 esp_err_t spp_send_data_to_btc(uint32_t handle, int len, uint8_t *p_data, esp_spp_mode_t spp_mode)
1408 {
1409 btc_msg_t msg;
1410 btc_spp_args_t arg;
1411
1412 if (spp_local_param.spp_mode != spp_mode) {
1413 BTC_TRACE_WARNING("The current mode used is %d\n", spp_local_param.spp_mode);
1414 return ESP_ERR_NOT_SUPPORTED;
1415 }
1416
1417 msg.sig = BTC_SIG_API_CALL;
1418 msg.pid = BTC_PID_SPP;
1419 msg.act = BTC_SPP_ACT_WRITE;
1420
1421 arg.write.handle = handle;
1422 arg.write.len = len;
1423 arg.write.p_data = p_data;
1424
1425 return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), btc_spp_arg_deep_copy,
1426 btc_spp_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
1427 }
1428
spp_vfs_write(int fd,const void * data,size_t size)1429 static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
1430 {
1431 assert(data != NULL);
1432 errno = 0;
1433 if (size == 0) {
1434 return 0;
1435 }
1436 if (!is_spp_init()) {
1437 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
1438 errno = ESRCH;
1439 return -1;
1440 }
1441
1442 spp_slot_t *slot = NULL;
1443 uint8_t serial = 0;
1444 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1445 slot = spp_find_slot_by_fd(fd);
1446 if (!slot) {
1447 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1448 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
1449 errno = ENOENT;
1450 return -1;
1451 }
1452 serial = slot->serial;
1453 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1454
1455 ssize_t sent = 0;
1456 size_t items_waiting = 0;
1457 size_t item_size = 0;
1458 EventBits_t tx_event_group_val = 0;
1459 BaseType_t done = false;
1460 while (size) {
1461 tx_event_group_val = 0;
1462 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1463 slot = spp_local_param.spp_slots[serial];
1464 if (slot && slot->connected) {
1465 items_waiting = 0;
1466 item_size = 0;
1467 vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting);
1468 if (items_waiting < spp_local_param.tx_buffer_size) {
1469 if ((spp_local_param.tx_buffer_size - items_waiting) > size) {
1470 item_size = size;
1471 done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0);
1472 } else {
1473 item_size = spp_local_param.tx_buffer_size - items_waiting;
1474 done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0);
1475 }
1476
1477 if (done) {
1478 sent += item_size;
1479 size -= item_size;
1480 if (slot->write_data == NULL) {
1481 spp_send_data_to_btc(slot->rfc_handle, 0, NULL, ESP_SPP_MODE_VFS);
1482 }
1483 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1484 continue;
1485 }
1486 }
1487
1488 BTC_TRACE_DEBUG("%s items_waiting:%d, fd:%d\n", __func__, items_waiting, fd);
1489 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1490
1491 // block until under water level, be closed or time out
1492 tx_event_group_val =
1493 xEventGroupWaitBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
1494 pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
1495 if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
1496 BTC_TRACE_ERROR("%s exit for RFCOMM close, fd:%d!", __func__, fd);
1497 errno = EPIPE;
1498 sent = -1;
1499 break;
1500 } else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
1501 continue;
1502 } else if (tx_event_group_val == 0) {
1503 BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
1504 errno = EBUSY;
1505 sent = -1;
1506 break;
1507 }
1508 } else {
1509 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1510 errno = EPIPE;
1511 sent = -1;
1512 break;
1513 }
1514 }
1515
1516 return sent;
1517 }
1518
spp_vfs_close(int fd)1519 static int spp_vfs_close(int fd)
1520 {
1521 errno = 0;
1522 if (!is_spp_init()) {
1523 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
1524 errno = ESRCH;
1525 return -1;
1526 }
1527 spp_slot_t *slot = NULL;
1528 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1529 slot = spp_find_slot_by_fd(fd);
1530 if (!slot) {
1531 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1532 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
1533 errno = ENOENT;
1534 return -1;
1535 }
1536 esp_spp_disconnect(slot->rfc_handle);
1537 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1538 return 0;
1539 }
1540
spp_vfs_read(int fd,void * dst,size_t size)1541 static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
1542 {
1543 assert(dst != NULL);
1544 errno = 0;
1545 if (!is_spp_init()) {
1546 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
1547 errno = ESRCH;
1548 return -1;
1549 }
1550
1551 spp_slot_t *slot = NULL;
1552 uint8_t serial = 0;
1553 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1554 slot = spp_find_slot_by_fd(fd);
1555 if (!slot) {
1556 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1557 BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
1558 errno = ENOENT;
1559 return -1;
1560 }
1561 serial = slot->serial;
1562 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1563
1564 ssize_t item_size = 0;
1565 uint16_t count = 0;
1566 BT_HDR *p_buf;
1567 while (1) {
1568 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1569 if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
1570 if (fixed_queue_length(slot->rx.queue) > 0) {
1571 // free unused p_buf
1572 if ((p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) != NULL && p_buf->len == 0) {
1573 osi_free(fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT));
1574 p_buf = NULL;
1575 count++;
1576 }
1577 if (size == 0 || (p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) == NULL) {
1578 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1579 break;
1580 }
1581 } else {
1582 /**
1583 * If close_alarm is not NULL, it means that we have received the BTA_JV_RFCOMM_CLOSE_EVT.
1584 * And we can trigger close_alarm immediately.
1585 */
1586 if (slot->close_alarm && osi_alarm_is_active(slot->close_alarm)) {
1587 osi_alarm_cancel(slot->close_alarm);
1588 osi_alarm_set(slot->close_alarm, 0);
1589 }
1590 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1591 break;
1592 }
1593 } else {
1594 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1595 BTC_TRACE_ERROR("%s peer close, data will be discarded!\n", __func__);
1596 errno = EPIPE;
1597 item_size = -1;
1598 break;
1599 }
1600 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1601
1602 if (p_buf->len <= size) {
1603 memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
1604 size -= p_buf->len;
1605 item_size += p_buf->len;
1606 dst += p_buf->len;
1607 p_buf->offset += p_buf->len;
1608 p_buf->len = 0; // indicate the p_buf is unused
1609 } else {
1610 memcpy(dst, p_buf->data + p_buf->offset, size);
1611 item_size += size;
1612 p_buf->offset += size;
1613 p_buf->len -= size;
1614 size = 0;
1615 }
1616 }
1617 if (count > 0) {
1618 osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1619 slot->credit_rx += count;
1620 if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
1621 BTA_JvRfcommFlowControl(slot->rfc_handle, count);
1622 BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
1623 }
1624 osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
1625 }
1626 return item_size;
1627 }
1628
btc_spp_vfs_register(void)1629 static void btc_spp_vfs_register(void)
1630 {
1631 esp_spp_status_t ret = ESP_SPP_SUCCESS;
1632 esp_spp_cb_param_t param;
1633
1634 do {
1635 if (!is_spp_init()) {
1636 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
1637 ret = ESP_SPP_NEED_INIT;
1638 break;
1639 }
1640
1641 esp_vfs_t vfs = {
1642 .flags = ESP_VFS_FLAG_DEFAULT,
1643 .write = spp_vfs_write,
1644 .open = NULL,
1645 .fstat = NULL,
1646 .close = spp_vfs_close,
1647 .read = spp_vfs_read,
1648 .fcntl = NULL
1649 };
1650
1651 // No FD range is registered here: spp_vfs_id is used to register/unregister
1652 // file descriptors
1653 if (esp_vfs_register_with_id(&vfs, NULL, &spp_local_param.spp_vfs_id) != ESP_OK) {
1654 ret = ESP_SPP_FAILURE;
1655 break;
1656 }
1657 } while (0);
1658
1659 param.vfs_register.status = ret;
1660 btc_spp_cb_to_app(ESP_SPP_VFS_REGISTER_EVT, ¶m);
1661 }
1662
btc_spp_vfs_unregister(void)1663 static void btc_spp_vfs_unregister(void)
1664 {
1665 esp_spp_status_t ret = ESP_SPP_SUCCESS;
1666 esp_spp_cb_param_t param;
1667
1668 do {
1669 if (!is_spp_init()) {
1670 BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
1671 ret = ESP_SPP_NEED_INIT;
1672 break;
1673 }
1674
1675 if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
1676 if (spp_local_param.spp_vfs_id != -1) {
1677 if (esp_vfs_unregister_with_id(spp_local_param.spp_vfs_id) != ESP_OK) {
1678 ret = ESP_SPP_FAILURE;
1679 break;
1680 }
1681 spp_local_param.spp_vfs_id = -1;
1682 }
1683 }
1684 } while (0);
1685
1686 param.vfs_unregister.status = ret;
1687 btc_spp_cb_to_app(ESP_SPP_VFS_UNREGISTER_EVT, ¶m);
1688 }
1689
1690 #endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
1691