1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
41
42
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
75
76
77
78
79
88
89
90
91
92
94
95
96
97
98
99
103
104
105
106
107
108
109
110
119
120
125
126
127
128
129
130
133
134
135
136
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
158
159
164
182
183
184
185
186
187
188
202
203
204
205
216
217
228
229
240
241
252
253
254
255
256
257
258
259
260
261
262
263
264
265
269
270
273
274
275
276
277
280
281
288
289
296
297
298
299
310
311
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
342
343
344
354
355
356
361
362
367
368
373
374
375
376
377
378
379
380
381
382
383
384
385
393
394
395
396
397
398
399
400
414
415
416
421
422
423
424
425
426
427
429
442
444
445
446
447
448
449
450
451
452
453
454
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
476
483
484
485
486
487
488
489
490
491
496
501
502
503
504
511
512
513
514
515
516
517
518
519
520
521
522
523
526
527
528
529
530
531
532
533
534
539
540
541
547
548
549
550
551
552
554
555
556
557
558
559
560
561
562
564
565
566
567
568
571
572
573
574
575
576
577
578
583
584
585
586
587
588
589
594
595
596
601
602
603
604
607
608
612
613
614
621
622
623
624
625
626
627
628
629
634
635
636
656
657
658
659
660
661
666
667
668
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
703
704
705
706
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
739
740
741
747
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
781
782
783
788
789
794
795
796
797
808
817
818
819
828
829
830
831
832
833
834
835
838
839
843
844
845
852
853
854
855
856
857
858
859
860
866
867
871
872
873
874
875
876
877
878
883
884
885
886
896
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
960
961
975
976
977
978
979
980
983
986
989
992
995
998
1001
1004
1007
1010
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1056
1057
1058
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1087
1088
1089
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1106
1107
1108
1109
1110
1111
1112
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1129
1133
1142
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1175
1176
1177
1178
1179
1180
1181
1182
1183
1189
1190
1191
1192
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1232
1233
1234
1235
1241
1242
1243
1248
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1277
1278
1279
1280
1281
1282
1283
1284
1285
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1321
1322
1323
1324
1325
1326
1330
1336
1337
1339
1340
1341
1342
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1364
1365
1366
1371
1372
1373
1374
1385
1389
1393
1394
1395
1396
1397
1401
1402
1406
1407
1408
1409
1410
1411
1412
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1436
1441
1442
1443
1444
1445
1446
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1476
1477
1478
1479
1480
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1508
1514
1515
1516
1517
1518
1519
1520
1521
1522
1527
1528
1529
1530
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1550
1551
1552
1553
1554
1555
1561
1562
1563
1564
1565
1566
1567
1568
1569
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1685
1686
1687
1688
1689
1690
/* ... */
#include <string.h>
#include "btc_spp.h"
#include "btc/btc_manage.h"
#include "btc/btc_task.h"
#include "bta/bta_jv_api.h"
#include "common/bt_trace.h"
#include "osi/allocator.h"
#include "esp_spp_api.h"
#include "osi/list.h"
#include "freertos/ringbuf.h"
#include "osi/mutex.h"
#include "osi/alarm.h"
#include <sys/errno.h>
#include <sys/lock.h>
#include <sys/fcntl.h>
#include "esp_vfs.h"
#include "esp_vfs_dev.h"
#include "stack/port_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "btc/btc_task.h"
#include "stack/btu.h"22 includes
#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
#define SLOT_WRITE_BIT(i) (1UL << (i - 1))
#define SLOT_CLOSE_BIT(i) (1UL << (i + MAX_RFC_PORTS - 1))
#define VFS_WRITE_TIMEOUT (40 * 1000)
#define SLOT_TX_QUEUE_SIZE 10
#define SLOT_TX_QUEUE_LOW_WM 4
#define SLOT_TX_DATA_HIGH_WM (SLOT_TX_QUEUE_SIZE * BTA_JV_DEF_RFC_MTU)
#define VFS_CLOSE_TIMEOUT (20 * 1000)7 defines
typedef struct {
bool peer_fc;
bool user_fc;
fixed_queue_t *queue;
uint32_t data_size;
}{...} slot_data_t;
typedef struct {
bool connected;
bool is_server;
bool is_writing;
uint8_t serial;
uint8_t scn;
uint8_t max_session;
uint16_t mtu;
uint16_t credit_rx;
uint16_t write_data_len;
uint32_t id;
uint32_t sdp_handle;
uint32_t rfc_handle;
uint32_t rfc_port_handle;
int fd;
uint8_t *write_data;
osi_alarm_t *close_alarm;
void *alarm_arg;
esp_spp_role_t role;
esp_spp_sec_t security;
esp_bd_addr_t addr;
slot_data_t rx;
union {
slot_data_t tx;
RingbufHandle_t ringbuf_write;
}{...};
uint8_t service_uuid[16];
char service_name[ESP_SPP_SERVER_NAME_MAX + 1];
}{...} spp_slot_t;
typedef struct {
uint16_t tx_buffer_size;
spp_slot_t *spp_slots[MAX_RFC_PORTS + 1];
uint32_t spp_slot_id;
esp_spp_mode_t spp_mode;
osi_mutex_t spp_slot_mutex;
EventGroupHandle_t tx_event_group;
esp_vfs_id_t spp_vfs_id;
}{...} spp_local_param_t;
#if SPP_DYNAMIC_MEMORY == FALSE
static spp_local_param_t spp_local_param;
#else
static spp_local_param_t *spp_local_param_ptr;
#define spp_local_param (*spp_local_param_ptr)/* ... */
#endif
static void btc_spp_vfs_register(void);
static void btc_spp_vfs_unregister(void);
static void spp_osi_free(void *p)
{
osi_free(p);
}{...}
#if SPP_DYNAMIC_MEMORY == FALSE
#define is_spp_init() (spp_local_param.spp_slot_mutex != NULL)
#else
#define is_spp_init() (&spp_local_param != NULL && spp_local_param.spp_slot_mutex != NULL)
#endif
static int init_slot_data(slot_data_t *slot_data, size_t queue_size)
{
memset(slot_data, 0, sizeof(slot_data_t));
if ((slot_data->queue = fixed_queue_new(queue_size)) == NULL) {
return -1;
}{...}
slot_data->data_size = 0;
return 0;
}{...}
static void free_slot_data(slot_data_t *slot_data)
{
fixed_queue_free(slot_data->queue, spp_osi_free);
slot_data->queue = NULL;
}{...}
static spp_slot_t *spp_malloc_slot(void)
{
uint8_t err_no = 0;
spp_slot_t **slot = NULL;
if (++spp_local_param.spp_slot_id == 0) {
spp_local_param.spp_slot_id = 1;
}{...}
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
slot = &spp_local_param.spp_slots[i];
if ((*slot) == NULL) {
if (((*slot) = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t))) == NULL) {
return NULL;
}{...}
(*slot)->id = spp_local_param.spp_slot_id;
(*slot)->serial = i;
(*slot)->sdp_handle = 0;
(*slot)->rfc_handle = 0;
(*slot)->rfc_port_handle = 0;
(*slot)->fd = -1;
(*slot)->connected = false;
(*slot)->is_server = false;
(*slot)->mtu = 0;
(*slot)->credit_rx = BTA_JV_MAX_CREDIT_NUM;
(*slot)->write_data = NULL;
(*slot)->write_data_len = 0;
(*slot)->is_writing = false;
(*slot)->close_alarm = NULL;
(*slot)->alarm_arg = NULL;
if (spp_local_param.tx_event_group) {
xEventGroupClearBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(i) | SLOT_CLOSE_BIT(i));
}{...}
if (init_slot_data(&(*slot)->rx, QUEUE_SIZE_MAX)) {
BTC_TRACE_ERROR("%s unable to malloc rx queue!", __func__);
err_no = 1;
goto err;
}{...}
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
err_no = 2;
goto err;
}{...}
}{...} else {
if (((*slot)->ringbuf_write = xRingbufferCreate(spp_local_param.tx_buffer_size, RINGBUF_TYPE_BYTEBUF)) == NULL) {
BTC_TRACE_ERROR("%s write ringbuffer create error!", __func__);
err_no = 2;
goto err;
}{...}
if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &(*slot)->fd) != ESP_OK) {
BTC_TRACE_ERROR("%s unable to register fd!", __func__);
err_no = 3;
goto err;
}{...}
}{...}
return (*slot);
}{...}
}{...}
return NULL;
err:
switch (err_no) {
case 3:
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
vRingbufferDelete((*slot)->ringbuf_write);
}{...}
... case 2:
free_slot_data(&(*slot)->rx);...
case 1:
osi_free((*slot));
(*slot) = NULL;
break;...
default:
break;...
}{...}
return (*slot);
}{...}
static spp_slot_t *spp_find_slot_by_id(uint32_t id)
{
spp_slot_t *slot = NULL;
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
slot = spp_local_param.spp_slots[i];
if (slot != NULL && slot->id == id) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static spp_slot_t *spp_find_slot_by_handle(uint32_t handle)
{
spp_slot_t *slot = NULL;
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
slot = spp_local_param.spp_slots[i];
if (slot != NULL && slot->rfc_handle == handle) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static spp_slot_t *spp_find_slot_by_fd(int fd)
{
spp_slot_t *slot = NULL;
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
slot = spp_local_param.spp_slots[i];
if (slot != NULL && slot->fd == fd) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static spp_slot_t *spp_find_slot_by_scn(uint32_t scn)
{
spp_slot_t *slot = NULL;
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
slot = spp_local_param.spp_slots[i];
if (slot != NULL && slot->is_server && slot->scn == (uint8_t)scn) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static void close_timeout_handler(void *arg)
{
btc_msg_t msg;
bt_status_t status;
spp_slot_t *slot = (spp_slot_t *)arg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_SPP;
msg.act = BTA_JV_RFCOMM_CLOSE_EVT;
status = btc_transfer_context(&msg, slot->alarm_arg, sizeof(tBTA_JV), NULL, NULL);
if (slot->alarm_arg) {
osi_free(slot->alarm_arg);
slot->alarm_arg = NULL;
}{...}
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
}{...}
}{...}
static void spp_free_slot(spp_slot_t *slot)
{
if (!slot) {
return;
}{...}
spp_local_param.spp_slots[slot->serial] = NULL;
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
(void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd);
xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
vRingbufferDelete(slot->ringbuf_write);
}{...} else {
free_slot_data(&slot->tx);
}{...}
free_slot_data(&slot->rx);
if (slot->close_alarm) {
osi_alarm_free(slot->close_alarm);
if (slot->alarm_arg) {
osi_free(slot->alarm_arg);
slot->alarm_arg = NULL;
}{...}
}{...}
osi_free(slot);
}{...}
static void spp_free_pending_slots(void)
{
spp_slot_t *slot = NULL;
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
slot = spp_local_param.spp_slots[i];
if (slot) {
BTC_TRACE_WARNING("%s found slot(rfc_handle=0x%x) pending to close, close it now!", __func__, slot->rfc_handle);
spp_free_slot(slot);
}{...}
}{...}
}{...}
static inline void btc_spp_cb_to_app(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
esp_spp_cb_t btc_spp_cb = (esp_spp_cb_t)btc_profile_cb_get(BTC_PID_SPP);
if (btc_spp_cb) {
btc_spp_cb(event, param);
}{...}
}{...}
static void btc_create_server_fail_cb(void)
{
esp_spp_cb_param_t param;
param.start.status = ESP_SPP_FAILURE;
param.start.handle = 0;
param.start.sec_id = 0;
param.start.scn = BTC_SPP_INVALID_SCN;
param.start.use_co = FALSE;
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
}{...}
static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
bt_status_t status;
btc_msg_t msg;
void *new_user_data = NULL;
uint32_t id = (uintptr_t)user_data, id_temp = 0;
spp_slot_t *slot = NULL, *slot_new = NULL;
if (!is_spp_init()) {
BTC_TRACE_WARNING("%s SPP have been deinit, incoming events ignore!\n", __func__);
return new_user_data;
}{...}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
switch (event) {
case BTA_JV_RFCOMM_START_EVT:
slot = spp_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
p_data->rfc_start.status = ESP_SPP_NO_CONNECTION;
break;
}{...}
slot->rfc_handle = p_data->rfc_start.handle;
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_start.handle);
break;...
case BTA_JV_RFCOMM_SRV_OPEN_EVT:
slot = p_data->rfc_srv_open.handle ? spp_find_slot_by_id(id) : spp_find_slot_by_scn((uint32_t)user_data);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
p_data->rfc_srv_open.status = ESP_SPP_NO_CONNECTION;
break;
}{...}
if (!p_data->rfc_srv_open.handle) {
slot->rfc_handle = p_data->rfc_srv_open.new_listen_handle;
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot->rfc_handle);
}{...} else {
slot_new = spp_malloc_slot();
if (!slot_new) {
BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
p_data->rfc_srv_open.status = ESP_SPP_NO_RESOURCE;
break;
}{...}
slot_new->connected = true;
slot_new->security = slot->security;
slot_new->role = slot->role;
slot_new->scn = slot->scn;
slot_new->max_session = slot->max_session;
strcpy(slot_new->service_name, slot->service_name);
slot_new->sdp_handle = slot->sdp_handle;
slot_new->mtu = p_data->rfc_srv_open.peer_mtu;
slot_new->rfc_handle = p_data->rfc_srv_open.handle;
slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot_new->rfc_handle);
BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN);
if (p_data->rfc_srv_open.new_listen_handle) {
slot->rfc_handle = p_data->rfc_srv_open.new_listen_handle;
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot->rfc_handle);
}{...} else {
slot->rfc_handle = 0;
slot->rfc_port_handle = 0;
}{...}
id_temp = slot->id;
slot->id = slot_new->id;
slot_new->id = id_temp;
}{...}
new_user_data = (void *)(uintptr_t)slot->id;
break;...
case BTA_JV_RFCOMM_CL_INIT_EVT:
slot = spp_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
p_data->rfc_cl_init.status = ESP_SPP_FAILURE;
break;
}{...}
if (p_data->rfc_cl_init.status == BTA_JV_SUCCESS) {
slot->rfc_handle = p_data->rfc_cl_init.handle;
}{...} else {
spp_free_slot(slot);
}{...}
break;...
case BTA_JV_RFCOMM_OPEN_EVT:
slot = spp_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
p_data->rfc_open.status = ESP_SPP_NO_CONNECTION;
break;
}{...}
slot->connected = true;
slot->rfc_handle = p_data->rfc_open.handle;
slot->mtu = p_data->rfc_open.peer_mtu;
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_data->rfc_open.handle);
BTA_JvSetPmProfile(p_data->rfc_open.handle, BTA_JV_PM_ID_1, BTA_JV_CONN_OPEN);
break;...
case BTA_JV_RFCOMM_DATA_IND_EVT:
break;...
case BTA_JV_FREE_SCN_EVT:
if (user_data) {
id = ((tBTA_JV_FREE_SCN_USER_DATA *)user_data)->slot_id;
slot = spp_find_slot_by_id(id);
if (slot) {
spp_free_slot(slot);
}{...} else {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
p_data->free_scn.status = ESP_SPP_NO_CONNECTION;
}{...}
osi_free(user_data);
}{...}
break;...
default:
break;...
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_SPP;
msg.act = event;
status = btc_transfer_context(&msg, p_data,
sizeof(tBTA_JV), NULL, NULL);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
}{...}
return new_user_data;
}{...}
static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
bt_status_t status;
btc_msg_t msg;
uint32_t id = (uintptr_t)user_data;
spp_slot_t *slot = NULL;
switch (event) {
case BTA_JV_GET_SCN_EVT:
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_id(id);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
if (p_data->scn == 0) {
btc_create_server_fail_cb();
spp_free_slot(slot);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to get scn, start server fail!", __func__);
break;
}{...}
slot->scn = p_data->scn;
BTA_JvCreateRecordByUser(slot->service_name, slot->scn, (void *)slot->id);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;...
case BTA_JV_CREATE_RECORD_EVT:
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_id(id);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
if (p_data->create_rec.status == BTA_JV_SUCCESS) {
slot->sdp_handle = p_data->create_rec.handle;
BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn,
slot->max_session, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id);
}{...} else {
BTC_TRACE_ERROR("%s unable to create record, start server fail!", __func__);
btc_create_server_fail_cb();
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
if (user_data) {
user_data->server_status = BTA_JV_SERVER_START_FAILED;
user_data->slot_id = slot->id;
}{...} else {
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
assert(0);
}{...}
BTA_JvFreeChannel(slot->scn, BTA_JV_CONN_TYPE_RFCOMM,
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;...
default:
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_SPP;
msg.act = event;
status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL, NULL);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
}{...}
break;...
}{...}
}{...}
static void btc_spp_init(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (is_spp_init()) {
BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__);
ret = ESP_SPP_NEED_DEINIT;
break;
}{...}
#if SPP_DYNAMIC_MEMORY == TRUE
if ((spp_local_param_ptr = (spp_local_param_t *)osi_malloc(sizeof(spp_local_param_t))) == NULL) {
BTC_TRACE_ERROR("%s malloc failed\n", __func__);
ret = ESP_SPP_NO_RESOURCE;
break;
}{...}
memset((void *)spp_local_param_ptr, 0, sizeof(spp_local_param_t));/* ... */
#endif
if (osi_mutex_new(&spp_local_param.spp_slot_mutex) != 0) {
BTC_TRACE_ERROR("%s osi_mutex_new failed\n", __func__);
#if SPP_DYNAMIC_MEMORY == TRUE
osi_free(spp_local_param_ptr);
spp_local_param_ptr = NULL;/* ... */
#endif
ret = ESP_SPP_NO_RESOURCE;
break;
}{...}
if ((spp_local_param.tx_event_group = xEventGroupCreate()) == NULL) {
BTC_TRACE_ERROR("%s create tx_event_group failed\n", __func__);
osi_mutex_free(&spp_local_param.spp_slot_mutex);
#if SPP_DYNAMIC_MEMORY == TRUE
osi_free(spp_local_param_ptr);
spp_local_param_ptr = NULL;/* ... */
#endif
ret = ESP_SPP_NO_RESOURCE;
break;
}{...}
if (arg->init.mode == ESP_SPP_MODE_VFS) {
spp_local_param.spp_vfs_id = -1;
}{...}
spp_local_param.spp_mode = arg->init.mode;
spp_local_param.spp_slot_id = 0;
spp_local_param.tx_buffer_size = arg->init.tx_buffer_size;
BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
BTA_JvRfcommConfig(arg->init.enable_l2cap_ertm);
}{...} while (0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.init.status = ret;
btc_spp_cb_to_app(ESP_SPP_INIT_EVT, ¶m);
}{...}
}{...}
static void btc_spp_uninit(void)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP has not been initiated, shall init first!", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->is_server) {
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (void *)spp_local_param.spp_slots[i]->id);
}{...}
}{...}
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->is_server) {
if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
}{...}
if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
(void *)spp_local_param.spp_slots[i]->id);
}{...}
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
if (user_data) {
user_data->server_status = BTA_JV_SERVER_RUNNING;
user_data->slot_id = spp_local_param.spp_slots[i]->id;
}{...} else {
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
assert(0);
}{...}
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
}{...}
}{...}
BTA_JvDisable((tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while(0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.uninit.status = ret;
btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, ¶m);
}{...}
}{...}
static void btc_spp_start_discovery(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL);
}{...} while (0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.disc_comp.status = ret;
param.disc_comp.scn_num = 0xff;
memset(param.disc_comp.scn, 0xff, ESP_SPP_MAX_SCN);
btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m);
}{...}
}{...}
static void btc_spp_connect(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_malloc_slot();
if (!slot) {
BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
ret = ESP_SPP_NO_RESOURCE;
break;
}{...}
slot->security = arg->connect.sec_mask;
slot->role = arg->connect.role;
slot->scn = arg->connect.remote_scn;
memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN);
BTA_JvRfcommConnect(arg->connect.sec_mask, arg->connect.role, arg->connect.remote_scn,
arg->connect.peer_bd_addr, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while (0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.open.status = ret;
param.open.handle = 0;
param.open.fd = -1;
memset(param.open.rem_bda, 0, ESP_BD_ADDR_LEN);
btc_spp_cb_to_app(ESP_SPP_OPEN_EVT, ¶m);
}{...}
}{...}
static void btc_spp_disconnect(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
spp_slot_t *slot = NULL;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(arg->disconnect.handle);
if (!slot || (slot && !slot->connected)) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
}{...} else {
BTC_TRACE_ERROR("%s RFCOMM has been disconnected already!", __func__);
}{...}
ret = ESP_SPP_NO_CONNECTION;
break;
}{...}
BTA_JvRfcommClose(arg->disconnect.handle, (void *)slot->id);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while(0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.close.status = ret;
param.close.port_status = PORT_ERR_MAX;
param.close.handle = 0;
param.close.async = FALSE;
btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
}{...}
}{...}
static void btc_spp_start_srv(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_malloc_slot();
if (!slot) {
BTC_TRACE_ERROR("%s unable to malloc RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
ret = ESP_SPP_NO_RESOURCE;
break;
}{...}
/* ... */
slot->is_server = true;
slot->security = arg->start_srv.sec_mask;
slot->role = arg->start_srv.role;
slot->scn = arg->start_srv.local_scn;
slot->max_session = arg->start_srv.max_session;
strcpy(slot->service_name, arg->start_srv.name);
BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void *)slot->id, arg->start_srv.local_scn);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while(0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.start.status = ret;
param.start.handle = 0;
param.start.sec_id = 0;
param.start.scn = BTC_SPP_INVALID_SCN;
param.start.use_co = FALSE;
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
}{...}
}{...}
static void btc_spp_stop_srv(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
bool is_remove_all = false;
uint8_t i, j, srv_cnt = 0;
uint8_t *srv_scn_arr = NULL;
if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) {
is_remove_all = true;
}{...}
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
srv_scn_arr = osi_malloc(MAX_RFC_PORTS);
if (srv_scn_arr == NULL) {
BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__);
ret = ESP_SPP_NO_RESOURCE;
break;
}{...}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
for (i = 1; i <= MAX_RFC_PORTS; i++) {
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected &&
spp_local_param.spp_slots[i]->sdp_handle > 0) {
if (is_remove_all) {
srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
}{...} else if (spp_local_param.spp_slots[i]->scn == arg->stop_srv.scn) {
srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
break;
}{...}
}{...}
}{...}
if (srv_cnt == 0) {
if (is_remove_all) {
BTC_TRACE_ERROR("%s can not find any server!\n", __func__);
}{...} else {
BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.scn);
}{...}
ret = ESP_SPP_NO_SERVER;
break;
}{...}
for (j = 0; j < srv_cnt; j++) {
for (i = 1; i <= MAX_RFC_PORTS; i++) {
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->is_server &&
spp_local_param.spp_slots[i]->sdp_handle > 0 &&
spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (void *)spp_local_param.spp_slots[i]->id);
}{...}
}{...}
}{...}
for (j = 0; j < srv_cnt; j++) {
for (i = 1; i <= MAX_RFC_PORTS; i++) {
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->is_server &&
spp_local_param.spp_slots[i]->sdp_handle > 0 &&
spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
}{...}
if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
(void *)spp_local_param.spp_slots[i]->id);
}{...}
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
if (user_data) {
user_data->server_status = BTA_JV_SERVER_RUNNING;
user_data->slot_id = spp_local_param.spp_slots[i]->id;
}{...} else {
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
assert(0);
}{...}
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
}{...}
}{...}
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while (0);
if (ret != ESP_SPP_SUCCESS) {
esp_spp_cb_param_t param;
param.srv_stop.status = ret;
param.srv_stop.scn = BTC_SPP_INVALID_SCN;
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
}{...}
if (srv_scn_arr) {
osi_free(srv_scn_arr);
srv_scn_arr = NULL;
}{...}
}{...}
static void btc_spp_write(btc_spp_args_t *arg)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
spp_slot_t *slot = NULL;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(arg->write.handle);
if (!slot || (slot && !slot->connected)) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
}{...} else {
BTC_TRACE_ERROR("%s RFCOMM has been disconnected already!", __func__);
}{...}
ret = ESP_SPP_NO_CONNECTION;
break;
}{...}
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
if (slot->is_writing) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return;
}{...}
size_t item_size = 0;
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
if (item_size > 0) {
slot->write_data = data;
slot->write_data_len = item_size;
slot->is_writing = true;
BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data);
}{...}
}{...} else {
if (fixed_queue_enqueue(slot->tx.queue, arg->write.p_data, 0)) {
BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
}{...} else {
ret = ESP_SPP_NO_RESOURCE;
}{...}
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while (0);
if (ret != ESP_SPP_SUCCESS && spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
esp_spp_cb_param_t param;
param.write.status = ret;
param.write.handle = 0;
param.write.len = -1;
param.write.cong = false;
btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m);
}{...}
}{...}
void btc_spp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
btc_spp_args_t *dst = (btc_spp_args_t *) p_dest;
btc_spp_args_t *src = (btc_spp_args_t *) p_src;
switch (msg->act) {
case BTC_SPP_ACT_START_DISCOVERY:
dst->start_discovery.p_uuid_list = (tSDP_UUID *)osi_malloc(src->start_discovery.num_uuid * sizeof(tSDP_UUID));
if (dst->start_discovery.p_uuid_list) {
memcpy(dst->start_discovery.p_uuid_list, src->start_discovery.p_uuid_list, src->start_discovery.num_uuid * sizeof(tSDP_UUID));
}{...} else if (src->start_discovery.num_uuid == 0) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}{...} else {
BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
}{...}
break;...
case BTC_SPP_ACT_WRITE:
dst->write.p_data = (uint8_t *)osi_malloc(src->write.len);
if (dst->write.p_data) {
memcpy(dst->write.p_data, src->write.p_data, src->write.len);
}{...} else if (src->write.len == 0) {
BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
}{...} else {
BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
}{...}
break;...
default:
break;...
}{...}
}{...}
void btc_spp_arg_deep_free(btc_msg_t *msg)
{
btc_spp_args_t *arg = (btc_spp_args_t *)msg->arg;
switch (msg->act) {
case BTC_SPP_ACT_START_DISCOVERY:
if (arg->start_discovery.p_uuid_list) {
osi_free(arg->start_discovery.p_uuid_list);
}{...}
break;...
default:
break;...
}{...}
}{...}
void btc_spp_call_handler(btc_msg_t *msg)
{
btc_spp_args_t *arg = (btc_spp_args_t *)(msg->arg);
switch (msg->act) {
case BTC_SPP_ACT_INIT:
btc_spp_init(arg);
break;...
case BTC_SPP_ACT_UNINIT:
btc_spp_uninit();
break;...
case BTC_SPP_ACT_START_DISCOVERY:
btc_spp_start_discovery(arg);
break;...
case BTC_SPP_ACT_CONNECT:
btc_spp_connect(arg);
break;...
case BTC_SPP_ACT_DISCONNECT:
btc_spp_disconnect(arg);
break;...
case BTC_SPP_ACT_START_SRV:
btc_spp_start_srv(arg);
break;...
case BTC_SPP_ACT_STOP_SRV:
btc_spp_stop_srv(arg);
break;...
case BTC_SPP_ACT_WRITE:
btc_spp_write(arg);
break;...
case BTC_SPP_ACT_VFS_REGISTER:
btc_spp_vfs_register();
break;...
case BTC_SPP_ACT_VFS_UNREGISTER:
btc_spp_vfs_unregister();
break;...
default:
BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act);
break;...
}{...}
btc_spp_arg_deep_free(msg);
}{...}
void btc_spp_cb_handler(btc_msg_t *msg)
{
esp_spp_cb_param_t param;
tBTA_JV *p_data = (tBTA_JV *)msg->arg;
spp_slot_t *slot = NULL;
uint8_t serial = 0;
uint8_t event = msg->act;
switch (event) {
case BTA_JV_ENABLE_EVT:
param.init.status = p_data->status;
btc_spp_cb_to_app(ESP_SPP_INIT_EVT, ¶m);
break;...
case BTA_JV_DISCOVERY_COMP_EVT:
param.disc_comp.status = p_data->disc_comp.status;
param.disc_comp.scn_num = p_data->disc_comp.scn_num;
memcpy(param.disc_comp.scn, p_data->disc_comp.scn, p_data->disc_comp.scn_num);
memcpy(param.disc_comp.service_name, p_data->disc_comp.service_name,
p_data->disc_comp.scn_num * sizeof(const char *));
btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m);
break;...
case BTA_JV_RFCOMM_CL_INIT_EVT:
param.cl_init.status = p_data->rfc_cl_init.status;
param.cl_init.handle = p_data->rfc_cl_init.handle;
param.cl_init.sec_id = p_data->rfc_cl_init.sec_id;
param.cl_init.use_co = p_data->rfc_cl_init.use_co;
btc_spp_cb_to_app(ESP_SPP_CL_INIT_EVT, ¶m);
break;...
case BTA_JV_RFCOMM_OPEN_EVT:
do {
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_open.handle);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
param.open.status = ESP_SPP_NO_CONNECTION;
break;
}{...}
param.open.fd = slot->fd;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} else {
param.open.fd = -1;
}{...}
param.open.status = p_data->rfc_open.status;
}{...} while (0);
param.open.handle = p_data->rfc_open.handle;
memcpy(param.open.rem_bda, p_data->rfc_open.rem_bda, ESP_BD_ADDR_LEN);
btc_spp_cb_to_app(ESP_SPP_OPEN_EVT, ¶m);
break;...
case BTA_JV_RFCOMM_START_EVT:
param.start.status = p_data->rfc_start.status;
param.start.handle = p_data->rfc_start.handle;
param.start.sec_id = p_data->rfc_start.sec_id;
param.start.scn = p_data->rfc_start.scn;
param.start.use_co = p_data->rfc_start.use_co;
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
break;...
case BTA_JV_RFCOMM_SRV_OPEN_EVT:
if (p_data->rfc_srv_open.handle) {
do {
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_srv_open.handle);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
param.srv_open.status = ESP_SPP_NO_CONNECTION;
break;
}{...}
param.srv_open.fd = slot->fd;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} else {
param.srv_open.fd = -1;
}{...}
param.srv_open.status = p_data->rfc_srv_open.status;
}{...} while (0);
param.srv_open.handle = p_data->rfc_srv_open.handle;
param.srv_open.new_listen_handle = p_data->rfc_srv_open.new_listen_handle;
memcpy(param.srv_open.rem_bda, p_data->rfc_srv_open.rem_bda, ESP_BD_ADDR_LEN);
btc_spp_cb_to_app(ESP_SPP_SRV_OPEN_EVT, ¶m);
}{...}
break;...
case BTA_JV_RFCOMM_WRITE_EVT:
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_write.handle);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!, handle:%d", __func__, p_data->rfc_write.handle);
}{...}
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB){
param.write.status = slot ? p_data->rfc_write.status : ESP_SPP_NO_CONNECTION;
param.write.handle = p_data->rfc_write.handle;
param.write.len = p_data->rfc_write.len;
param.write.cong = p_data->rfc_write.cong;
btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m);
if (slot) {
osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
}{...}
}{...} else {
if (slot) {
size_t item_size = 0;
size_t items_waiting = 0;
serial = slot->serial;
if (p_data->rfc_write.status == BTA_JV_SUCCESS) {
vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
slot->write_data = NULL;
slot->is_writing = false;
slot->write_data_len = 0;
vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting);
if (spp_local_param.tx_buffer_size > items_waiting) {
xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
}{...}
if (items_waiting == 0) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;
}{...}
if (!p_data->rfc_write.cong) {
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
if (item_size > 0) {
slot->write_data = data;
slot->write_data_len = item_size;
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, item_size, data);
}{...}
}{...}
}{...} else {
if (!p_data->rfc_write.old_cong) {
BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", slot->write_data,
p_data->rfc_write.handle);
}{...} else {
if (!p_data->rfc_write.cong && slot->connected) {
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, slot->write_data_len, slot->write_data);
}{...} else {
slot->is_writing = false;
}{...}
}{...}
}{...}
}{...}
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;...
case BTA_JV_RFCOMM_CLOSE_EVT:
param.close.status = BTA_JV_SUCCESS;
param.close.port_status = p_data->rfc_close.port_status;
param.close.handle = p_data->rfc_close.handle;
param.close.async = p_data->rfc_close.async;
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_close.handle);
if (!slot) {
param.close.status = ESP_SPP_NO_CONNECTION;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
spp_free_slot(slot);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
}{...} else {
bool need_call = true;
do {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_close.handle);
if (!slot) {
param.close.status = ESP_SPP_NO_CONNECTION;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
if (slot->close_alarm == NULL && slot->rx.queue && fixed_queue_length(slot->rx.queue) > 0) {
tBTA_JV *p_arg = NULL;
if ((p_arg = osi_malloc(sizeof(tBTA_JV))) == NULL) {
param.close.status = ESP_SPP_NO_RESOURCE;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to malloc slot close_alarm arg!", __func__);
break;
}{...}
memcpy(p_arg, p_data, sizeof(tBTA_JV));
slot->alarm_arg = (void *)p_arg;
if ((slot->close_alarm =
osi_alarm_new("slot", close_timeout_handler, (void *)slot, VFS_CLOSE_TIMEOUT)) == NULL) {
osi_free(p_arg);
slot->alarm_arg = NULL;
param.close.status = ESP_SPP_NO_RESOURCE;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to malloc slot close_alarm!", __func__);
break;
}{...}
if (osi_alarm_set(slot->close_alarm, VFS_CLOSE_TIMEOUT) != OSI_ALARM_ERR_PASS) {
osi_free(p_arg);
slot->alarm_arg = NULL;
osi_alarm_free(slot->close_alarm);
param.close.status = ESP_SPP_BUSY;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s set slot close_alarm failed!", __func__);
break;
}{...}
BTC_TRACE_WARNING("%s slot rx data will be discard in %d milliseconds!",
__func__, VFS_CLOSE_TIMEOUT);
slot->connected = false;
need_call = false;
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...} while (0);
if (need_call) {
btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_free_slot(slot);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...}
}{...}
break;...
case BTA_JV_RFCOMM_CONG_EVT:
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
param.cong.status = p_data->rfc_cong.status;
param.cong.handle = p_data->rfc_cong.handle;
param.cong.cong = p_data->rfc_cong.cong;
btc_spp_cb_to_app(ESP_SPP_CONG_EVT, ¶m);
}{...} else {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_cong.handle);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
if (!p_data->rfc_cong.cong && !slot->is_writing) {
if (slot->write_data == NULL && slot->write_data_len == 0) {
size_t item_size = 0;
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, slot->mtu);
if (item_size > 0) {
slot->write_data = data;
slot->write_data_len = item_size;
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, item_size, data);
}{...}
}{...} else {
slot->is_writing = true;
BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, slot->write_data_len, slot->write_data);
}{...}
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...}
break;...
case BTA_JV_RFCOMM_DATA_IND_EVT:
do {
BT_HDR *p_buf;
UINT16 count = 0;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->data_ind.handle);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
serial = slot->serial;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
while (1) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
if ((slot = spp_local_param.spp_slots[serial]) != NULL &&
slot->rfc_handle == p_data->data_ind.handle &&
fixed_queue_length(slot->rx.queue) > 0) {
p_buf = (BT_HDR *)fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT);
}{...} else {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
if (p_buf) {
count += 1;
param.data_ind.status = ESP_SPP_SUCCESS;
param.data_ind.handle = p_data->data_ind.handle;
param.data_ind.len = p_buf->len;
param.data_ind.data = p_buf->data + p_buf->offset;
btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, ¶m);
BTC_TRACE_DEBUG("data cb to app: len %d\n", p_buf->len);
osi_free(p_buf);
}{...}
}{...}
if (count != 0) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot->credit_rx += count;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTA_JvRfcommFlowControl(p_data->data_ind.handle, count);
BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
}{...}
}{...} while (0);
break;...
case BTA_JV_FREE_SCN_EVT:
if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) {
param.srv_stop.status = p_data->free_scn.status;
param.srv_stop.scn = p_data->free_scn.scn;
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
}{...}
break;...
case BTA_JV_DISABLE_EVT:
param.uninit.status = ESP_SPP_SUCCESS;
spp_free_pending_slots();
BTA_JvFree();
osi_mutex_free(&spp_local_param.spp_slot_mutex);
if (spp_local_param.tx_event_group) {
vEventGroupDelete(spp_local_param.tx_event_group);
spp_local_param.tx_event_group = NULL;
}{...}
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
if (spp_local_param.spp_vfs_id != -1) {
esp_vfs_unregister_with_id(spp_local_param.spp_vfs_id);
spp_local_param.spp_vfs_id = -1;
}{...}
}{...}
#if SPP_DYNAMIC_MEMORY == TRUE
osi_free(spp_local_param_ptr);
spp_local_param_ptr = NULL;/* ... */
#endif
btc_spp_cb_to_app(ESP_SPP_UNINIT_EVT, ¶m);
break;...
default:
BTC_TRACE_DEBUG("%s: Unhandled event (%d)!", __FUNCTION__, msg->act);
break;...
}{...}
}{...}
int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
{
int ret = 1;
bt_status_t status;
tBTA_JV p_data;
btc_msg_t msg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_SPP;
msg.act = BTA_JV_RFCOMM_DATA_IND_EVT;
uint32_t id = (uintptr_t)user_data;
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
return -1;
}{...}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_id(id);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
return -1;
}{...}
p_data.data_ind.handle = slot->rfc_handle;
p_data.data_ind.p_buf = NULL;
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
size_t rx_len = fixed_queue_length(slot->rx.queue);
fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
if (rx_len == 0) {
BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, rx_len);
status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_JV), NULL, NULL);
assert(status == BT_STATUS_SUCCESS);
}{...}
}{...} else {
fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
}{...}
if (--slot->credit_rx == 0) {
BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
ret = 0;
}{...}
if (slot->credit_rx > BTA_JV_MAX_CREDIT_NUM) {
BTC_TRACE_WARNING("%s credit %d", __func__, slot->credit_rx);
assert(0);
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return ret;
}{...}
int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
{
return 1;
}{...}
int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
{
return 1;
}{...}
esp_err_t spp_send_data_to_btc(uint32_t handle, int len, uint8_t *p_data, esp_spp_mode_t spp_mode)
{
btc_msg_t msg;
btc_spp_args_t arg;
if (spp_local_param.spp_mode != spp_mode) {
BTC_TRACE_WARNING("The current mode used is %d\n", spp_local_param.spp_mode);
return ESP_ERR_NOT_SUPPORTED;
}{...}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_SPP;
msg.act = BTC_SPP_ACT_WRITE;
arg.write.handle = handle;
arg.write.len = len;
arg.write.p_data = p_data;
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), btc_spp_arg_deep_copy,
btc_spp_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}{...}
static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
{
assert(data != NULL);
errno = 0;
if (size == 0) {
return 0;
}{...}
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
errno = ESRCH;
return -1;
}{...}
spp_slot_t *slot = NULL;
uint8_t serial = 0;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_fd(fd);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
errno = ENOENT;
return -1;
}{...}
serial = slot->serial;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
ssize_t sent = 0;
size_t items_waiting = 0;
size_t item_size = 0;
EventBits_t tx_event_group_val = 0;
BaseType_t done = false;
while (size) {
tx_event_group_val = 0;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_local_param.spp_slots[serial];
if (slot && slot->connected) {
items_waiting = 0;
item_size = 0;
vRingbufferGetInfo(slot->ringbuf_write, NULL, NULL, NULL, NULL, &items_waiting);
if (items_waiting < spp_local_param.tx_buffer_size) {
if ((spp_local_param.tx_buffer_size - items_waiting) > size) {
item_size = size;
done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0);
}{...} else {
item_size = spp_local_param.tx_buffer_size - items_waiting;
done = xRingbufferSend(slot->ringbuf_write, (void *)data + sent, item_size, 0);
}{...}
if (done) {
sent += item_size;
size -= item_size;
if (slot->write_data == NULL) {
spp_send_data_to_btc(slot->rfc_handle, 0, NULL, ESP_SPP_MODE_VFS);
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
continue;
}{...}
}{...}
BTC_TRACE_DEBUG("%s items_waiting:%d, fd:%d\n", __func__, items_waiting, fd);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
tx_event_group_val =
xEventGroupWaitBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
BTC_TRACE_ERROR("%s exit for RFCOMM close, fd:%d!", __func__, fd);
errno = EPIPE;
sent = -1;
break;
}{...} else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
continue;
}{...} else if (tx_event_group_val == 0) {
BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
errno = EBUSY;
sent = -1;
break;
}{...}
}{...} else {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
errno = EPIPE;
sent = -1;
break;
}{...}
}{...}
return sent;
}{...}
static int spp_vfs_close(int fd)
{
errno = 0;
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
errno = ESRCH;
return -1;
}{...}
spp_slot_t *slot = NULL;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_fd(fd);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
errno = ENOENT;
return -1;
}{...}
esp_spp_disconnect(slot->rfc_handle);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return 0;
}{...}
static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
{
assert(dst != NULL);
errno = 0;
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
errno = ESRCH;
return -1;
}{...}
spp_slot_t *slot = NULL;
uint8_t serial = 0;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_fd(fd);
if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
errno = ENOENT;
return -1;
}{...}
serial = slot->serial;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
ssize_t item_size = 0;
uint16_t count = 0;
BT_HDR *p_buf;
while (1) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
if (fixed_queue_length(slot->rx.queue) > 0) {
if ((p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) != NULL && p_buf->len == 0) {
osi_free(fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT));
p_buf = NULL;
count++;
}{...}
if (size == 0 || (p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) == NULL) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;
}{...}
}{...} else {
/* ... */
if (slot->close_alarm && osi_alarm_is_active(slot->close_alarm)) {
osi_alarm_cancel(slot->close_alarm);
osi_alarm_set(slot->close_alarm, 0);
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break;
}{...}
}{...} else {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s peer close, data will be discarded!\n", __func__);
errno = EPIPE;
item_size = -1;
break;
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
if (p_buf->len <= size) {
memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
size -= p_buf->len;
item_size += p_buf->len;
dst += p_buf->len;
p_buf->offset += p_buf->len;
p_buf->len = 0;
}{...} else {
memcpy(dst, p_buf->data + p_buf->offset, size);
item_size += size;
p_buf->offset += size;
p_buf->len -= size;
size = 0;
}{...}
}{...}
if (count > 0) {
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot->credit_rx += count;
if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
BTA_JvRfcommFlowControl(slot->rfc_handle, count);
BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
}{...}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}{...}
return item_size;
}{...}
static void btc_spp_vfs_register(void)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
esp_spp_cb_param_t param;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
esp_vfs_t vfs = {
.flags = ESP_VFS_FLAG_DEFAULT,
.write = spp_vfs_write,
.open = NULL,
.fstat = NULL,
.close = spp_vfs_close,
.read = spp_vfs_read,
.fcntl = NULL
}{...};
if (esp_vfs_register_with_id(&vfs, NULL, &spp_local_param.spp_vfs_id) != ESP_OK) {
ret = ESP_SPP_FAILURE;
break;
}{...}
}{...} while (0);
param.vfs_register.status = ret;
btc_spp_cb_to_app(ESP_SPP_VFS_REGISTER_EVT, ¶m);
}{...}
static void btc_spp_vfs_unregister(void)
{
esp_spp_status_t ret = ESP_SPP_SUCCESS;
esp_spp_cb_param_t param;
do {
if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
ret = ESP_SPP_NEED_INIT;
break;
}{...}
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
if (spp_local_param.spp_vfs_id != -1) {
if (esp_vfs_unregister_with_id(spp_local_param.spp_vfs_id) != ESP_OK) {
ret = ESP_SPP_FAILURE;
break;
}{...}
spp_local_param.spp_vfs_id = -1;
}{...}
}{...}
}{...} while (0);
param.vfs_unregister.status = ret;
btc_spp_cb_to_app(ESP_SPP_VFS_UNREGISTER_EVT, ¶m);
}{...}
/* ... */
#endif