mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
component/bt: Add Controller to Host Flow Control into v3.1
A cherry-pick of MR !2493
This commit is contained in:
parent
5ebb70ecc5
commit
f406174be5
@ -754,6 +754,14 @@
|
|||||||
#define BTM_BLE_CONFORMANCE_TESTING FALSE
|
#define BTM_BLE_CONFORMANCE_TESTING FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
**
|
||||||
|
** CONTROLLER TO HOST FLOW CONTROL
|
||||||
|
**
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define C2H_FLOW_CONTROL_INCLUDED TRUE
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
**
|
**
|
||||||
** L2CAP
|
** L2CAP
|
||||||
|
@ -95,6 +95,12 @@ static void start_up(void)
|
|||||||
response, &acl_data_size_classic, &acl_buffer_count_classic,
|
response, &acl_data_size_classic, &acl_buffer_count_classic,
|
||||||
&sco_data_size, &sco_buffer_count);
|
&sco_data_size, &sco_buffer_count);
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
// Enable controller to host flow control
|
||||||
|
response = AWAIT_COMMAND(packet_factory->make_set_c2h_flow_control(HCI_HOST_FLOW_CTRL_ACL_ON));
|
||||||
|
packet_parser->parse_generic_command_complete(response);
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
// Tell the controller about our buffer sizes and buffer counts next
|
// Tell the controller about our buffer sizes and buffer counts next
|
||||||
// TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10?
|
// TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10?
|
||||||
response = AWAIT_COMMAND(
|
response = AWAIT_COMMAND(
|
||||||
|
@ -27,6 +27,11 @@
|
|||||||
#include "osi/thread.h"
|
#include "osi/thread.h"
|
||||||
#include "esp_bt.h"
|
#include "esp_bt.h"
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
#include "l2c_int.h"
|
||||||
|
#include "stack/hcimsgs.h"
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
|
#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
|
||||||
#define HCI_BLE_EVENT 0x3e
|
#define HCI_BLE_EVENT 0x3e
|
||||||
#define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2)
|
#define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2)
|
||||||
@ -165,6 +170,7 @@ static void hci_hal_h4_rx_handler(void *arg)
|
|||||||
if (pdTRUE == xQueueReceive(xHciH4Queue, &e, (portTickType)portMAX_DELAY)) {
|
if (pdTRUE == xQueueReceive(xHciH4Queue, &e, (portTickType)portMAX_DELAY)) {
|
||||||
if (e.sig == SIG_HCI_HAL_RECV_PACKET) {
|
if (e.sig == SIG_HCI_HAL_RECV_PACKET) {
|
||||||
fixed_queue_process(hci_hal_env.rx_q);
|
fixed_queue_process(hci_hal_env.rx_q);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,6 +191,37 @@ task_post_status_t hci_hal_h4_task_post(task_post_t timeout)
|
|||||||
return TASK_POST_FAIL;
|
return TASK_POST_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
static void hci_packet_complete(BT_HDR *packet){
|
||||||
|
uint8_t type, num_handle;
|
||||||
|
uint16_t handle;
|
||||||
|
uint16_t handles[MAX_L2CAP_LINKS + 4];
|
||||||
|
uint16_t num_packets[MAX_L2CAP_LINKS + 4];
|
||||||
|
uint8_t *stream = packet->data + packet->offset;
|
||||||
|
tL2C_LCB *p_lcb = NULL;
|
||||||
|
|
||||||
|
STREAM_TO_UINT8(type, stream);
|
||||||
|
if (type == DATA_TYPE_ACL/* || type == DATA_TYPE_SCO*/) {
|
||||||
|
STREAM_TO_UINT16(handle, stream);
|
||||||
|
handle = handle & HCI_DATA_HANDLE_MASK;
|
||||||
|
p_lcb = l2cu_find_lcb_by_handle(handle);
|
||||||
|
if (p_lcb) {
|
||||||
|
p_lcb->completed_packets++;
|
||||||
|
}
|
||||||
|
if (esp_vhci_host_check_send_available()){
|
||||||
|
num_handle = l2cu_find_completed_packets(handles, num_packets);
|
||||||
|
if (num_handle > 0){
|
||||||
|
btsnd_hcic_host_num_xmitted_pkts (num_handle, handles, num_packets);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Send HCI_Host_Number_of_Completed_Packets next time.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
|
|
||||||
static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
|
static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
|
||||||
{
|
{
|
||||||
uint8_t type, hdr_size;
|
uint8_t type, hdr_size;
|
||||||
@ -194,6 +231,11 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
|
|||||||
if (!packet) {
|
if (!packet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
hci_packet_complete(packet);
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
STREAM_TO_UINT8(type, stream);
|
STREAM_TO_UINT8(type, stream);
|
||||||
packet->offset++;
|
packet->offset++;
|
||||||
packet->len--;
|
packet->len--;
|
||||||
|
@ -274,6 +274,7 @@ static void transmit_command(
|
|||||||
|
|
||||||
fixed_queue_enqueue(hci_host_env.command_queue, wait_entry);
|
fixed_queue_enqueue(hci_host_env.command_queue, wait_entry);
|
||||||
hci_host_task_post(TASK_POST_BLOCKING);
|
hci_host_task_post(TASK_POST_BLOCKING);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static future_t *transmit_command_futured(BT_HDR *command)
|
static future_t *transmit_command_futured(BT_HDR *command)
|
||||||
@ -317,8 +318,14 @@ static void event_command_ready(fixed_queue_t *queue)
|
|||||||
command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q;
|
command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q;
|
||||||
|
|
||||||
wait_entry = fixed_queue_dequeue(queue);
|
wait_entry = fixed_queue_dequeue(queue);
|
||||||
hci_host_env.command_credits--;
|
|
||||||
|
|
||||||
|
if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE){
|
||||||
|
packet_fragmenter->fragment_and_dispatch(wait_entry->command);
|
||||||
|
buffer_allocator->free(wait_entry->command);
|
||||||
|
osi_free(wait_entry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hci_host_env.command_credits--;
|
||||||
// Move it to the list of commands awaiting response
|
// Move it to the list of commands awaiting response
|
||||||
osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
|
osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||||
list_append(cmd_wait_q->commands_pending_response, wait_entry);
|
list_append(cmd_wait_q->commands_pending_response, wait_entry);
|
||||||
@ -435,7 +442,6 @@ static bool filter_incoming_event(BT_HDR *packet)
|
|||||||
if (event_code == HCI_COMMAND_COMPLETE_EVT) {
|
if (event_code == HCI_COMMAND_COMPLETE_EVT) {
|
||||||
STREAM_TO_UINT8(hci_host_env.command_credits, stream);
|
STREAM_TO_UINT8(hci_host_env.command_credits, stream);
|
||||||
STREAM_TO_UINT16(opcode, stream);
|
STREAM_TO_UINT16(opcode, stream);
|
||||||
|
|
||||||
wait_entry = get_waiting_command(opcode);
|
wait_entry = get_waiting_command(opcode);
|
||||||
if (!wait_entry) {
|
if (!wait_entry) {
|
||||||
HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
|
HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
|
||||||
|
@ -45,6 +45,16 @@ static BT_HDR *make_read_buffer_size(void)
|
|||||||
return make_command_no_params(HCI_READ_BUFFER_SIZE);
|
return make_command_no_params(HCI_READ_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BT_HDR *make_set_c2h_flow_control(uint8_t enable)
|
||||||
|
{
|
||||||
|
uint8_t *stream;
|
||||||
|
const uint8_t parameter_size = 1;
|
||||||
|
BT_HDR *packet = make_command(HCI_SET_HC_TO_HOST_FLOW_CTRL, parameter_size, &stream);
|
||||||
|
|
||||||
|
UINT8_TO_STREAM(stream, enable);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
static BT_HDR *make_host_buffer_size(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count)
|
static BT_HDR *make_host_buffer_size(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count)
|
||||||
{
|
{
|
||||||
uint8_t *stream;
|
uint8_t *stream;
|
||||||
@ -220,6 +230,7 @@ static BT_HDR *make_packet(size_t data_size)
|
|||||||
static const hci_packet_factory_t interface = {
|
static const hci_packet_factory_t interface = {
|
||||||
make_reset,
|
make_reset,
|
||||||
make_read_buffer_size,
|
make_read_buffer_size,
|
||||||
|
make_set_c2h_flow_control,
|
||||||
make_host_buffer_size,
|
make_host_buffer_size,
|
||||||
make_read_local_version_info,
|
make_read_local_version_info,
|
||||||
make_read_bd_addr,
|
make_read_bd_addr,
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
BT_HDR *(*make_reset)(void);
|
BT_HDR *(*make_reset)(void);
|
||||||
BT_HDR *(*make_read_buffer_size)(void);
|
BT_HDR *(*make_read_buffer_size)(void);
|
||||||
|
BT_HDR *(*make_set_c2h_flow_control)(uint8_t enable);
|
||||||
BT_HDR *(*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count);
|
BT_HDR *(*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count);
|
||||||
BT_HDR *(*make_read_local_version_info)(void);
|
BT_HDR *(*make_read_local_version_info)(void);
|
||||||
BT_HDR *(*make_read_bd_addr)(void);
|
BT_HDR *(*make_read_bd_addr)(void);
|
||||||
|
@ -376,6 +376,7 @@ typedef struct t_l2c_linkcb {
|
|||||||
|
|
||||||
TIMER_LIST_ENT timer_entry; /* Timer list entry for timeout evt */
|
TIMER_LIST_ENT timer_entry; /* Timer list entry for timeout evt */
|
||||||
UINT16 handle; /* The handle used with LM */
|
UINT16 handle; /* The handle used with LM */
|
||||||
|
UINT16 completed_packets; /* The number of conpleted packets */
|
||||||
|
|
||||||
tL2C_CCB_Q ccb_queue; /* Queue of CCBs on this LCB */
|
tL2C_CCB_Q ccb_queue; /* Queue of CCBs on this LCB */
|
||||||
|
|
||||||
@ -667,6 +668,10 @@ extern void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
extern UINT8 l2cu_find_completed_packets(UINT16 *handles, UINT16 *num_packets);
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
|
extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
|
||||||
extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
|
extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
|
||||||
extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
|
extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
|
||||||
|
@ -86,6 +86,9 @@ tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPOR
|
|||||||
l2c_link_adjust_allocation();
|
l2c_link_adjust_allocation();
|
||||||
}
|
}
|
||||||
p_lcb->link_xmit_data_q = list_new(NULL);
|
p_lcb->link_xmit_data_q = list_new(NULL);
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
p_lcb->completed_packets = 0;
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
return (p_lcb);
|
return (p_lcb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,6 +253,11 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb)
|
|||||||
fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
|
fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
|
||||||
p_lcb->le_sec_pending_q = NULL;
|
p_lcb->le_sec_pending_q = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
p_lcb->completed_packets = 0;
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3140,6 +3148,35 @@ void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb)
|
|||||||
|
|
||||||
#endif /* BLE_INCLUDED == TRUE */
|
#endif /* BLE_INCLUDED == TRUE */
|
||||||
|
|
||||||
|
#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function l2cu_find_completed_packets
|
||||||
|
**
|
||||||
|
** Description Find the completed packets,
|
||||||
|
** Then set it to zero
|
||||||
|
**
|
||||||
|
** Returns The num of handles
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
UINT8 l2cu_find_completed_packets(UINT16 *handles, UINT16 *num_packets)
|
||||||
|
{
|
||||||
|
int xx;
|
||||||
|
UINT8 num = 0;
|
||||||
|
tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
|
||||||
|
|
||||||
|
for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
|
||||||
|
if ((p_lcb->in_use) && (p_lcb->completed_packets > 0)) {
|
||||||
|
*(handles++) = p_lcb->handle;
|
||||||
|
*(num_packets++) = p_lcb->completed_packets;
|
||||||
|
num++;
|
||||||
|
p_lcb->completed_packets = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Functions used by both Full and Light Stack
|
** Functions used by both Full and Light Stack
|
||||||
|
Loading…
Reference in New Issue
Block a user