mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-26 00:40:38 +00:00
implemented L2CAP packet framgentation (in hci.c)
This commit is contained in:
parent
2e480f6351
commit
452cf3bbef
102
src/hci.c
102
src/hci.c
@ -384,9 +384,80 @@ int hci_transport_synchronous(void){
|
||||
return hci_stack->hci_transport->can_send_packet_now == NULL;
|
||||
}
|
||||
|
||||
static int hci_send_acl_packet_fragments(hci_connection_t *connection){
|
||||
|
||||
// log_info("hci_send_acl_packet_fragments %u/%u (con 0x%04x)", hci_stack->acl_fragmentation_pos, hci_stack->acl_fragmentation_total_size, connection->con_handle);
|
||||
|
||||
// max ACL data packet length depends on connection type (LE vs. Classic) and available buffers
|
||||
uint16_t max_acl_data_packet_length = hci_stack->acl_data_packet_length;
|
||||
if (hci_is_le_connection(connection) && hci_stack->le_data_packets_length > 0){
|
||||
max_acl_data_packet_length = hci_stack->le_data_packets_length;
|
||||
}
|
||||
|
||||
// testing: reduce buffer to minimum
|
||||
// max_acl_data_packet_length = 52;
|
||||
|
||||
int err;
|
||||
// multiple packets could be send on a synchronous HCI transport
|
||||
while (1){
|
||||
|
||||
// get current data
|
||||
const uint16_t acl_header_pos = hci_stack->acl_fragmentation_pos - 4;
|
||||
int current_acl_data_packet_length = hci_stack->acl_fragmentation_total_size - hci_stack->acl_fragmentation_pos;
|
||||
int more_fragments = 0;
|
||||
|
||||
// if ACL packet is larger than Bluetooth packet buffer, only send max_acl_data_packet_length
|
||||
if (current_acl_data_packet_length > max_acl_data_packet_length){
|
||||
more_fragments = 1;
|
||||
current_acl_data_packet_length = max_acl_data_packet_length;
|
||||
}
|
||||
|
||||
// copy handle_and_flags if not first fragment and update packet boundary flags to be 01 (continuing fragmnent)
|
||||
if (acl_header_pos > 0){
|
||||
uint16_t handle_and_flags = READ_BT_16(hci_stack->hci_packet_buffer, 0);
|
||||
handle_and_flags = (handle_and_flags & 0xcfff) | (1 << 12);
|
||||
bt_store_16(hci_stack->hci_packet_buffer, acl_header_pos, handle_and_flags);
|
||||
}
|
||||
|
||||
// update header len
|
||||
bt_store_16(hci_stack->hci_packet_buffer, acl_header_pos + 2, current_acl_data_packet_length);
|
||||
|
||||
// count packet
|
||||
connection->num_acl_packets_sent++;
|
||||
|
||||
// send packet
|
||||
uint8_t * packet = &hci_stack->hci_packet_buffer[acl_header_pos];
|
||||
const int size = current_acl_data_packet_length + 4;
|
||||
// hexdump(packet, size);
|
||||
err = hci_stack->hci_transport->send_packet(HCI_ACL_DATA_PACKET, packet, size);
|
||||
|
||||
// done yet?
|
||||
if (!more_fragments) break;
|
||||
|
||||
// update start of next fragment to send
|
||||
hci_stack->acl_fragmentation_pos += current_acl_data_packet_length;
|
||||
|
||||
// can send more?
|
||||
if (!hci_can_send_prepared_acl_packet_now(connection->con_handle)) return err;
|
||||
}
|
||||
|
||||
// done
|
||||
hci_stack->acl_fragmentation_pos = 0;
|
||||
hci_stack->acl_fragmentation_total_size = 0;
|
||||
|
||||
// free buffer now for synchronous transport
|
||||
if (!hci_transport_synchronous()){
|
||||
hci_release_packet_buffer();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// pre: caller has reserved the packet buffer
|
||||
int hci_send_acl_packet_buffer(int size){
|
||||
|
||||
// log_info("hci_send_acl_packet_buffer size %u", size);
|
||||
|
||||
if (!hci_stack->hci_packet_buffer_reserved) {
|
||||
log_error("hci_send_acl_packet_buffer called without reserving packet buffer");
|
||||
return 0;
|
||||
@ -410,19 +481,13 @@ int hci_send_acl_packet_buffer(int size){
|
||||
}
|
||||
hci_connection_timestamp(connection);
|
||||
|
||||
// count packet
|
||||
connection->num_acl_packets_sent++;
|
||||
// log_info("hci_send_acl_packet - handle %u, sent %u", connection->con_handle, connection->num_acl_packets_sent);
|
||||
// hci_dump_packet( HCI_ACL_DATA_PACKET, 0, packet, size);
|
||||
|
||||
// send packet
|
||||
int err = hci_stack->hci_transport->send_packet(HCI_ACL_DATA_PACKET, packet, size);
|
||||
// setup data
|
||||
hci_stack->acl_fragmentation_total_size = size;
|
||||
hci_stack->acl_fragmentation_pos = 4; // start of L2CAP packet
|
||||
|
||||
// free packet buffer for synchronous transport implementations
|
||||
if (hci_transport_synchronous()){
|
||||
hci_release_packet_buffer();
|
||||
}
|
||||
|
||||
return err;
|
||||
return hci_send_acl_packet_fragments(connection);
|
||||
}
|
||||
|
||||
static void acl_handler(uint8_t *packet, int size){
|
||||
@ -1851,6 +1916,21 @@ void hci_run(){
|
||||
#endif
|
||||
}
|
||||
|
||||
// send continuation fragments
|
||||
if (hci_stack->acl_fragmentation_total_size > 0) {
|
||||
hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(hci_stack->hci_packet_buffer);
|
||||
if (hci_can_send_prepared_acl_packet_now(con_handle)){
|
||||
hci_connection_t *connection = hci_connection_for_handle(con_handle);
|
||||
if (connection) {
|
||||
hci_send_acl_packet_fragments(connection);
|
||||
return;
|
||||
}
|
||||
// connection gone -> discard further fragments
|
||||
hci_stack->acl_fragmentation_total_size = 0;
|
||||
hci_stack->acl_fragmentation_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (hci_stack->state){
|
||||
case HCI_STATE_INITIALIZING:
|
||||
hci_initializing_state_machine();
|
||||
|
@ -375,10 +375,12 @@ typedef struct {
|
||||
// list of existing baseband connections
|
||||
linked_list_t connections;
|
||||
|
||||
// single buffer for HCI Command assembly
|
||||
// single buffer for HCI packet assembly
|
||||
uint8_t hci_packet_buffer[HCI_PACKET_BUFFER_SIZE]; // opcode (16), len(8)
|
||||
uint8_t hci_packet_buffer_reserved;
|
||||
|
||||
uint16_t acl_fragmentation_pos;
|
||||
uint16_t acl_fragmentation_total_size;
|
||||
|
||||
/* host to controller flow control */
|
||||
uint8_t num_cmd_packets;
|
||||
// uint8_t total_num_cmd_packets;
|
||||
|
Loading…
x
Reference in New Issue
Block a user