replace list and ringbuffer with fixed queue

use eventgroup to sync spp_vfs_write

each connection has a switch_delay_timer not sharing a one

revert functions like spp_find_slot_by_xxx

fix vfs read bug when peer close
This commit is contained in:
liqigan 2020-08-24 09:52:36 +08:00
parent 2765d5b829
commit 023f44e348
10 changed files with 434 additions and 151 deletions

View File

@ -409,3 +409,8 @@ bool btc_check_queue_is_congest(void)
return false; return false;
} }
int get_btc_work_queue_size(void)
{
return osi_thread_queue_wait_size(btc_thread, 0);
}

View File

@ -116,5 +116,6 @@ bt_status_t btc_inter_profile_call(btc_msg_t *msg, void *arg);
bt_status_t btc_init(void); bt_status_t btc_init(void);
void btc_deinit(void); void btc_deinit(void);
bool btc_check_queue_is_congest(void); bool btc_check_queue_is_congest(void);
int get_btc_work_queue_size(void);
#endif /* __BTC_TASK_H__ */ #endif /* __BTC_TASK_H__ */

View File

@ -27,9 +27,9 @@ typedef enum {
ESP_SPP_FAILURE, /*!< Generic failure. */ ESP_SPP_FAILURE, /*!< Generic failure. */
ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */ ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */
ESP_SPP_NO_DATA, /*!< no data. */ ESP_SPP_NO_DATA, /*!< no data. */
ESP_SPP_NO_RESOURCE, /*!< No more set pm control block */ ESP_SPP_NO_RESOURCE, /*!< No more resource */
ESP_SPP_NEED_INIT, /*!< SPP module shall init first */ ESP_SPP_NEED_INIT, /*!< SPP module shall init first */
ESP_SPP_NEED_UNINIT, /*!< SPP module shall uninit first */ ESP_SPP_NEED_DEINIT, /*!< SPP module shall deinit first */
ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */ ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */
} esp_spp_status_t; } esp_spp_status_t;

View File

@ -3759,9 +3759,9 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
HCI_ROLE_MASTER, NULL); HCI_ROLE_MASTER, NULL);
} else { } else {
bta_dm_cb.switch_delay_timer.p_cback = bta_dm_cb.switch_delay_timer[i].p_cback =
(TIMER_CBACK *)&bta_dm_delay_role_switch_cback; (TIMER_CBACK *)&bta_dm_delay_role_switch_cback;
bta_sys_start_timer(&bta_dm_cb.switch_delay_timer, 0, 500); bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
} }
} }

View File

@ -1067,7 +1067,7 @@ typedef struct {
tBTA_DM_ENCRYPT_CBACK *p_encrypt_cback; tBTA_DM_ENCRYPT_CBACK *p_encrypt_cback;
TIMER_LIST_ENT switch_delay_timer; TIMER_LIST_ENT switch_delay_timer[BTA_DM_NUM_PEER_DEVICE];
} tBTA_DM_CB; } tBTA_DM_CB;

View File

@ -297,7 +297,6 @@ typedef struct {
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
UINT32 port_status; /* PORT status */ UINT32 port_status; /* PORT status */
UINT32 handle; /* The connection handle */ UINT32 handle; /* The connection handle */
void *slot; /* slot pointer */
BOOLEAN async; /* FALSE, if local initiates disconnect */ BOOLEAN async; /* FALSE, if local initiates disconnect */
} tBTA_JV_RFCOMM_CLOSE; } tBTA_JV_RFCOMM_CLOSE;
@ -347,6 +346,7 @@ typedef struct {
UINT32 req_id; /* The req_id in the associated BTA_JvRfcommWrite() */ UINT32 req_id; /* The req_id in the associated BTA_JvRfcommWrite() */
int len; /* The length of the data written. */ int len; /* The length of the data written. */
BOOLEAN cong; /* congestion status */ BOOLEAN cong; /* congestion status */
BOOLEAN old_cong; /* congestion status */
} tBTA_JV_RFCOMM_WRITE; } tBTA_JV_RFCOMM_WRITE;
/* data associated with BTA_JV_API_SET_PM_PROFILE_EVT */ /* data associated with BTA_JV_API_SET_PM_PROFILE_EVT */

