mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
move flow control to btc layer
defer free slot in btc layer when receive BTA_JV_RFCOMM_CLOSE_EVT
This commit is contained in:
@ -22,6 +22,10 @@ list_t *list_new(list_free_cb callback);
|
|||||||
|
|
||||||
|
|
||||||
list_node_t *list_free_node(list_t *list, list_node_t *node);
|
list_node_t *list_free_node(list_t *list, list_node_t *node);
|
||||||
|
|
||||||
|
// similar with list_free_node, this function doesn't free the node data
|
||||||
|
list_node_t *list_delete_node(list_t *list, list_node_t *node);
|
||||||
|
|
||||||
// Frees the list. This function accepts NULL as an argument, in which case it
|
// Frees the list. This function accepts NULL as an argument, in which case it
|
||||||
// behaves like a no-op.
|
// behaves like a no-op.
|
||||||
void list_free(list_t *list);
|
void list_free(list_t *list);
|
||||||
@ -75,6 +79,9 @@ bool list_append(list_t *list, void *data);
|
|||||||
|
|
||||||
bool list_remove(list_t *list, void *data);
|
bool list_remove(list_t *list, void *data);
|
||||||
|
|
||||||
|
// similar with list_remove, but do not free the node data
|
||||||
|
bool list_delete(list_t *list, void *data);
|
||||||
|
|
||||||
// Removes all elements in the list. Calling this function will return the list to the
|
// Removes all elements in the list. Calling this function will return the list to the
|
||||||
// same state it was in after |list_new|. |list| may not be NULL.
|
// same state it was in after |list_new|. |list| may not be NULL.
|
||||||
void list_clear(list_t *list);
|
void list_clear(list_t *list);
|
||||||
|
@ -186,6 +186,36 @@ bool list_remove(list_t *list, void *data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool list_delete(list_t *list, void *data)
|
||||||
|
{
|
||||||
|
assert(list != NULL);
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (list_is_empty(list)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list->head->data == data) {
|
||||||
|
list_node_t *next = list_delete_node(list, list->head);
|
||||||
|
if (list->tail == list->head) {
|
||||||
|
list->tail = next;
|
||||||
|
}
|
||||||
|
list->head = next;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
|
||||||
|
if (node->data == data) {
|
||||||
|
prev->next = list_delete_node(list, node);
|
||||||
|
if (list->tail == node) {
|
||||||
|
list->tail = prev;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void list_clear(list_t *list)
|
void list_clear(list_t *list)
|
||||||
{
|
{
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
@ -251,3 +281,17 @@ list_node_t *list_free_node(list_t *list, list_node_t *node)
|
|||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove the element from list but do not free the node data
|
||||||
|
list_node_t *list_delete_node(list_t *list, list_node_t *node)
|
||||||
|
{
|
||||||
|
assert(list != NULL);
|
||||||
|
assert(node != NULL);
|
||||||
|
|
||||||
|
list_node_t *next = node->next;
|
||||||
|
|
||||||
|
osi_free(node);
|
||||||
|
--list->length;
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
@ -297,6 +297,7 @@ 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;
|
||||||
|
|
||||||
@ -894,6 +895,18 @@ extern tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size);
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p_data);
|
extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p_data);
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function BTA_JvRfcommFlowControl
|
||||||
|
**
|
||||||
|
** Description This function gives the credit to the peer
|
||||||
|
**
|
||||||
|
** Returns BTA_JV_SUCCESS, if the request is being processed.
|
||||||
|
** BTA_JV_FAILURE, otherwise.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
extern tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given);
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
** Function BTA_JVSetPmProfile
|
** Function BTA_JVSetPmProfile
|
||||||
|
@ -1688,6 +1688,7 @@ 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;
|
||||||
@ -1871,6 +1872,7 @@ 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 ||
|
||||||
@ -1960,6 +1962,7 @@ 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;
|
||||||
@ -2275,6 +2278,23 @@ void bta_jv_rfcomm_write(tBTA_JV_MSG *p_data)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function bta_jv_rfcomm_flow_control
|
||||||
|
**
|
||||||
|
** Description give credits to the peer
|
||||||
|
**
|
||||||
|
** Returns void
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
void bta_jv_rfcomm_flow_control(tBTA_JV_MSG *p_data)
|
||||||
|
{
|
||||||
|
tBTA_JV_API_RFCOMM_FLOW_CONTROL *fc = &(p_data->rfcomm_fc);
|
||||||
|
|
||||||
|
tBTA_JV_PCB *p_pcb = fc->p_pcb;
|
||||||
|
PORT_FlowControl_GiveCredit(p_pcb->port_handle, TRUE, fc->credits_given);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
** Function bta_jv_set_pm_profile
|
** Function bta_jv_set_pm_profile
|
||||||
|
@ -1136,6 +1136,38 @@ tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p
|
|||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function BTA_JvRfcommFlowControl
|
||||||
|
**
|
||||||
|
** Description This function gives credits to the peer
|
||||||
|
**
|
||||||
|
** Returns BTA_JV_SUCCESS, if the request is being processed.
|
||||||
|
** BTA_JV_FAILURE, otherwise.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given)
|
||||||
|
{
|
||||||
|
tBTA_JV_STATUS status = BTA_JV_FAILURE;
|
||||||
|
tBTA_JV_API_RFCOMM_FLOW_CONTROL *p_msg;
|
||||||
|
UINT32 hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
|
||||||
|
UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle);
|
||||||
|
|
||||||
|
APPL_TRACE_API( "BTA_JvRfcommFlowControl");
|
||||||
|
APPL_TRACE_DEBUG( "handle:0x%x, hi:%d, si:%d", handle, hi, si);
|
||||||
|
if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
|
||||||
|
si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si] &&
|
||||||
|
(p_msg = (tBTA_JV_API_RFCOMM_FLOW_CONTROL *)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_FLOW_CONTROL))) != NULL) {
|
||||||
|
p_msg->hdr.event = BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT;
|
||||||
|
p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
|
||||||
|
p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
|
||||||
|
p_msg->credits_given = credits_given;
|
||||||
|
APPL_TRACE_API( "credits given %d", credits_given);
|
||||||
|
bta_sys_sendmsg(p_msg);
|
||||||
|
status = BTA_JV_SUCCESS;
|
||||||
|
}
|
||||||
|
return (status);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
|
@ -68,6 +68,7 @@ const tBTA_JV_ACTION bta_jv_action[] = {
|
|||||||
bta_jv_rfcomm_stop_server, /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */
|
bta_jv_rfcomm_stop_server, /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */
|
||||||
bta_jv_rfcomm_read, /* BTA_JV_API_RFCOMM_READ_EVT */
|
bta_jv_rfcomm_read, /* BTA_JV_API_RFCOMM_READ_EVT */
|
||||||
bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
|
bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
|
||||||
|
bta_jv_rfcomm_flow_control, /* BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT */
|
||||||
bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
|
bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
|
||||||
bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
|
bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
|
||||||
#if BTA_JV_L2CAP_INCLUDED
|
#if BTA_JV_L2CAP_INCLUDED
|
||||||
|
@ -62,6 +62,7 @@ enum {
|
|||||||
BTA_JV_API_RFCOMM_STOP_SERVER_EVT,
|
BTA_JV_API_RFCOMM_STOP_SERVER_EVT,
|
||||||
BTA_JV_API_RFCOMM_READ_EVT,
|
BTA_JV_API_RFCOMM_READ_EVT,
|
||||||
BTA_JV_API_RFCOMM_WRITE_EVT,
|
BTA_JV_API_RFCOMM_WRITE_EVT,
|
||||||
|
BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT,
|
||||||
BTA_JV_API_SET_PM_PROFILE_EVT,
|
BTA_JV_API_SET_PM_PROFILE_EVT,
|
||||||
BTA_JV_API_PM_STATE_CHANGE_EVT,
|
BTA_JV_API_PM_STATE_CHANGE_EVT,
|
||||||
#if BTA_JV_L2CAP_INCLUDED
|
#if BTA_JV_L2CAP_INCLUDED
|
||||||
@ -309,6 +310,14 @@ typedef struct {
|
|||||||
tBTA_JV_PCB *p_pcb;
|
tBTA_JV_PCB *p_pcb;
|
||||||
} tBTA_JV_API_RFCOMM_WRITE;
|
} tBTA_JV_API_RFCOMM_WRITE;
|
||||||
|
|
||||||
|
/* data type for BTA_JV_API_RFCOMM_FLOW_CONTROL_EVT */
|
||||||
|
typedef struct {
|
||||||
|
BT_HDR hdr;
|
||||||
|
tBTA_JV_RFC_CB *p_cb;
|
||||||
|
tBTA_JV_PCB *p_pcb;
|
||||||
|
UINT16 credits_given;
|
||||||
|
} tBTA_JV_API_RFCOMM_FLOW_CONTROL;
|
||||||
|
|
||||||
/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */
|
/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BT_HDR hdr;
|
BT_HDR hdr;
|
||||||
@ -375,6 +384,7 @@ typedef union {
|
|||||||
tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
|
tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
|
||||||
tBTA_JV_API_RFCOMM_READ rfcomm_read;
|
tBTA_JV_API_RFCOMM_READ rfcomm_read;
|
||||||
tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
|
tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
|
||||||
|
tBTA_JV_API_RFCOMM_FLOW_CONTROL rfcomm_fc;
|
||||||
tBTA_JV_API_SET_PM_PROFILE set_pm;
|
tBTA_JV_API_SET_PM_PROFILE set_pm;
|
||||||
tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
|
tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
|
||||||
tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
|
tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
|
||||||
@ -444,6 +454,7 @@ extern void bta_jv_rfcomm_start_server (tBTA_JV_MSG *p_data);
|
|||||||
extern void bta_jv_rfcomm_stop_server (tBTA_JV_MSG *p_data);
|
extern void bta_jv_rfcomm_stop_server (tBTA_JV_MSG *p_data);
|
||||||
extern void bta_jv_rfcomm_read (tBTA_JV_MSG *p_data);
|
extern void bta_jv_rfcomm_read (tBTA_JV_MSG *p_data);
|
||||||
extern void bta_jv_rfcomm_write (tBTA_JV_MSG *p_data);
|
extern void bta_jv_rfcomm_write (tBTA_JV_MSG *p_data);
|
||||||
|
extern void bta_jv_rfcomm_flow_control(tBTA_JV_MSG *p_data);
|
||||||
extern void bta_jv_set_pm_profile (tBTA_JV_MSG *p_data);
|
extern void bta_jv_set_pm_profile (tBTA_JV_MSG *p_data);
|
||||||
extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data);
|
extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data);
|
||||||
#if BTA_JV_L2CAP_INCLUDED
|
#if BTA_JV_L2CAP_INCLUDED
|
||||||
|
@ -101,8 +101,8 @@ static spp_slot_t *spp_malloc_slot(void)
|
|||||||
spp_local_param.spp_slots[i]->connected = FALSE;
|
spp_local_param.spp_slots[i]->connected = FALSE;
|
||||||
spp_local_param.spp_slots[i]->write_data = NULL;
|
spp_local_param.spp_slots[i]->write_data = NULL;
|
||||||
spp_local_param.spp_slots[i]->list = list_new(spp_osi_free);
|
spp_local_param.spp_slots[i]->list = list_new(spp_osi_free);
|
||||||
|
spp_local_param.spp_slots[i]->incoming_list = list_new(spp_osi_free);
|
||||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
||||||
spp_local_param.spp_slots[i]->incoming_list = list_new(spp_osi_free);
|
|
||||||
if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &spp_local_param.spp_slots[i]->fd) != ESP_OK) {
|
if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &spp_local_param.spp_slots[i]->fd) != ESP_OK) {
|
||||||
osi_free(spp_local_param.spp_slots[i]);
|
osi_free(spp_local_param.spp_slots[i]);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -165,10 +165,10 @@ static void spp_free_slot(spp_slot_t *slot)
|
|||||||
list_free(slot->list);
|
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);
|
||||||
list_free(slot->incoming_list);
|
|
||||||
vRingbufferDelete(slot->ringbuf_read);
|
vRingbufferDelete(slot->ringbuf_read);
|
||||||
vRingbufferDelete(slot->ringbuf_write);
|
vRingbufferDelete(slot->ringbuf_write);
|
||||||
}
|
}
|
||||||
|
list_free(slot->incoming_list);
|
||||||
osi_free(slot);
|
osi_free(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ 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);
|
||||||
}
|
}
|
||||||
spp_free_slot(slot);
|
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:
|
||||||
@ -890,6 +890,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
|||||||
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, ¶m);
|
btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
|
||||||
|
spp_free_slot((spp_slot_t *)p_data->rfc_close.slot);
|
||||||
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) {
|
||||||
@ -921,18 +922,52 @@ 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:
|
||||||
param.data_ind.status = ESP_SPP_SUCCESS;
|
do {
|
||||||
param.data_ind.handle = p_data->data_ind.handle;
|
uint8_t serial;
|
||||||
if (p_data->data_ind.p_buf) {
|
BT_HDR *p_buf;
|
||||||
param.data_ind.len = p_data->data_ind.p_buf->len;
|
UINT16 count = 0;
|
||||||
param.data_ind.data = p_data->data_ind.p_buf->data + p_data->data_ind.p_buf->offset;
|
|
||||||
} else {
|
|
||||||
param.data_ind.len = 0;
|
|
||||||
param.data_ind.data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
btc_spp_cb_to_app(ESP_SPP_DATA_IND_EVT, ¶m);
|
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||||
osi_free (p_data->data_ind.p_buf);
|
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) {
|
||||||
|
BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// get incoming_data from slot incoming list
|
||||||
|
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)) {
|
||||||
|
p_buf = list_front(slot->incoming_list);
|
||||||
|
list_delete(slot->incoming_list, p_buf);
|
||||||
|
} else {
|
||||||
|
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||||
|
|
||||||
|
// invoke callback
|
||||||
|
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) {
|
||||||
|
BTA_JvRfcommFlowControl(p_data->data_ind.handle, count);
|
||||||
|
BTC_TRACE_DEBUG("%s give credits:%d\n", __func__, count);
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
break;
|
break;
|
||||||
case BTA_JV_FREE_SCN_EVT:
|
case BTA_JV_FREE_SCN_EVT:
|
||||||
if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) {
|
if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) {
|
||||||
@ -957,28 +992,9 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If there is too much data not accepted, wait until accepted,or discard it when timeout!
|
|
||||||
* @param list list
|
|
||||||
* @param p_buf incoming data
|
|
||||||
*/
|
|
||||||
static void spp_delay_append(list_t *list, BT_HDR *p_buf){
|
|
||||||
uint8_t count = 0;
|
|
||||||
while (count++ < 100) {
|
|
||||||
if (list_length(list) < 200){
|
|
||||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
|
||||||
list_append(list, p_buf);
|
|
||||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
osi_free(p_buf);
|
|
||||||
BTC_TRACE_WARNING("%s There is too much data not accepted, discard it!", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
|
int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
|
||||||
{
|
{
|
||||||
|
int ret = 1;
|
||||||
bt_status_t status;
|
bt_status_t status;
|
||||||
tBTA_JV p_data;
|
tBTA_JV p_data;
|
||||||
btc_msg_t msg;
|
btc_msg_t msg;
|
||||||
@ -999,36 +1015,35 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
|
|||||||
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;
|
||||||
|
|
||||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
|
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
|
||||||
p_data.data_ind.p_buf = p_buf;
|
bool incoming_list_empty = list_is_empty(slot->incoming_list);
|
||||||
status = btc_transfer_context(&msg, &p_data,
|
list_append(slot->incoming_list, p_buf);
|
||||||
sizeof(tBTA_JV), NULL);
|
if (incoming_list_empty) {
|
||||||
if (status != BT_STATUS_SUCCESS) {
|
BTC_TRACE_DEBUG("%s data post! %d, %d", __func__, slot->rfc_handle, list_length(slot->incoming_list));
|
||||||
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
|
status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_JV), NULL);
|
||||||
|
assert(status == BT_STATUS_SUCCESS);
|
||||||
|
} else if (list_length(slot->incoming_list) > 2) {
|
||||||
|
BTC_TRACE_ERROR("%s data post stop! %d %d", __func__, slot->rfc_handle, list_length(slot->incoming_list));
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (list_is_empty(slot->incoming_list)) {
|
list_append(slot->incoming_list, p_buf);
|
||||||
BaseType_t done = xRingbufferSend(slot->ringbuf_read, p_buf->data + p_buf->offset, p_buf->len, 0);
|
if (list_length(slot->incoming_list) > 2) {
|
||||||
if (done) {
|
BTC_TRACE_ERROR("%s data post stop! %d %d", __func__, slot->rfc_handle, list_length(slot->incoming_list));
|
||||||
osi_free (p_buf);
|
ret = 0;
|
||||||
} else {
|
|
||||||
list_append(slot->incoming_list, p_buf);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list_t *list = slot->incoming_list;
|
|
||||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
|
||||||
spp_delay_append(list,p_buf);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||||
return 1;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
|
int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
|
int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@ -1076,20 +1091,6 @@ static int spp_vfs_close(int fd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool incoming_list_2_ringbuf_read(spp_slot_t *slot)
|
|
||||||
{
|
|
||||||
while (!list_is_empty(slot->incoming_list)) {
|
|
||||||
BT_HDR *p_buf = list_front(slot->incoming_list);
|
|
||||||
BaseType_t done = xRingbufferSend(slot->ringbuf_read, p_buf->data + p_buf->offset, p_buf->len, 0);
|
|
||||||
if (done) {
|
|
||||||
list_remove(slot->incoming_list, p_buf);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (!is_spp_init()) {
|
if (!is_spp_init()) {
|
||||||
@ -1103,12 +1104,28 @@ static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
|
|||||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
incoming_list_2_ringbuf_read(slot);
|
ssize_t item_size = 0;
|
||||||
size_t item_size = 0;
|
uint16_t count = 0;
|
||||||
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_read, &item_size, 0, size);
|
while (!list_is_empty(slot->incoming_list) && size > 0) {
|
||||||
if (item_size > 0){
|
BT_HDR *p_buf = list_front(slot->incoming_list);
|
||||||
memcpy(dst, data, item_size);
|
if (p_buf->len <= size) {
|
||||||
vRingbufferReturnItem(slot->ringbuf_read, data);
|
memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
|
||||||
|
size -= p_buf->len;
|
||||||
|
item_size += p_buf->len;
|
||||||
|
dst += p_buf->len;
|
||||||
|
list_remove(slot->incoming_list, p_buf);
|
||||||
|
count++;
|
||||||
|
} 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) {
|
||||||
|
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;
|
||||||
|
@ -409,7 +409,18 @@ extern int PORT_Control (UINT16 handle, UINT8 signal);
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
extern int PORT_FlowControl (UINT16 handle, BOOLEAN enable);
|
extern int PORT_FlowControl (UINT16 handle, BOOLEAN enable);
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function PORT_FlowControl_GiveCredit
|
||||||
|
**
|
||||||
|
** Description This function gives specified credits to the peer
|
||||||
|
**
|
||||||
|
** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
|
||||||
|
** enable - enables data flow
|
||||||
|
** credits_given - credits to give
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
extern int PORT_FlowControl_GiveCredit (UINT16 handle, BOOLEAN enable, UINT16 credits_given);
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
** Function PORT_GetModemStatus
|
** Function PORT_GetModemStatus
|
||||||
|
@ -899,6 +899,77 @@ int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function PORT_FlowControl_GiveCredit
|
||||||
|
**
|
||||||
|
** Description This function gives specified credits to the peer
|
||||||
|
**
|
||||||
|
** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
|
||||||
|
** enable - enables data flow
|
||||||
|
** credits_given - credits to give
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
int PORT_FlowControl_GiveCredit (UINT16 handle, BOOLEAN enable, UINT16 credits_given)
|
||||||
|
{
|
||||||
|
tPORT *p_port;
|
||||||
|
BOOLEAN old_fc;
|
||||||
|
UINT32 events;
|
||||||
|
|
||||||
|
RFCOMM_TRACE_DEBUG("%s handle:%d enable: %d, cred %d", __func__, handle, enable, credits_given);
|
||||||
|
|
||||||
|
/* Check if handle is valid to avoid crashing */
|
||||||
|
if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
|
||||||
|
return (PORT_BAD_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_port = &rfc_cb.port.port[handle - 1];
|
||||||
|
|
||||||
|
if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
|
||||||
|
return (PORT_NOT_OPENED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p_port->rfc.p_mcb) {
|
||||||
|
return (PORT_NOT_OPENED);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_port->rx.user_fc = !enable;
|
||||||
|
|
||||||
|
if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
|
||||||
|
if (!p_port->rx.user_fc) {
|
||||||
|
port_flow_control_peer(p_port, TRUE, credits_given);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(0); // karl: temporarily not allowed
|
||||||
|
old_fc = p_port->local_ctrl.fc;
|
||||||
|
|
||||||
|
/* FC is set if user is set or peer is set */
|
||||||
|
p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
|
||||||
|
|
||||||
|
if (p_port->local_ctrl.fc != old_fc) {
|
||||||
|
port_start_control (p_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to take care of the case when we could not deliver events */
|
||||||
|
/* to the application because we were flow controlled */
|
||||||
|
if (enable && (p_port->rx.queue_size != 0)) {
|
||||||
|
assert(0); // karl: temporarily not allowed
|
||||||
|
events = PORT_EV_RXCHAR;
|
||||||
|
if (p_port->rx_flag_ev_pending) {
|
||||||
|
p_port->rx_flag_ev_pending = FALSE;
|
||||||
|
events |= PORT_EV_RXFLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
events &= p_port->ev_mask;
|
||||||
|
if (p_port->p_callback && events) {
|
||||||
|
p_port->p_callback (events, p_port->inx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (PORT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
** Function PORT_GetModemStatus
|
** Function PORT_GetModemStatus
|
||||||
|
@ -826,7 +826,8 @@ void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
|
|||||||
/* Another packet is delivered to user. Send credits to peer if required */
|
/* Another packet is delivered to user. Send credits to peer if required */
|
||||||
|
|
||||||
if (p_port->p_data_co_callback(p_port->inx, (UINT8 *)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING)) {
|
if (p_port->p_data_co_callback(p_port->inx, (UINT8 *)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING)) {
|
||||||
port_flow_control_peer(p_port, TRUE, 1);
|
// do nothing, flow control credits will be given upon upper-layer request;
|
||||||
|
// port_flow_control_peer(p_port, TRUE, 1);
|
||||||
} else {
|
} else {
|
||||||
port_flow_control_peer(p_port, FALSE, 0);
|
port_flow_control_peer(p_port, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
@ -210,17 +210,17 @@ void port_release_port (tPORT *p_port)
|
|||||||
|
|
||||||
osi_mutex_global_lock();
|
osi_mutex_global_lock();
|
||||||
RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port);
|
RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port);
|
||||||
if (p_port->rx.queue) {
|
if (p_port->rx.queue != NULL) {
|
||||||
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0)) != NULL) {
|
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue, 0)) != NULL) {
|
||||||
osi_free (p_buf);
|
osi_free(p_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p_port->rx.queue_size = 0;
|
p_port->rx.queue_size = 0;
|
||||||
|
|
||||||
if (p_port->tx.queue) {
|
if (p_port->tx.queue != NULL) {
|
||||||
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) {
|
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue, 0)) != NULL) {
|
||||||
osi_free (p_buf);
|
osi_free(p_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p_port->tx.queue_size = 0;
|
p_port->tx.queue_size = 0;
|
||||||
|
|
||||||
@ -514,10 +514,12 @@ void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
|
|||||||
&& (p_port->credit_rx_max > p_port->credit_rx)) {
|
&& (p_port->credit_rx_max > p_port->credit_rx)) {
|
||||||
rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
|
rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
|
||||||
(UINT8) (p_port->credit_rx_max - p_port->credit_rx));
|
(UINT8) (p_port->credit_rx_max - p_port->credit_rx));
|
||||||
|
RFCOMM_TRACE_DEBUG("send credit: max %d, rx %d, count %d", p_port->credit_rx_max, p_port->credit_rx, count);
|
||||||
p_port->credit_rx = p_port->credit_rx_max;
|
p_port->credit_rx = p_port->credit_rx_max;
|
||||||
|
|
||||||
p_port->rx.peer_fc = FALSE;
|
p_port->rx.peer_fc = FALSE;
|
||||||
|
} else {
|
||||||
|
RFCOMM_TRACE_DEBUG("credit: max %d, rx %d, low %d", p_port->credit_rx_max, p_port->credit_rx, p_port->credit_rx_low);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* else want to disable flow from peer */
|
/* else want to disable flow from peer */
|
||||||
|
Reference in New Issue
Block a user