Merge branch 'bugfix/fix_spp_read_flow_control_v3.3' into 'release/v3.3'

component_bt/fix spp flow control and vfs write[backport 3.3]

See merge request espressif/esp-idf!11471
This commit is contained in:
Jiang Jiang Jian 2020-12-10 22:50:56 +08:00
commit ab41d84a2f
15 changed files with 979 additions and 373 deletions

View File

@ -27,7 +27,10 @@ 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_DEINIT, /*!< SPP module shall deinit first */
ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */
} esp_spp_status_t; } esp_spp_status_t;
/* Security Setting Mask, Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.*/ /* Security Setting Mask, Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.*/

View File

@ -3624,9 +3624,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

@ -1040,7 +1040,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

@ -345,6 +345,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 */
@ -892,6 +893,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

View File

@ -2258,16 +2258,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 {
@ -2276,6 +2276,24 @@ 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

View File

@ -1137,6 +1137,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);
}
/******************************************************************************* /*******************************************************************************
** **

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -409,6 +409,19 @@ 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

View File

@ -897,6 +897,75 @@ int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable)
return (PORT_SUCCESS); return (PORT_SUCCESS);
} }
/*******************************************************************************
**
** 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);
}
/******************************************************************************* /*******************************************************************************
** **

View File

@ -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);
} }

View File

@ -210,26 +210,18 @@ 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);
while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL) { if (p_port->rx.queue != NULL) {
osi_free (p_buf); while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue)) != NULL) {
if (p_port->rx.queue) { osi_free(p_buf);
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->rx.queue)) != NULL) {
osi_free (p_buf);
}
} }
} }
p_port->rx.queue_size = 0; p_port->rx.queue_size = 0;
while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) { if (p_port->tx.queue != NULL) {
osi_free (p_buf); while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue)) != NULL) {
if (p_port->tx.queue) { osi_free(p_buf);
while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_port->tx.queue)) != NULL) {
osi_free (p_buf);
}
} }
} }
p_port->tx.queue_size = 0; p_port->tx.queue_size = 0;
osi_mutex_global_unlock(); osi_mutex_global_unlock();
@ -522,10 +514,14 @@ 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 */

View File

@ -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);

View File

@ -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;
}