mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-12 15:47:14 +00:00
add counters for flow control, channel credits event, return -1 if no space in BT module
This commit is contained in:
parent
c7a78ec387
commit
6218e6f12b
@ -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
|
||||
|
||||
|
@ -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){
|
||||
|
10
src/hci.c
10
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){
|
||||
|
81
src/l2cap.c
81
src/l2cap.c
@ -40,6 +40,7 @@
|
||||
#include "l2cap.h"
|
||||
#include "hci.h"
|
||||
#include "hci_dump.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
@ -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; i<packet[2];i++){
|
||||
handle = READ_BT_16(packet, 3 + 2*i);
|
||||
uint16_t num_packets = READ_BT_16(packet, 3 + packet[2]*2 + 2*i);
|
||||
while (num_packets) {
|
||||
num_packets--;
|
||||
// pick some slot
|
||||
l2cap_channel_t * oldest_channel = NULL;
|
||||
for (it = (linked_item_t *) &l2cap_channels; it->next ; 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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user