View File

@ -1688,7 +1688,6 @@ static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle)
evt_data.rfc_close.status = BTA_JV_FAILURE; evt_data.rfc_close.status = BTA_JV_FAILURE;
evt_data.rfc_close.port_status = code; evt_data.rfc_close.port_status = code;
evt_data.rfc_close.async = TRUE; evt_data.rfc_close.async = TRUE;
evt_data.rfc_close.slot = NULL;
if (p_pcb->state == BTA_JV_ST_CL_CLOSING) { if (p_pcb->state == BTA_JV_ST_CL_CLOSING) {
evt_data.rfc_close.async = FALSE; evt_data.rfc_close.async = FALSE;
evt_data.rfc_close.status = BTA_JV_SUCCESS; evt_data.rfc_close.status = BTA_JV_SUCCESS;
@ -1872,7 +1871,6 @@ void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data)
evt_data.rfc_close.port_status = PORT_LOCAL_CLOSED; evt_data.rfc_close.port_status = PORT_LOCAL_CLOSED;
evt_data.rfc_close.handle = cc->handle; evt_data.rfc_close.handle = cc->handle;
evt_data.rfc_close.async = TRUE; evt_data.rfc_close.async = TRUE;
evt_data.rfc_close.slot = NULL;
if (p_pcb && (p_pcb->state == BTA_JV_ST_SR_LISTEN || if (p_pcb && (p_pcb->state == BTA_JV_ST_SR_LISTEN ||
p_pcb->state == BTA_JV_ST_SR_OPEN || p_pcb->state == BTA_JV_ST_SR_OPEN ||
p_pcb->state == BTA_JV_ST_CL_OPEN || p_pcb->state == BTA_JV_ST_CL_OPEN ||
@ -1962,7 +1960,6 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
evt_data.rfc_close.status = BTA_JV_FAILURE; evt_data.rfc_close.status = BTA_JV_FAILURE;
evt_data.rfc_close.async = TRUE; evt_data.rfc_close.async = TRUE;
evt_data.rfc_close.port_status = code; evt_data.rfc_close.port_status = code;
evt_data.rfc_close.slot = NULL;
p_pcb->cong = FALSE; p_pcb->cong = FALSE;
tBTA_JV_RFCOMM_CBACK *p_cback = p_cb->p_cback; tBTA_JV_RFCOMM_CBACK *p_cback = p_cb->p_cback;
@ -2260,16 +2257,16 @@ void bta_jv_rfcomm_write(tBTA_JV_MSG *p_data)
evt_data.status = BTA_JV_FAILURE; evt_data.status = BTA_JV_FAILURE;
evt_data.handle = p_pcb->handle; evt_data.handle = p_pcb->handle;
evt_data.req_id = wc->req_id; evt_data.req_id = wc->req_id;
evt_data.cong = p_pcb->cong; evt_data.old_cong = p_pcb->cong;
bta_jv_pm_conn_busy(p_pcb->p_pm_cb); bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
evt_data.len = wc->len; evt_data.len = -1;
if (!evt_data.cong && if (!evt_data.old_cong &&
PORT_WriteDataCO(p_pcb->port_handle, &evt_data.len, wc->len, wc->p_data) == PORT_WriteDataCO(p_pcb->port_handle, &evt_data.len, wc->len, wc->p_data) ==
PORT_SUCCESS) { PORT_SUCCESS) {
evt_data.status = BTA_JV_SUCCESS; evt_data.status = BTA_JV_SUCCESS;
} }
// update congestion flag // update congestion flag
evt_data.cong = p_pcb->cong; evt_data.cong = p_pcb->cong;
if (p_cb->p_cback) { if (p_cb->p_cback) {
p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data); p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data);
} else { } else {

View File

@ -24,22 +24,41 @@
#include "osi/list.h" #include "osi/list.h"
#include "freertos/ringbuf.h" #include "freertos/ringbuf.h"
#include "osi/mutex.h" #include "osi/mutex.h"
#include "osi/alarm.h"
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
#include "esp_vfs.h" #include "esp_vfs.h"
#include "esp_vfs_dev.h" #include "esp_vfs_dev.h"
#include "stack/port_api.h" #include "stack/port_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "btc/btc_task.h"
#include "stack/btu.h"
#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE) #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)
typedef struct {
bool peer_fc; /* true if flow control is set based on peer's request */
bool user_fc; /* true if flow control is set based on user's request */
fixed_queue_t *queue; /* Queue of buffers waiting to be sent */
uint32_t data_size; /* Number of data bytes in the queue */
} slot_data_t;
typedef struct { typedef struct {
uint8_t serial; uint8_t serial;
bool connected; bool connected;
uint8_t scn; uint8_t scn;
uint8_t max_session; uint8_t max_session;
RingbufHandle_t ringbuf_read;
RingbufHandle_t ringbuf_write;
uint32_t id; uint32_t id;
uint32_t mtu;//unused uint32_t mtu;//unused
uint32_t sdp_handle; uint32_t sdp_handle;
@ -47,11 +66,12 @@ typedef struct {
uint32_t rfc_port_handle; uint32_t rfc_port_handle;
int fd; int fd;
uint8_t *write_data; uint8_t *write_data;
osi_alarm_t *close_alarm;
esp_spp_role_t role; esp_spp_role_t role;
esp_spp_sec_t security; esp_spp_sec_t security;
esp_bd_addr_t addr; esp_bd_addr_t addr;
list_t *list; slot_data_t rx;
list_t *incoming_list; slot_data_t tx;
uint8_t service_uuid[16]; uint8_t service_uuid[16];
char service_name[ESP_SPP_SERVER_NAME_MAX + 1]; char service_name[ESP_SPP_SERVER_NAME_MAX + 1];
} spp_slot_t; } spp_slot_t;
@ -61,6 +81,7 @@ typedef struct {
uint32_t spp_slot_id; uint32_t spp_slot_id;
esp_spp_mode_t spp_mode; esp_spp_mode_t spp_mode;
osi_mutex_t spp_slot_mutex; osi_mutex_t spp_slot_mutex;
EventGroupHandle_t tx_event_group;
esp_vfs_id_t spp_vfs_id; esp_vfs_id_t spp_vfs_id;
} spp_local_param_t; } spp_local_param_t;
@ -82,38 +103,76 @@ static void spp_osi_free(void *p)
#define is_spp_init() (&spp_local_param != NULL && spp_local_param.spp_slot_mutex != NULL) #define is_spp_init() (&spp_local_param != NULL && spp_local_param.spp_slot_mutex != NULL)
#endif #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;
}
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) 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) { if (++spp_local_param.spp_slot_id == 0) {
spp_local_param.spp_slot_id = 1; spp_local_param.spp_slot_id = 1;
} }
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) { for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
if (spp_local_param.spp_slots[i] == NULL) { slot = &spp_local_param.spp_slots[i];
spp_local_param.spp_slots[i] = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t)); if ((*slot) == NULL) {
if (!spp_local_param.spp_slots[i]) { if (((*slot) = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t))) == NULL) {
return NULL; return NULL;
} }
spp_local_param.spp_slots[i]->id = spp_local_param.spp_slot_id; (*slot)->id = spp_local_param.spp_slot_id;
spp_local_param.spp_slots[i]->serial = i; (*slot)->serial = i;
spp_local_param.spp_slots[i]->sdp_handle = 0; (*slot)->sdp_handle = 0;
spp_local_param.spp_slots[i]->rfc_handle = 0; (*slot)->rfc_handle = 0;
spp_local_param.spp_slots[i]->rfc_port_handle = 0; (*slot)->rfc_port_handle = 0;
spp_local_param.spp_slots[i]->connected = FALSE; (*slot)->connected = FALSE;
spp_local_param.spp_slots[i]->write_data = NULL; (*slot)->write_data = NULL;
spp_local_param.spp_slots[i]->list = list_new(spp_osi_free); (*slot)->close_alarm = NULL;
spp_local_param.spp_slots[i]->incoming_list = list_new(spp_osi_free); if (init_slot_data(&(*slot)->rx, QUEUE_SIZE_MAX)) {
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { BTC_TRACE_ERROR("%s unable to malloc rx queue!", __func__);
if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &spp_local_param.spp_slots[i]->fd) != ESP_OK) { err_no = 1;
osi_free(spp_local_param.spp_slots[i]); break;
return NULL;
}
spp_local_param.spp_slots[i]->ringbuf_read = xRingbufferCreate(ESP_SPP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
spp_local_param.spp_slots[i]->ringbuf_write = xRingbufferCreate(ESP_SPP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
} }
return spp_local_param.spp_slots[i]; if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
err_no = 2;
break;
}
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
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;
break;
}
}
return (*slot);
} }
} }
return NULL; switch (err_no) {
case 3:
free_slot_data(&(*slot)->tx);
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) static spp_slot_t *spp_find_slot_by_id(uint32_t id)
@ -156,19 +215,41 @@ static spp_slot_t *spp_find_slot_by_scn(uint32_t scn)
return NULL; return NULL;
} }
static void close_timeout_handler(void *arg)
{
btc_msg_t msg;
bt_status_t status;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_SPP;
msg.act = BTA_JV_RFCOMM_CLOSE_EVT;
status = btc_transfer_context(&msg, arg, sizeof(tBTA_JV), NULL);
if (arg) {
free(arg);
}
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
}
}
static void spp_free_slot(spp_slot_t *slot) static void spp_free_slot(spp_slot_t *slot)
{ {
if (!slot) { if (!slot) {
return; return;
} }
spp_local_param.spp_slots[slot->serial] = NULL; spp_local_param.spp_slots[slot->serial] = NULL;
list_free(slot->list);
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
(void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd); (void) esp_vfs_unregister_fd(spp_local_param.spp_vfs_id, slot->fd);
vRingbufferDelete(slot->ringbuf_read); xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
vRingbufferDelete(slot->ringbuf_write); }
free_slot_data(&slot->tx);
free_slot_data(&slot->rx);
if (slot->close_alarm) {
osi_alarm_free(slot->close_alarm);
} }
list_free(slot->incoming_list);
osi_free(slot); osi_free(slot);
} }
@ -194,8 +275,8 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
void *new_user_data = NULL; void *new_user_data = NULL;
uint32_t id = (uintptr_t)user_data; uint32_t id = (uintptr_t)user_data;
spp_slot_t *slot, *slot_new; spp_slot_t *slot = NULL, *slot_new = NULL;
if (!spp_local_param.spp_slot_mutex) { if (!is_spp_init()) {
BTC_TRACE_WARNING("%s SPP have been deinit, incoming events ignore!\n", __func__); BTC_TRACE_WARNING("%s SPP have been deinit, incoming events ignore!\n", __func__);
return new_user_data; return new_user_data;
} }
@ -268,7 +349,6 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
if (slot->connected && p_data->rfc_close.port_status != PORT_LOCAL_CLOSED) { if (slot->connected && p_data->rfc_close.port_status != PORT_LOCAL_CLOSED) {
BTA_JvRfcommClose(slot->rfc_handle, NULL, (void *)slot->id); BTA_JvRfcommClose(slot->rfc_handle, NULL, (void *)slot->id);
} }
p_data->rfc_close.slot = slot;
p_data->rfc_close.status = BTA_JV_SUCCESS; p_data->rfc_close.status = BTA_JV_SUCCESS;
break; break;
case BTA_JV_RFCOMM_DATA_IND_EVT: case BTA_JV_RFCOMM_DATA_IND_EVT:
@ -310,21 +390,21 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
btc_msg_t msg; btc_msg_t msg;
uint32_t id = (uintptr_t)user_data; uint32_t id = (uintptr_t)user_data;
spp_slot_t *slot; spp_slot_t *slot = NULL;
switch (event) { switch (event) {
case BTA_JV_GET_SCN_EVT: case BTA_JV_GET_SCN_EVT:
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_id(id); slot = spp_find_slot_by_id(id);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
break; break;
} }
if (p_data->scn == 0) { if (p_data->scn == 0) {
BTC_TRACE_ERROR("%s unable to get scn, start server fail!", __func__);
btc_create_server_fail_cb(); btc_create_server_fail_cb();
spp_free_slot(slot); spp_free_slot(slot);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to get scn, start server fail!", __func__);
break; break;
} }
@ -336,8 +416,8 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_id(id); slot = spp_find_slot_by_id(id);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
break; break;
} }
if (p_data->create_rec.status == BTA_JV_SUCCESS) { if (p_data->create_rec.status == BTA_JV_SUCCESS) {
@ -379,7 +459,7 @@ static void btc_spp_init(btc_spp_args_t *arg)
do { do {
if (is_spp_init()) { if (is_spp_init()) {
BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__); BTC_TRACE_ERROR("%s SPP has been initiated, shall uninit first!", __func__);
ret = ESP_SPP_NEED_UNINIT; ret = ESP_SPP_NEED_DEINIT;
break; break;
} }
@ -397,6 +477,11 @@ static void btc_spp_init(btc_spp_args_t *arg)
ret = ESP_SPP_NO_RESOURCE; ret = ESP_SPP_NO_RESOURCE;
break; break;
} }
if ((spp_local_param.tx_event_group = xEventGroupCreate()) == NULL) {
BTC_TRACE_ERROR("%s create tx_event_group failed\n", __func__);
ret = ESP_SPP_NO_RESOURCE;
break;
}
spp_local_param.spp_mode = arg->init.mode; spp_local_param.spp_mode = arg->init.mode;
spp_local_param.spp_slot_id = 0; spp_local_param.spp_slot_id = 0;
BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb); BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
@ -530,11 +615,16 @@ static void btc_spp_disconnect(btc_spp_args_t *arg)
ret = ESP_SPP_NEED_INIT; ret = ESP_SPP_NEED_INIT;
break; break;
} }
spp_slot_t *slot = NULL;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_handle(arg->disconnect.handle); slot = spp_find_slot_by_handle(arg->disconnect.handle);
if (!slot) { if (!slot || (slot && !slot->connected)) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); 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; ret = ESP_SPP_NO_CONNECTION;
break; break;
} }
@ -652,28 +742,33 @@ static void btc_spp_write(btc_spp_args_t *arg)
ret = ESP_SPP_NEED_INIT; ret = ESP_SPP_NEED_INIT;
break; break;
} }
spp_slot_t *slot = NULL;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_handle(arg->write.handle); slot = spp_find_slot_by_handle(arg->write.handle);
if (!slot) { if (!slot || (slot && !slot->connected)) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); 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; ret = ESP_SPP_NO_CONNECTION;
break; break;
} }
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
size_t item_size = 0; BT_HDR *p_buf;
if (slot->write_data != NULL) { if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); p_buf->event++;
return; p_buf->layer_specific = 1;
} BTA_JvRfcommWrite(arg->write.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, BTA_JV_DEF_RFC_MTU);
if (item_size != 0) {
slot->write_data = data;
BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data);
} }
} else { } else {
list_append(slot->list, arg->write.p_data); 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); BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
} else {
ret = ESP_SPP_NO_RESOURCE;
break;
}
} }
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
} while (0); } while (0);
@ -774,7 +869,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
{ {
esp_spp_cb_param_t param; esp_spp_cb_param_t param;
tBTA_JV *p_data = (tBTA_JV *)msg->arg; tBTA_JV *p_data = (tBTA_JV *)msg->arg;
spp_slot_t *slot; spp_slot_t *slot = NULL;
uint8_t serial = 0;
switch (msg->act) { switch (msg->act) {
case BTA_JV_ENABLE_EVT: case BTA_JV_ENABLE_EVT:
param.init.status = p_data->status; param.init.status = p_data->status;
@ -799,8 +895,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_open.handle); slot = spp_find_slot_by_handle(p_data->rfc_open.handle);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
param.open.status = ESP_SPP_NO_CONNECTION; param.open.status = ESP_SPP_NO_CONNECTION;
break; break;
} }
@ -827,8 +923,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); 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); slot = spp_find_slot_by_handle(p_data->rfc_srv_open.handle);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
param.srv_open.status = ESP_SPP_NO_CONNECTION; param.srv_open.status = ESP_SPP_NO_CONNECTION;
break; break;
} }
@ -844,10 +940,10 @@ void btc_spp_cb_handler(btc_msg_t *msg)
} }
break; break;
case BTA_JV_RFCOMM_WRITE_EVT: case BTA_JV_RFCOMM_WRITE_EVT:
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_write.handle); slot = spp_find_slot_by_handle(p_data->rfc_write.handle);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); 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){ 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.status = slot ? p_data->rfc_write.status : ESP_SPP_NO_CONNECTION;
@ -856,28 +952,40 @@ void btc_spp_cb_handler(btc_msg_t *msg)
param.write.cong = p_data->rfc_write.cong; param.write.cong = p_data->rfc_write.cong;
btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, &param); btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, &param);
if (slot) { if (slot) {
list_remove(slot->list, list_front(slot->list)); osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
} }
} else { } else {
if (slot) { if (slot) {
if (p_data->rfc_write.status != BTA_JV_SUCCESS) { BT_HDR *p_buf;
if (slot->write_data != NULL) { serial = slot->serial;
vRingbufferReturnItem(slot->ringbuf_write, slot->write_data); if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) == NULL) {
slot->write_data = NULL;
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break; break;
} }
if (p_data->rfc_write.cong == 0) { if (p_data->rfc_write.status == BTA_JV_SUCCESS) {
if (slot->write_data != NULL) { p_buf->len -= p_data->rfc_write.len;
vRingbufferReturnItem(slot->ringbuf_write, slot->write_data); p_buf->offset += p_data->rfc_write.len;
slot->write_data = NULL; p_buf->layer_specific = 0;
if (p_buf->len == 0) {
osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
if (fixed_queue_length(slot->tx.queue) <= SLOT_TX_QUEUE_LOW_WM) {
xEventGroupSetBits(spp_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
}
} }
size_t item_size = 0;
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, BTA_JV_DEF_RFC_MTU); if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0 &&
if (item_size != 0) { !p_data->rfc_write.cong) {
slot->write_data = data; p_buf->layer_specific = 1;
BTA_JvRfcommWrite(slot->rfc_handle, slot->id, item_size, data); p_buf->event++;
BTA_JvRfcommWrite(p_data->rfc_write.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
}
} else {
if (!p_data->rfc_write.old_cong) {
// PORT_WriteDataCO failed
BTC_TRACE_ERROR("PORT_WriteDataCO failed p_buf:%p, handle:%d\n", p_buf,
p_data->rfc_write.handle);
} else {
// need rewrite
p_buf->layer_specific = 0;
} }
} }
} }
@ -889,8 +997,69 @@ void btc_spp_cb_handler(btc_msg_t *msg)
param.close.port_status = p_data->rfc_close.port_status; param.close.port_status = p_data->rfc_close.port_status;
param.close.handle = p_data->rfc_close.handle; param.close.handle = p_data->rfc_close.handle;
param.close.async = p_data->rfc_close.async; param.close.async = p_data->rfc_close.async;
btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, &param); if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
spp_free_slot((spp_slot_t *)p_data->rfc_close.slot); btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, &param);
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) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
break;
}
spp_free_slot(slot);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
} 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!", __func__);
break;
}
// if rx still has data, delay free slot
if (slot->close_alarm == NULL && slot->rx.queue && fixed_queue_length(slot->rx.queue) > 0) {
tBTA_JV *p_arg = NULL;
if ((p_arg = 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));
if ((slot->close_alarm =
osi_alarm_new("slot", close_timeout_handler, (void *)p_arg, VFS_CLOSE_TIMEOUT)) == NULL) {
free(p_arg);
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) {
free(p_arg);
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 seconds!", __func__,
VFS_CLOSE_TIMEOUT / 1000);
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, &param);
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; break;
case BTA_JV_RFCOMM_CONG_EVT: case BTA_JV_RFCOMM_CONG_EVT:
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) { if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
@ -902,20 +1071,16 @@ void btc_spp_cb_handler(btc_msg_t *msg)
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->rfc_cong.handle); slot = spp_find_slot_by_handle(p_data->rfc_cong.handle);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
break; break;
} }
if (p_data->rfc_cong.cong == 0) { if (!p_data->rfc_cong.cong) {
if (slot->write_data != NULL){ BT_HDR *p_buf;
vRingbufferReturnItem(slot->ringbuf_write,slot->write_data); if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
slot->write_data = NULL; p_buf->event++;
} p_buf->layer_specific = 1;
size_t item_size = 0; BTA_JvRfcommWrite(p_data->rfc_cong.handle, slot->id, p_buf->len, p_buf->data + p_buf->offset);
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0, BTA_JV_DEF_RFC_MTU);
if (item_size != 0){
slot->write_data = data;
BTA_JvRfcommWrite(slot->rfc_handle, slot->id, item_size, data);
} }
} }
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
@ -923,28 +1088,25 @@ void btc_spp_cb_handler(btc_msg_t *msg)
break; break;
case BTA_JV_RFCOMM_DATA_IND_EVT: case BTA_JV_RFCOMM_DATA_IND_EVT:
do { do {
uint8_t serial;
BT_HDR *p_buf; BT_HDR *p_buf;
UINT16 count = 0; UINT16 count = 0;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = spp_find_slot_by_handle(p_data->data_ind.handle); slot = spp_find_slot_by_handle(p_data->data_ind.handle);
if (slot) {
serial = slot->serial;
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
if (!slot) { if (!slot) {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
break; break;
} }
serial = slot->serial;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
while (1) { while (1) {
// get incoming_data from slot incoming list // get incoming_data from slot incoming list
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); 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 && !list_is_empty(slot->incoming_list)) { if ((slot = spp_local_param.spp_slots[serial]) != NULL &&
p_buf = list_front(slot->incoming_list); slot->rfc_handle == p_data->data_ind.handle &&
list_delete(slot->incoming_list, p_buf); fixed_queue_length(slot->rx.queue) > 0) {
p_buf = (BT_HDR *)fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT);
} else { } else {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
break; break;
@ -1010,29 +1172,29 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_id(id); spp_slot_t *slot = spp_find_slot_by_id(id);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
return -1; return -1;
} }
p_data.data_ind.handle = slot->rfc_handle; p_data.data_ind.handle = slot->rfc_handle;
p_data.data_ind.p_buf = NULL; p_data.data_ind.p_buf = NULL;
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) { if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
bool incoming_list_empty = list_is_empty(slot->incoming_list); size_t rx_len = fixed_queue_length(slot->rx.queue);
list_append(slot->incoming_list, p_buf); fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
if (incoming_list_empty) { if (rx_len == 0) {
BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, list_length(slot->incoming_list)); 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); status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_JV), NULL);
assert(status == BT_STATUS_SUCCESS); assert(status == BT_STATUS_SUCCESS);
} else if (list_length(slot->incoming_list) > 2) { } else if (fixed_queue_length(slot->rx.queue) > 2) {
BTC_TRACE_ERROR("%s data post stop! %d %d", __func__, slot->rfc_handle, list_length(slot->incoming_list)); BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
ret = 0; ret = 0; // reserved for other flow control
} }
} else { } else {
list_append(slot->incoming_list, p_buf); fixed_queue_enqueue(slot->rx.queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
if (list_length(slot->incoming_list) > 2) { if (fixed_queue_length(slot->rx.queue) > 2) {
BTC_TRACE_ERROR("%s data post stop! %d %d", __func__, slot->rfc_handle, list_length(slot->incoming_list)); BTC_TRACE_DEBUG("%s data post stop! %d %d", __func__, slot->rfc_handle, fixed_queue_length(slot->rx.queue));
ret = 0; ret = 0; // reserved for other flow control
} }
} }
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
@ -1052,38 +1214,111 @@ int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
static ssize_t spp_vfs_write(int fd, const void * data, size_t size) static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
{ {
if (!is_spp_init()) { assert(data != NULL);
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); if (size == 0) {
return -1;
}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_fd(fd);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return -1;
}
BaseType_t done = xRingbufferSend(slot->ringbuf_write, (void *)data, size, 0);
esp_spp_write(slot->rfc_handle, 0, NULL);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
if (done){
return size;
} else {
return 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, write_size = 0;
size_t tx_len;
BT_HDR *p_buf = NULL;
bool enqueue_status= false;
EventBits_t tx_event_group_val = 0;
while (1) {
tx_event_group_val = 0;
if (size) {
if (p_buf == NULL) {
write_size = size < BTA_JV_DEF_RFC_MTU ? size : BTA_JV_DEF_RFC_MTU;
if ((p_buf = osi_malloc(sizeof(BT_HDR) + write_size)) == NULL) {
BTC_TRACE_ERROR("%s malloc failed!", __func__);
errno = ENOMEM;
sent = -1;
break;
}
p_buf->offset = 0;
p_buf->len = write_size;
p_buf->event = 0; // indicate the p_buf be sent count
p_buf->layer_specific = 0; // indicate the p_buf whether to be sent, 0 - ready to send; 1 - have sent
memcpy((UINT8 *)(p_buf + 1), data + sent, write_size);
}
} else {
break;
}
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
if ((slot = spp_local_param.spp_slots[serial]) != NULL) {
tx_len = fixed_queue_length(slot->tx.queue);
enqueue_status = fixed_queue_enqueue(slot->tx.queue, p_buf, 0);
if (!enqueue_status) {
BTC_TRACE_DEBUG("%s tx_len:%d, fd:%d\n", __func__, fixed_queue_length(slot->tx.queue), fd);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
//block untill under water level, be closed or time out
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;
}
}
if (tx_len == 0) {
esp_spp_write(slot->rfc_handle, 0, NULL);
}
sent += write_size;
size -= write_size;
p_buf = NULL;
} else {
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
errno = EPIPE;
sent = -1;
break;
}
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
}
return sent;
} }
static int spp_vfs_close(int fd) static int spp_vfs_close(int fd)
{ {
if (!is_spp_init()) { if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
errno = ESRCH;
return -1; return -1;
} }
spp_slot_t *slot = NULL;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_fd(fd); slot = spp_find_slot_by_fd(fd);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
errno = ENOENT;
return -1; return -1;
} }
esp_spp_disconnect(slot->rfc_handle); esp_spp_disconnect(slot->rfc_handle);
@ -1093,28 +1328,63 @@ static int spp_vfs_close(int fd)
static ssize_t spp_vfs_read(int fd, void * dst, size_t size) static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
{ {
assert(dst != NULL);
if (!is_spp_init()) { if (!is_spp_init()) {
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__); BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
errno = ESRCH;
return -1; return -1;
} }
spp_slot_t *slot = NULL;
uint8_t serial = 0;
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
spp_slot_t *slot = spp_find_slot_by_fd(fd); slot = spp_find_slot_by_fd(fd);
if (!slot) { if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
osi_mutex_unlock(&spp_local_param.spp_slot_mutex); osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!\n", __func__);
errno = ENOENT;
return -1; return -1;
} }
serial = slot->serial;
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
ssize_t item_size = 0; ssize_t item_size = 0;
uint16_t count = 0; uint16_t count = 0;
while (!list_is_empty(slot->incoming_list) && size > 0) { BT_HDR *p_buf;
BT_HDR *p_buf = list_front(slot->incoming_list); 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) {
// free unused p_buf
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 {
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) { if (p_buf->len <= size) {
memcpy(dst, p_buf->data + p_buf->offset, p_buf->len); memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
size -= p_buf->len; size -= p_buf->len;
item_size += p_buf->len; item_size += p_buf->len;
dst += p_buf->len; dst += p_buf->len;
list_remove(slot->incoming_list, p_buf); p_buf->offset += p_buf->len;
count++; p_buf->len = 0; // indicate the p_buf is unused
} else { } else {
memcpy(dst, p_buf->data + p_buf->offset, size); memcpy(dst, p_buf->data + p_buf->offset, size);
item_size += size; item_size += size;
@ -1124,10 +1394,13 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
} }
} }
if (count > 0) { if (count > 0) {
BTA_JvRfcommFlowControl(slot->rfc_handle, count); osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, 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);
} }
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
return item_size; return item_size;
} }

View File

@ -260,3 +260,8 @@ bool BTU_check_queue_is_congest(void)
return false; return false;
} }
#endif #endif
int get_btu_work_queue_size(void)
{
return osi_thread_queue_wait_size(btu_thread, 0);
}

View File

@ -290,6 +290,8 @@ UINT16 BTU_BleAclPktSize(void);
bool btu_task_post(uint32_t sig, void *param, uint32_t timeout); bool btu_task_post(uint32_t sig, void *param, uint32_t timeout);
int get_btu_work_queue_size(void);
/* /*
#ifdef __cplusplus #ifdef __cplusplus
} }