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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
1688 }
1689 
1690 #endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
1691