From 6218e6f12b65360502381e49940a9ac8941192a4 Mon Sep 17 00:00:00 2001 From: "matthias.ringwald" Date: Thu, 29 Jul 2010 19:35:34 +0000 Subject: [PATCH] add counters for flow control, channel credits event, return -1 if no space in BT module --- include/btstack/hci_cmds.h | 3 ++ src/daemon.c | 9 +++-- src/hci.c | 10 +++-- src/l2cap.c | 81 ++++++++++++++++++++++++++++++++++++-- src/l2cap.h | 5 ++- 5 files changed, 97 insertions(+), 11 deletions(-) diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 852562b64..1bd45010e 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -126,6 +126,9 @@ // data: event(8), len(8), handle(16) #define L2CAP_EVENT_TIMEOUT_CHECK 0x73 +// data: event(8), len(8), handle(16) +#define L2CAP_EVENT_CREDITS 0x74 + // data: event(8), len(8), service_record_handle(32) #define SDP_SERVICE_REGISTERED 0x80 diff --git a/src/daemon.c b/src/daemon.c index 08f453cc3..f8e804f10 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -177,6 +177,9 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui } static int daemon_client_handler(connection_t *connection, uint16_t packet_type, uint16_t channel, uint8_t *data, uint16_t length){ + + int err = 0; + switch (packet_type){ case HCI_COMMAND_DATA_PACKET: if (READ_CMD_OGF(data) != OGF_BTSTACK) { @@ -188,11 +191,11 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type, } break; case HCI_ACL_DATA_PACKET: - hci_send_acl_packet(data, length); + err = hci_send_acl_packet(data, length); break; case L2CAP_DATA_PACKET: // process l2cap packet... - l2cap_send_internal(channel, data, length); + err = l2cap_send_internal(channel, data, length); break; case DAEMON_EVENT_PACKET: switch (data[0]) { @@ -213,7 +216,7 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type, } break; } - return 0; + return err; } static void deamon_status_event_handler(uint8_t *packet, uint16_t size){ diff --git a/src/hci.c b/src/hci.c index 808871e58..a43f4aea2 100644 --- a/src/hci.c +++ b/src/hci.c @@ -188,7 +188,9 @@ int hci_ready_to_send(hci_con_handle_t handle){ int hci_send_acl_packet(uint8_t *packet, int size){ - // update idle timestamp + // check for free places on BT module + if (!hci_number_free_acl_slots()) return -1; + hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet); hci_connection_t *connection = connection_for_handle( con_handle); if (!connection) return 0; @@ -198,8 +200,10 @@ int hci_send_acl_packet(uint8_t *packet, int size){ connection->num_acl_packets_sent++; log_dbg("hci_send_acl_packet - handle %u, sent %u\n", connection->con_handle, connection->num_acl_packets_sent); - // send packet - return hci_stack.hci_transport->send_acl_packet(packet, size); + // send packet - ignore errors + hci_stack.hci_transport->send_acl_packet(packet, size); + + return 0; } static void acl_handler(uint8_t *packet, int size){ diff --git a/src/l2cap.c b/src/l2cap.c index 71100091a..5d9ff41fb 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -40,6 +40,7 @@ #include "l2cap.h" #include "hci.h" #include "hci_dump.h" +#include "debug.h" #include #include @@ -73,7 +74,7 @@ static uint8_t config_options[] = { 1, 2, 150, 0}; // mtu = 48 void l2cap_init(){ sig_buffer = malloc( L2CAP_MINIMAL_MTU ); acl_buffer = malloc( HCI_ACL_3DH5_SIZE); - + // // register callback with HCI // @@ -133,6 +134,25 @@ void l2cap_emit_connection_request(l2cap_channel_t *channel) { l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event)); } +void l2cap_emit_credits(l2cap_channel_t *channel, uint8_t credits) { + // first check if we should hand out credits + + if (!hci_number_free_acl_slots() || hci_number_outgoing_packets(channel->handle) >= 2){ + return; // not yet + } + // track credits + channel->packets_granted += credits; + log_dbg("l2cap_emit_credits for cid %u, credits now: %u (+%u)\n", channel->local_cid, channel->packets_granted, credits); + + uint8_t event[5]; + event[0] = L2CAP_EVENT_CREDITS; + event[1] = sizeof(event) - 2; + bt_store_16(event, 2, channel->local_cid); + event[4] = credits; + hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); + l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event)); +} + l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){ linked_item_t *it; l2cap_channel_t * channel; @@ -162,10 +182,26 @@ int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMAND return hci_send_acl_packet(sig_buffer, len); } -void l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){ +int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){ + + // check for free places on BT module + if (!hci_number_free_acl_slots()) return -1; + + int err = 0; + // find channel for local_cid, construct l2cap packet and send l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); if (channel) { + // track sending + ++channel->packets_outgoing; + if (channel->packets_granted > 0){ + --channel->packets_granted; + } else { + log_err("l2cap_send_internal cid %u, no credits!\n", local_cid); + } + log_dbg("l2cap_send_internal cid %u, 1 credit used, credits left %u; outgoing count %u\n", + local_cid, channel->packets_granted, channel->packets_outgoing); + // 0 - Connection handle : PB=10 : BC=00 bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14)); // 2 - ACL length @@ -176,9 +212,11 @@ void l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){ bt_store_16(acl_buffer, 6, channel->remote_cid); // 8 - data memcpy(&acl_buffer[8], data, len); + // send - hci_send_acl_packet(acl_buffer, len+8); + err = hci_send_acl_packet(acl_buffer, len+8); } + return err; } // open outgoing L2CAP channel @@ -197,6 +235,10 @@ void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t p chan->packet_handler = packet_handler; chan->remote_mtu = L2CAP_MINIMAL_MTU; + // flow control + chan->packets_granted = 0; + chan->packets_outgoing = 0; + // set initial state chan->state = L2CAP_STATE_CLOSED; chan->sig_id = L2CAP_SIG_ID_INVALID; @@ -257,7 +299,8 @@ void l2cap_event_handler( uint8_t *packet, uint16_t size ){ bd_addr_t address; hci_con_handle_t handle; linked_item_t *it; - + int i; + switch(packet[0]){ // handle connection complete events @@ -297,6 +340,34 @@ void l2cap_event_handler( uint8_t *packet, uint16_t size ){ } break; + case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: + for (i=0; inext ; it = it->next){ + l2cap_channel_t * channel = (l2cap_channel_t *) it->next; + if (channel->packets_outgoing){ + oldest_channel = channel; + } + } + // decrease packets and grant new credits + if (oldest_channel) { + oldest_channel->packets_outgoing--; + + log_dbg("hci_number_completed_packet (l2cap) for cid %u, outgoing count %u\n", + oldest_channel->local_cid, oldest_channel->packets_outgoing); + + } else { + log_err("hci_number_completed_packet but no outgoing packet in records\n"); + } + } + } + break; + // HCI Connection Timeouts case L2CAP_EVENT_TIMEOUT_CHECK: handle = READ_BT_16(packet, 2); @@ -490,6 +561,7 @@ void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command) l2cap_signaling_handle_configure_request(channel, command); channel->state = L2CAP_STATE_OPEN; l2cap_emit_channel_opened(channel, 0); // success + l2cap_emit_credits(channel, 1); break; case DISCONNECTION_REQUEST: l2cap_handle_disconnect_request(channel, identifier); @@ -505,6 +577,7 @@ void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command) case CONFIGURE_RESPONSE: channel->state = L2CAP_STATE_OPEN; l2cap_emit_channel_opened(channel, 0); // success + l2cap_emit_credits(channel, 1); break; case DISCONNECTION_REQUEST: l2cap_handle_disconnect_request(channel, identifier); diff --git a/src/l2cap.h b/src/l2cap.h index d9be83bf2..3d112265d 100644 --- a/src/l2cap.h +++ b/src/l2cap.h @@ -73,6 +73,9 @@ typedef struct { uint16_t remote_mtu; uint16_t psm; + + uint8_t packets_granted; // number of L2CAP/ACL packets client is allowed to send + uint8_t packets_outgoing; // number of L2CAP/ACL packets send to BT module // uint16_t local_mtu; // uint16_t flush_timeout_incoming; @@ -109,7 +112,7 @@ void l2cap_init(); void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)); void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm); void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason); -void l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len); +int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len); uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid); void l2cap_finialize_channel_close(l2cap_channel_t *channel);