mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-03 20:54:18 +00:00
Merge branch 'hci-controller-to-host-flow-control' into develop
This commit is contained in:
commit
dcd578c4c7
@ -79,6 +79,21 @@ ENBALE_LE_CENTRAL | Enable support for LE Central Role in HCI and Sec
|
||||
ENABLE_LE_SECURE_CONNECTIONS | Enable LE Secure Connections using [mbed TLS library](https://tls.mbed.org)
|
||||
ENABLE_LE_DATA_CHANNELS | Enable LE Data Channels in credit-based flow control mode
|
||||
ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT
|
||||
ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL | Enable HCI Controller to Host Flow Control, see below
|
||||
|
||||
|
||||
### HCI Controller to Host Flow Control
|
||||
In general, BTstack relies on flow control of the HCI transport, either via Hardware CTS/RTS flow control for UART or regular USB flow control. If this is not possible, e.g on an SoC, BTstack can use HCI Controller to Host Flow Control by defining ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL. If enabled, the HCI Transport implementation must be able to buffer the specified packets. In addition, it also need to be able to buffer a few HCI Events. Using a low number of host buffers might result in less throughput.
|
||||
|
||||
Host buffer configuration for HCI Controller to Host Flow Control:
|
||||
|
||||
#define | Description
|
||||
------------------|------------
|
||||
HCI_HOST_ACL_PACKET_NUM | Max number of ACL packets
|
||||
HCI_HOST_ACL_PACKET_LEN | Max size of HCI Host ACL packets
|
||||
HCI_HOST_SCO_PACKET_NUM | Max number of ACL packets
|
||||
HCI_HOST_SCO_PACKET_LEN | Max size of HCI Host SCO packets
|
||||
|
||||
|
||||
### Memory configuration directives {#sec:memoryConfigurationHowTo}
|
||||
|
||||
@ -118,6 +133,7 @@ MAX_NR_SM_LOOKUP_ENTRIES | Max number of items in Security Manager lookup queue
|
||||
MAX_NR_WHITELIST_ENTRIES | Max number of items in GAP LE Whitelist to connect to
|
||||
MAX_NR_LE_DEVICE_DB_ENTRIES | Max number of items in LE Device DB
|
||||
|
||||
|
||||
The memory is set up by calling *btstack_memory_init* function:
|
||||
|
||||
btstack_memory_init();
|
||||
@ -530,6 +546,3 @@ Finally, if that's not sufficient for your application, you could request BTstac
|
||||
int hci_power_control(HCI_POWER_MODE mode);
|
||||
|
||||
with mode set to *HCI_POWER_OFF*. When needed later, Bluetooth can be started again via by calling it with mode *HCI_POWER_ON*, as seen in all examples.
|
||||
|
||||
|
||||
|
||||
|
104
src/hci.c
104
src/hci.c
@ -76,6 +76,20 @@
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_dump.h"
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
#ifndef HCI_HOST_ACL_PACKET_NUM
|
||||
#error "ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL requires to define HCI_HOST_ACL_PACKET_NUM"
|
||||
#endif
|
||||
#ifndef HCI_HOST_ACL_PACKET_LEN
|
||||
#error "ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL requires to define HCI_HOST_ACL_PACKET_LEN"
|
||||
#endif
|
||||
#ifndef HCI_HOST_SCO_PACKET_NUM
|
||||
#error "ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL requires to define HCI_HOST_SCO_PACKET_NUM"
|
||||
#endif
|
||||
#ifndef HCI_HOST_SCO_PACKET_LEN
|
||||
#error "ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL requires to define HCI_HOST_SCO_PACKET_LEN"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define HCI_CONNECTION_TIMEOUT_MS 10000
|
||||
#define HCI_RESET_RESEND_TIMEOUT_MS 200
|
||||
@ -401,8 +415,8 @@ static int hci_number_free_sco_slots(void){
|
||||
}
|
||||
#endif
|
||||
|
||||
// new functions replacing hci_can_send_packet_now[_using_packet_buffer]
|
||||
int hci_can_send_command_packet_now(void){
|
||||
// only used to send HCI Host Number Completed Packets
|
||||
static int hci_can_send_comand_packet_transport(void){
|
||||
if (hci_stack->hci_packet_buffer_reserved) return 0;
|
||||
|
||||
// check for async hci transport implementations
|
||||
@ -411,7 +425,12 @@ int hci_can_send_command_packet_now(void){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// new functions replacing hci_can_send_packet_now[_using_packet_buffer]
|
||||
int hci_can_send_command_packet_now(void){
|
||||
if (hci_can_send_comand_packet_transport() == 0) return 0;
|
||||
return hci_stack->num_cmd_packets > 0;
|
||||
}
|
||||
|
||||
@ -687,6 +706,11 @@ static void acl_handler(uint8_t *packet, int size){
|
||||
hci_connection_timestamp(conn);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
hci_stack->host_completed_packets = 1;
|
||||
conn->num_packets_completed++;
|
||||
#endif
|
||||
|
||||
// handle different packet types
|
||||
switch (acl_flags & 0x03) {
|
||||
|
||||
@ -1143,6 +1167,19 @@ static void hci_initializing_run(void){
|
||||
hci_stack->substate = HCI_INIT_W4_READ_LOCAL_SUPPORTED_FEATURES;
|
||||
hci_send_cmd(&hci_read_local_supported_features);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
case HCI_INIT_SET_CONTROLLER_TO_HOST_FLOW_CONTROL:
|
||||
hci_stack->substate = HCI_INIT_W4_SET_CONTROLLER_TO_HOST_FLOW_CONTROL;
|
||||
hci_send_cmd(&hci_set_controller_to_host_flow_control, 3); // ACL + SCO Flow Control
|
||||
break;
|
||||
case HCI_INIT_HOST_BUFFER_SIZE:
|
||||
hci_stack->substate = HCI_INIT_W4_HOST_BUFFER_SIZE;
|
||||
hci_send_cmd(&hci_host_buffer_size, HCI_HOST_ACL_PACKET_LEN, HCI_HOST_SCO_PACKET_LEN,
|
||||
HCI_HOST_ACL_PACKET_NUM, HCI_HOST_SCO_PACKET_NUM);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case HCI_INIT_SET_EVENT_MASK:
|
||||
hci_stack->substate = HCI_INIT_W4_SET_EVENT_MASK;
|
||||
if (hci_le_supported()){
|
||||
@ -1152,6 +1189,7 @@ static void hci_initializing_run(void){
|
||||
hci_send_cmd(&hci_set_event_mask,0xffffffff, 0x1FFFFFFF);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_CLASSIC
|
||||
case HCI_INIT_WRITE_SIMPLE_PAIRING_MODE:
|
||||
hci_stack->substate = HCI_INIT_W4_WRITE_SIMPLE_PAIRING_MODE;
|
||||
@ -2109,6 +2147,15 @@ static void event_handler(uint8_t *packet, int size){
|
||||
static void sco_handler(uint8_t * packet, uint16_t size){
|
||||
if (!hci_stack->sco_packet_handler) return;
|
||||
hci_stack->sco_packet_handler(HCI_SCO_DATA_PACKET, 0, packet, size);
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
hci_con_handle_t con_handle = READ_SCO_CONNECTION_HANDLE(packet);
|
||||
hci_connection_t *conn = hci_connection_for_handle(con_handle);
|
||||
if (conn){
|
||||
conn->num_packets_completed++;
|
||||
hci_stack->host_completed_packets = 1;
|
||||
hci_run();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2600,6 +2647,50 @@ void gap_local_bd_addr(bd_addr_t address_buffer){
|
||||
memcpy(address_buffer, hci_stack->local_bd_addr, 6);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
static void hci_host_num_completed_packets(void){
|
||||
|
||||
// create packet manually as arrays are not supported and num_commands should not get reduced
|
||||
hci_reserve_packet_buffer();
|
||||
uint8_t * packet = hci_get_outgoing_packet_buffer();
|
||||
|
||||
uint16_t size = 0;
|
||||
uint16_t num_handles = 0;
|
||||
packet[size++] = 0x35;
|
||||
packet[size++] = 0x0c;
|
||||
size++; // skip param len
|
||||
size++; // skip num handles
|
||||
|
||||
// add { handle, packets } entries
|
||||
btstack_linked_item_t * it;
|
||||
for (it = (btstack_linked_item_t *) hci_stack->connections; it ; it = it->next){
|
||||
hci_connection_t * connection = (hci_connection_t *) it;
|
||||
if (connection->num_packets_completed){
|
||||
little_endian_store_16(packet, size, connection->con_handle);
|
||||
size += 2;
|
||||
little_endian_store_16(packet, size, connection->num_packets_completed);
|
||||
size += 2;
|
||||
//
|
||||
num_handles++;
|
||||
connection->num_packets_completed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
packet[2] = size - 3;
|
||||
packet[3] = num_handles;
|
||||
|
||||
hci_stack->host_completed_packets = 0;
|
||||
|
||||
hci_dump_packet(HCI_COMMAND_DATA_PACKET, 0, packet, size);
|
||||
hci_stack->hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
|
||||
|
||||
// release packet buffer for synchronous transport implementations
|
||||
if (hci_transport_synchronous()){
|
||||
hci_stack->hci_packet_buffer_reserved = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void hci_run(void){
|
||||
|
||||
// log_info("hci_run: entered");
|
||||
@ -2622,6 +2713,15 @@ static void hci_run(void){
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
// send host num completed packets next as they don't require num_cmd_packets > 0
|
||||
if (!hci_can_send_comand_packet_transport()) return;
|
||||
if (hci_stack->host_completed_packets){
|
||||
hci_host_num_completed_packets();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!hci_can_send_command_packet_now()) return;
|
||||
|
||||
// global/non-connection oriented commands
|
||||
|
18
src/hci.h
18
src/hci.h
@ -136,6 +136,7 @@ extern "C" {
|
||||
|
||||
// ACL Packet
|
||||
#define READ_ACL_CONNECTION_HANDLE( buffer ) ( little_endian_read_16(buffer,0) & 0x0fff)
|
||||
#define READ_SCO_CONNECTION_HANDLE( buffer ) ( little_endian_read_16(buffer,0) & 0x0fff)
|
||||
#define READ_ACL_FLAGS( buffer ) ( buffer[1] >> 4 )
|
||||
#define READ_ACL_LENGTH( buffer ) (little_endian_read_16(buffer, 2))
|
||||
|
||||
@ -494,6 +495,10 @@ typedef struct {
|
||||
uint8_t num_acl_packets_sent;
|
||||
uint8_t num_sco_packets_sent;
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
uint8_t num_packets_completed;
|
||||
#endif
|
||||
|
||||
// LE Connection parameter update
|
||||
le_con_parameter_update_state_t le_con_parameter_update_state;
|
||||
uint8_t le_con_param_update_identifier;
|
||||
@ -552,8 +557,17 @@ typedef enum hci_init_state{
|
||||
HCI_INIT_W4_READ_BUFFER_SIZE,
|
||||
HCI_INIT_READ_LOCAL_SUPPORTED_FEATURES,
|
||||
HCI_INIT_W4_READ_LOCAL_SUPPORTED_FEATURES,
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
HCI_INIT_SET_CONTROLLER_TO_HOST_FLOW_CONTROL,
|
||||
HCI_INIT_W4_SET_CONTROLLER_TO_HOST_FLOW_CONTROL,
|
||||
HCI_INIT_HOST_BUFFER_SIZE,
|
||||
HCI_INIT_W4_HOST_BUFFER_SIZE,
|
||||
#endif
|
||||
|
||||
HCI_INIT_SET_EVENT_MASK,
|
||||
HCI_INIT_W4_SET_EVENT_MASK,
|
||||
|
||||
HCI_INIT_WRITE_SIMPLE_PAIRING_MODE,
|
||||
HCI_INIT_W4_WRITE_SIMPLE_PAIRING_MODE,
|
||||
HCI_INIT_WRITE_PAGE_TIMEOUT,
|
||||
@ -731,6 +745,10 @@ typedef struct {
|
||||
uint8_t decline_reason;
|
||||
bd_addr_t decline_addr;
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
uint8_t host_completed_packets;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BLE
|
||||
uint8_t le_own_addr_type;
|
||||
bd_addr_t le_random_address;
|
||||
|
@ -644,6 +644,15 @@ const hci_cmd_t hci_write_synchronous_flow_control_enable = {
|
||||
OPCODE(OGF_CONTROLLER_BASEBAND, 0x2f), "1"
|
||||
};
|
||||
|
||||
#ifdef ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
|
||||
|
||||
/**
|
||||
* @param flow_control_enable - 0: off, 1: ACL only, 2: SCO only, 3: ACL + SCO
|
||||
*/
|
||||
const hci_cmd_t hci_set_controller_to_host_flow_control = {
|
||||
OPCODE(OGF_CONTROLLER_BASEBAND, 0x31), "1"
|
||||
};
|
||||
|
||||
/**
|
||||
* @param host_acl_data_packet_length
|
||||
* @param host_synchronous_data_packet_length
|
||||
@ -654,6 +663,23 @@ const hci_cmd_t hci_host_buffer_size = {
|
||||
OPCODE(OGF_CONTROLLER_BASEBAND, 0x33), "2122"
|
||||
};
|
||||
|
||||
#if 0
|
||||
//
|
||||
// command sent manually sent by hci_host_num_completed_packets
|
||||
//
|
||||
/**
|
||||
* @note only single handle supported by BTstack command generator
|
||||
* @param number_of_handles must be 1
|
||||
* @param connection_handle
|
||||
* @param host_num_of_completed_packets for the given connection handle
|
||||
*/
|
||||
const hci_cmd_t hci_host_number_of_completed_packets = {
|
||||
OPCODE(OGF_CONTROLLER_BASEBAND, 0x35), "1H2"
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param handle
|
||||
*/
|
||||
|
@ -98,6 +98,7 @@ extern const hci_cmd_t hci_enhanced_accept_synchronous_connection;
|
||||
extern const hci_cmd_t hci_enhanced_setup_synchronous_connection;
|
||||
extern const hci_cmd_t hci_flush;
|
||||
extern const hci_cmd_t hci_host_buffer_size;
|
||||
// extern const hci_cmd_t hci_host_number_of_completed_packets;
|
||||
extern const hci_cmd_t hci_inquiry;
|
||||
extern const hci_cmd_t hci_inquiry_cancel;
|
||||
extern const hci_cmd_t hci_io_capability_request_negative_reply;
|
||||
@ -132,6 +133,7 @@ extern const hci_cmd_t hci_reset;
|
||||
extern const hci_cmd_t hci_role_discovery;
|
||||
extern const hci_cmd_t hci_set_connection_encryption;
|
||||
extern const hci_cmd_t hci_set_event_mask;
|
||||
extern const hci_cmd_t hci_set_controller_to_host_flow_control;
|
||||
extern const hci_cmd_t hci_setup_synchronous_connection;
|
||||
extern const hci_cmd_t hci_sniff_mode;
|
||||
extern const hci_cmd_t hci_switch_role_command;
|
||||
|
Loading…
x
Reference in New Issue
Block a user