diff --git a/components/bt/bluedroid/common/include/common/bt_target.h b/components/bt/bluedroid/common/include/common/bt_target.h index ef4556686..a5bb49b6c 100644 --- a/components/bt/bluedroid/common/include/common/bt_target.h +++ b/components/bt/bluedroid/common/include/common/bt_target.h @@ -581,7 +581,7 @@ #define BTM_DEFAULT_DISC_INTERVAL 0x0800 #endif -/* +/* * {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS} * * SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object Transfer,Bit22 -Telephony) @@ -754,6 +754,14 @@ #define BTM_BLE_CONFORMANCE_TESTING FALSE #endif +/****************************************************************************** +** +** CONTROLLER TO HOST FLOW CONTROL +** +******************************************************************************/ + +#define C2H_FLOW_CONTROL_INCLUDED TRUE + /****************************************************************************** ** ** L2CAP diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c index 06b8a52c7..a748f0f53 100644 --- a/components/bt/bluedroid/device/controller.c +++ b/components/bt/bluedroid/device/controller.c @@ -95,6 +95,12 @@ static void start_up(void) response, &acl_data_size_classic, &acl_buffer_count_classic, &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 // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10? response = AWAIT_COMMAND( diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index 8b87a6faa..0a93f1d0c 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -27,6 +27,11 @@ #include "osi/thread.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_BLE_EVENT 0x3e #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 (e.sig == SIG_HCI_HAL_RECV_PACKET) { 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; } +#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) { uint8_t type, hdr_size; @@ -194,6 +231,11 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) if (!packet) { return; } + +#if (C2H_FLOW_CONTROL_INCLUDED == TRUE) + hci_packet_complete(packet); +#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE + STREAM_TO_UINT8(type, stream); packet->offset++; packet->len--; diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/bluedroid/hci/hci_layer.c index 59b08c481..ec6866386 100644 --- a/components/bt/bluedroid/hci/hci_layer.c +++ b/components/bt/bluedroid/hci/hci_layer.c @@ -274,6 +274,7 @@ static void transmit_command( fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); hci_host_task_post(TASK_POST_BLOCKING); + } 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; 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 osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); 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) { STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); - wait_entry = get_waiting_command(opcode); if (!wait_entry) { HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); diff --git a/components/bt/bluedroid/hci/hci_packet_factory.c b/components/bt/bluedroid/hci/hci_packet_factory.c index 2c88570e3..ae204caf4 100644 --- a/components/bt/bluedroid/hci/hci_packet_factory.c +++ b/components/bt/bluedroid/hci/hci_packet_factory.c @@ -45,6 +45,16 @@ static BT_HDR *make_read_buffer_size(void) 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) { uint8_t *stream; @@ -220,6 +230,7 @@ static BT_HDR *make_packet(size_t data_size) static const hci_packet_factory_t interface = { make_reset, make_read_buffer_size, + make_set_c2h_flow_control, make_host_buffer_size, make_read_local_version_info, make_read_bd_addr, diff --git a/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h b/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h index 0cc4dc684..e48c4be43 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h +++ b/components/bt/bluedroid/hci/include/hci/hci_packet_factory.h @@ -25,6 +25,7 @@ typedef struct { BT_HDR *(*make_reset)(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_read_local_version_info)(void); BT_HDR *(*make_read_bd_addr)(void); diff --git a/components/bt/bluedroid/stack/include/stack/hcidefs.h b/components/bt/bluedroid/stack/include/stack/hcidefs.h index 09320b1f1..0169ba8cc 100644 --- a/components/bt/bluedroid/stack/include/stack/hcidefs.h +++ b/components/bt/bluedroid/stack/include/stack/hcidefs.h @@ -793,7 +793,7 @@ #define HCI_ERR_MAX_ERR 0x43 //ESP vendor error code -#define HCI_ERR_ESP_VENDOR_FAIL 0xE0 +#define HCI_ERR_ESP_VENDOR_FAIL 0xE0 #define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK 0xFF diff --git a/components/bt/bluedroid/stack/l2cap/include/l2c_int.h b/components/bt/bluedroid/stack/l2cap/include/l2c_int.h index 3699e7f05..e2c0ef6a7 100644 --- a/components/bt/bluedroid/stack/l2cap/include/l2c_int.h +++ b/components/bt/bluedroid/stack/l2cap/include/l2c_int.h @@ -376,6 +376,7 @@ typedef struct t_l2c_linkcb { TIMER_LIST_ENT timer_entry; /* Timer list entry for timeout evt */ 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 */ @@ -667,6 +668,10 @@ extern void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb); #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 void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb); extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb); diff --git a/components/bt/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/bluedroid/stack/l2cap/l2c_utils.c index 358a57b5f..b1cfbe46d 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_utils.c @@ -57,7 +57,7 @@ tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPOR btu_free_timer(&p_lcb->timer_entry); btu_free_timer(&p_lcb->info_timer_entry); btu_free_timer(&p_lcb->upda_con_timer); - + memset (p_lcb, 0, sizeof (tL2C_LCB)); memcpy (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN); @@ -86,6 +86,9 @@ tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPOR l2c_link_adjust_allocation(); } 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); } } @@ -137,7 +140,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb) memset(&p_lcb->info_timer_entry, 0, sizeof(TIMER_LIST_ENT)); btu_free_timer(&p_lcb->upda_con_timer); memset(&p_lcb->upda_con_timer, 0, sizeof(TIMER_LIST_ENT)); - + /* Release any unfinished L2CAP packet on this link */ if (p_lcb->p_hcit_rcv_acl) { osi_free(p_lcb->p_hcit_rcv_acl); @@ -250,6 +253,11 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb) fixed_queue_free(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 + } @@ -1488,7 +1496,7 @@ tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid) btu_free_quick_timer(&p_ccb->fcrb.ack_timer); memset(&p_ccb->fcrb.ack_timer, 0, sizeof(TIMER_LIST_ENT)); p_ccb->fcrb.ack_timer.param = (TIMER_PARAM_TYPE)p_ccb; - + btu_free_quick_timer(&p_ccb->fcrb.mon_retrans_timer); memset(&p_ccb->fcrb.mon_retrans_timer, 0, sizeof(TIMER_LIST_ENT)); p_ccb->fcrb.mon_retrans_timer.param = (TIMER_PARAM_TYPE)p_ccb; @@ -3140,6 +3148,35 @@ void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb) #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