Merge branch 'hci-controller-to-host-flow-control' into develop

This commit is contained in:
Matthias Ringwald 2017-04-01 15:46:41 +02:00
commit dcd578c4c7
5 changed files with 201 additions and 42 deletions

View File

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

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

View File

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

View File

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

View File

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