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