Bluetooth: Add support for tracking transmitted packets
Protocols/profiles may want to know when exactly their PDU has been transmitted over the air. To make this possible, introduce support for a callback that will get called when the controller reports that a packet has been transmitted (through the Number of Completed Packets HCI event). Change-Id: Ia3a19b93c5b2111f144bfabe5861187c41525f30 Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
ac9a2398d8
commit
4be4c60ab6
9 changed files with 182 additions and 39 deletions
|
@ -161,6 +161,15 @@ config BLUETOOTH_L2CAP_TX_MTU
|
||||||
help
|
help
|
||||||
Maximum L2CAP MTU for L2CAP TX buffers.
|
Maximum L2CAP MTU for L2CAP TX buffers.
|
||||||
|
|
||||||
|
config BLUETOOTH_CONN_TX_MAX
|
||||||
|
int "Maximum number of pending TX buffers"
|
||||||
|
default 7
|
||||||
|
default BLUETOOTH_CONTROLLER_TX_BUFFERS if BLUETOOTH_CONTROLLER
|
||||||
|
range 1 128
|
||||||
|
help
|
||||||
|
Maximum number of pending TX buffers that have not yet
|
||||||
|
been acknowledged by the controller.
|
||||||
|
|
||||||
config BLUETOOTH_L2CAP_TX_USER_DATA_SIZE
|
config BLUETOOTH_L2CAP_TX_USER_DATA_SIZE
|
||||||
int "Maximum supported user data size for L2CAP TX buffers"
|
int "Maximum supported user data size for L2CAP TX buffers"
|
||||||
default 4
|
default 4
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <atomic.h>
|
#include <atomic.h>
|
||||||
#include <misc/byteorder.h>
|
#include <misc/byteorder.h>
|
||||||
#include <misc/util.h>
|
#include <misc/util.h>
|
||||||
|
#include <misc/slist.h>
|
||||||
#include <misc/stack.h>
|
#include <misc/stack.h>
|
||||||
#include <misc/__assert.h>
|
#include <misc/__assert.h>
|
||||||
|
|
||||||
|
@ -44,6 +45,16 @@ const struct bt_conn_auth_cb *bt_auth;
|
||||||
|
|
||||||
static struct bt_conn conns[CONFIG_BLUETOOTH_MAX_CONN];
|
static struct bt_conn conns[CONFIG_BLUETOOTH_MAX_CONN];
|
||||||
static struct bt_conn_cb *callback_list;
|
static struct bt_conn_cb *callback_list;
|
||||||
|
|
||||||
|
struct conn_tx_cb {
|
||||||
|
bt_conn_tx_cb_t cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define conn_tx(buf) ((struct conn_tx_cb *)net_buf_user_data(buf))
|
||||||
|
|
||||||
|
static struct bt_conn_tx conn_tx[CONFIG_BLUETOOTH_CONN_TX_MAX];
|
||||||
|
static sys_slist_t free_tx = SYS_SLIST_STATIC_INIT(&free_tx);
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_BREDR)
|
#if defined(CONFIG_BLUETOOTH_BREDR)
|
||||||
static struct bt_conn sco_conns[CONFIG_BLUETOOTH_MAX_SCO_CONN];
|
static struct bt_conn sco_conns[CONFIG_BLUETOOTH_MAX_SCO_CONN];
|
||||||
|
|
||||||
|
@ -1040,9 +1051,10 @@ void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
|
||||||
bt_l2cap_recv(conn, buf);
|
bt_l2cap_recv(conn, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_conn_send(struct bt_conn *conn, struct net_buf *buf)
|
int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
|
||||||
|
bt_conn_tx_cb_t cb)
|
||||||
{
|
{
|
||||||
BT_DBG("conn handle %u buf len %u", conn->handle, buf->len);
|
BT_DBG("conn handle %u buf len %u cb %p", conn->handle, buf->len, cb);
|
||||||
|
|
||||||
if (buf->pool->user_data_size < BT_BUF_USER_DATA_MIN) {
|
if (buf->pool->user_data_size < BT_BUF_USER_DATA_MIN) {
|
||||||
BT_ERR("Too small user data size");
|
BT_ERR("Too small user data size");
|
||||||
|
@ -1056,14 +1068,55 @@ int bt_conn_send(struct bt_conn *conn, struct net_buf *buf)
|
||||||
return -ENOTCONN;
|
return -ENOTCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn_tx(buf)->cb = cb;
|
||||||
|
|
||||||
net_buf_put(&conn->tx_queue, buf);
|
net_buf_put(&conn->tx_queue, buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tx_free(struct bt_conn_tx *tx)
|
||||||
|
{
|
||||||
|
tx->cb = NULL;
|
||||||
|
sys_slist_prepend(&free_tx, &tx->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_conn_notify_tx(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
struct bt_conn_tx *tx;
|
||||||
|
|
||||||
|
BT_DBG("conn %p", conn);
|
||||||
|
|
||||||
|
while ((tx = k_fifo_get(&conn->tx_notify, K_NO_WAIT))) {
|
||||||
|
if (tx->cb) {
|
||||||
|
tx->cb(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_free(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_pending_tx(struct bt_conn *conn, bt_conn_tx_cb_t cb)
|
||||||
|
{
|
||||||
|
sys_snode_t *node;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
BT_DBG("conn %p cb %p", conn, cb);
|
||||||
|
|
||||||
|
__ASSERT(!sys_slist_is_empty(&free_tx), "No free conn TX contexts");
|
||||||
|
|
||||||
|
node = sys_slist_get_not_empty(&free_tx);
|
||||||
|
CONTAINER_OF(node, struct bt_conn_tx, node)->cb = cb;
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
|
sys_slist_append(&conn->tx_pending, node);
|
||||||
|
irq_unlock(key);
|
||||||
|
}
|
||||||
|
|
||||||
static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
|
static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
|
||||||
bool always_consume)
|
bool always_consume)
|
||||||
{
|
{
|
||||||
struct bt_hci_acl_hdr *hdr;
|
struct bt_hci_acl_hdr *hdr;
|
||||||
|
bt_conn_tx_cb_t cb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len,
|
BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len,
|
||||||
|
@ -1072,6 +1125,9 @@ static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
|
||||||
/* Wait until the controller can accept ACL packets */
|
/* Wait until the controller can accept ACL packets */
|
||||||
k_sem_take(bt_conn_get_pkts(conn), K_FOREVER);
|
k_sem_take(bt_conn_get_pkts(conn), K_FOREVER);
|
||||||
|
|
||||||
|
/* Make sure we notify and free up any pending tx contexts */
|
||||||
|
bt_conn_notify_tx(conn);
|
||||||
|
|
||||||
/* Check for disconnection while waiting for pkts_sem */
|
/* Check for disconnection while waiting for pkts_sem */
|
||||||
if (conn->state != BT_CONN_CONNECTED) {
|
if (conn->state != BT_CONN_CONNECTED) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1081,6 +1137,7 @@ static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
|
||||||
hdr->handle = sys_cpu_to_le16(bt_acl_handle_pack(conn->handle, flags));
|
hdr->handle = sys_cpu_to_le16(bt_acl_handle_pack(conn->handle, flags));
|
||||||
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));
|
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));
|
||||||
|
|
||||||
|
cb = conn_tx(buf)->cb;
|
||||||
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
||||||
|
|
||||||
err = bt_send(buf);
|
err = bt_send(buf);
|
||||||
|
@ -1089,7 +1146,7 @@ static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->pending_pkts++;
|
add_pending_tx(conn, cb);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -1123,6 +1180,9 @@ static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fragments never have a TX completion callback */
|
||||||
|
conn_tx(frag)->cb = NULL;
|
||||||
|
|
||||||
frag_len = min(conn_mtu(conn), net_buf_tailroom(frag));
|
frag_len = min(conn_mtu(conn), net_buf_tailroom(frag));
|
||||||
|
|
||||||
net_buf_add_mem(frag, buf->data, frag_len);
|
net_buf_add_mem(frag, buf->data, frag_len);
|
||||||
|
@ -1181,7 +1241,7 @@ static void conn_cleanup(struct bt_conn *conn)
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
BT_ASSERT(!conn->pending_pkts);
|
__ASSERT(sys_slist_is_empty(&conn->tx_pending), "Pending TX packets");
|
||||||
|
|
||||||
bt_conn_reset_rx_state(conn);
|
bt_conn_reset_rx_state(conn);
|
||||||
|
|
||||||
|
@ -1224,7 +1284,13 @@ int bt_conn_prepare_events(struct k_poll_event events[])
|
||||||
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||||
K_POLL_MODE_NOTIFY_ONLY,
|
K_POLL_MODE_NOTIFY_ONLY,
|
||||||
&conn->tx_queue);
|
&conn->tx_queue);
|
||||||
events[ev_count++].tag = BT_EVENT_CONN_TX;
|
events[ev_count++].tag = BT_EVENT_CONN_TX_QUEUE;
|
||||||
|
|
||||||
|
k_poll_event_init(&events[ev_count],
|
||||||
|
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||||
|
K_POLL_MODE_NOTIFY_ONLY,
|
||||||
|
&conn->tx_notify);
|
||||||
|
events[ev_count++].tag = BT_EVENT_CONN_TX_NOTIFY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ev_count;
|
return ev_count;
|
||||||
|
@ -1272,6 +1338,27 @@ struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer)
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void process_unack_tx(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
/* Return any unacknowledged packets */
|
||||||
|
while (1) {
|
||||||
|
sys_snode_t *node;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
|
node = sys_slist_get(&conn->tx_pending);
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_free(CONTAINER_OF(node, struct bt_conn_tx, node));
|
||||||
|
|
||||||
|
k_sem_give(bt_conn_get_pkts(conn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
||||||
{
|
{
|
||||||
bt_conn_state_t old_state;
|
bt_conn_state_t old_state;
|
||||||
|
@ -1313,6 +1400,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
k_fifo_init(&conn->tx_queue);
|
k_fifo_init(&conn->tx_queue);
|
||||||
|
k_fifo_init(&conn->tx_notify);
|
||||||
k_poll_signal(&conn_change, 0);
|
k_poll_signal(&conn_change, 0);
|
||||||
|
|
||||||
sys_slist_init(&conn->channels);
|
sys_slist_init(&conn->channels);
|
||||||
|
@ -1334,12 +1422,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
||||||
old_state == BT_CONN_DISCONNECT) {
|
old_state == BT_CONN_DISCONNECT) {
|
||||||
bt_l2cap_disconnected(conn);
|
bt_l2cap_disconnected(conn);
|
||||||
notify_disconnected(conn);
|
notify_disconnected(conn);
|
||||||
|
process_unack_tx(conn);
|
||||||
/* Return any unacknowledged packets */
|
|
||||||
while (conn->pending_pkts) {
|
|
||||||
k_sem_give(bt_conn_get_pkts(conn));
|
|
||||||
conn->pending_pkts--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel Connection Update if it is pending */
|
/* Cancel Connection Update if it is pending */
|
||||||
if (conn->type == BT_CONN_TYPE_LE) {
|
if (conn->type == BT_CONN_TYPE_LE) {
|
||||||
|
@ -1944,7 +2027,11 @@ int bt_conn_auth_pairing_confirm(struct bt_conn *conn)
|
||||||
|
|
||||||
int bt_conn_init(void)
|
int bt_conn_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err, i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(conn_tx); i++) {
|
||||||
|
sys_slist_prepend(&free_tx, &conn_tx[i].node);
|
||||||
|
}
|
||||||
|
|
||||||
bt_att_init();
|
bt_att_init();
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,13 @@ struct bt_conn_sco {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef void (*bt_conn_tx_cb_t)(struct bt_conn *conn);
|
||||||
|
|
||||||
|
struct bt_conn_tx {
|
||||||
|
sys_snode_t node;
|
||||||
|
bt_conn_tx_cb_t cb;
|
||||||
|
};
|
||||||
|
|
||||||
struct bt_conn {
|
struct bt_conn {
|
||||||
uint16_t handle;
|
uint16_t handle;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
@ -85,11 +92,14 @@ struct bt_conn {
|
||||||
uint8_t encrypt;
|
uint8_t encrypt;
|
||||||
#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */
|
#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */
|
||||||
|
|
||||||
uint8_t pending_pkts;
|
|
||||||
|
|
||||||
uint16_t rx_len;
|
uint16_t rx_len;
|
||||||
struct net_buf *rx;
|
struct net_buf *rx;
|
||||||
|
|
||||||
|
/* Sent but not acknowledged TX packets */
|
||||||
|
sys_slist_t tx_pending;
|
||||||
|
/* Acknowledged but not yet notified TX packets */
|
||||||
|
struct k_fifo tx_notify;
|
||||||
|
|
||||||
/* Queue for outgoing ACL data */
|
/* Queue for outgoing ACL data */
|
||||||
struct k_fifo tx_queue;
|
struct k_fifo tx_queue;
|
||||||
|
|
||||||
|
@ -116,7 +126,13 @@ struct bt_conn {
|
||||||
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags);
|
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags);
|
||||||
|
|
||||||
/* Send data over a connection */
|
/* Send data over a connection */
|
||||||
int bt_conn_send(struct bt_conn *conn, struct net_buf *buf);
|
int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
|
||||||
|
bt_conn_tx_cb_t cb);
|
||||||
|
|
||||||
|
static inline int bt_conn_send(struct bt_conn *conn, struct net_buf *buf)
|
||||||
|
{
|
||||||
|
return bt_conn_send_cb(conn, buf, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add a new LE connection */
|
/* Add a new LE connection */
|
||||||
struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer);
|
struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer);
|
||||||
|
@ -191,3 +207,4 @@ struct k_sem *bt_conn_get_pkts(struct bt_conn *conn);
|
||||||
/* k_poll related helpers for the TX thread */
|
/* k_poll related helpers for the TX thread */
|
||||||
int bt_conn_prepare_events(struct k_poll_event events[]);
|
int bt_conn_prepare_events(struct k_poll_event events[]);
|
||||||
void bt_conn_process_tx(struct bt_conn *conn);
|
void bt_conn_process_tx(struct bt_conn *conn);
|
||||||
|
void bt_conn_notify_tx(struct bt_conn *conn);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <atomic.h>
|
#include <atomic.h>
|
||||||
#include <misc/util.h>
|
#include <misc/util.h>
|
||||||
|
#include <misc/slist.h>
|
||||||
#include <misc/byteorder.h>
|
#include <misc/byteorder.h>
|
||||||
#include <misc/stack.h>
|
#include <misc/stack.h>
|
||||||
#include <misc/__assert.h>
|
#include <misc/__assert.h>
|
||||||
|
@ -489,17 +490,21 @@ static void hci_num_completed_packets(struct net_buf *buf)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->pending_pkts >= count) {
|
|
||||||
conn->pending_pkts -= count;
|
|
||||||
} else {
|
|
||||||
BT_ERR("completed packets mismatch: %u > %u",
|
|
||||||
count, conn->pending_pkts);
|
|
||||||
conn->pending_pkts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
sys_snode_t *node;
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
|
node = sys_slist_get(&conn->tx_pending);
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
BT_ERR("packets count mismatch");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_fifo_put(&conn->tx_notify, node);
|
||||||
k_sem_give(bt_conn_get_pkts(conn));
|
k_sem_give(bt_conn_get_pkts(conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2727,13 +2732,20 @@ static void process_events(struct k_poll_event *ev, int count)
|
||||||
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
|
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
|
||||||
if (ev->tag == BT_EVENT_CMD_TX) {
|
if (ev->tag == BT_EVENT_CMD_TX) {
|
||||||
send_cmd();
|
send_cmd();
|
||||||
} else if (IS_ENABLED(CONFIG_BLUETOOTH_CONN) &&
|
} else if (IS_ENABLED(CONFIG_BLUETOOTH_CONN)) {
|
||||||
ev->tag == BT_EVENT_CONN_TX) {
|
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
|
|
||||||
conn = CONTAINER_OF(ev->fifo, struct bt_conn,
|
if (ev->tag == BT_EVENT_CONN_TX_NOTIFY) {
|
||||||
tx_queue);
|
conn = CONTAINER_OF(ev->fifo,
|
||||||
bt_conn_process_tx(conn);
|
struct bt_conn,
|
||||||
|
tx_notify);
|
||||||
|
bt_conn_notify_tx(conn);
|
||||||
|
} else if (ev->tag == BT_EVENT_CONN_TX_QUEUE) {
|
||||||
|
conn = CONTAINER_OF(ev->fifo,
|
||||||
|
struct bt_conn,
|
||||||
|
tx_queue);
|
||||||
|
bt_conn_process_tx(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case K_POLL_STATE_NOT_READY:
|
case K_POLL_STATE_NOT_READY:
|
||||||
|
@ -2746,8 +2758,8 @@ static void process_events(struct k_poll_event *ev, int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_CONN)
|
#if defined(CONFIG_BLUETOOTH_CONN)
|
||||||
/* command FIFO + conn_change signal + MAX_CONN */
|
/* command FIFO + conn_change signal + MAX_CONN * 2 (tx & tx_notify) */
|
||||||
#define EV_COUNT (2 + CONFIG_BLUETOOTH_MAX_CONN)
|
#define EV_COUNT (2 + (CONFIG_BLUETOOTH_MAX_CONN * 2))
|
||||||
#else
|
#else
|
||||||
/* command FIFO */
|
/* command FIFO */
|
||||||
#define EV_COUNT 1
|
#define EV_COUNT 1
|
||||||
|
@ -2854,6 +2866,8 @@ static void read_buffer_size_complete(struct net_buf *buf)
|
||||||
|
|
||||||
BT_DBG("ACL BR/EDR buffers: pkts %u mtu %u", pkts, bt_dev.le.mtu);
|
BT_DBG("ACL BR/EDR buffers: pkts %u mtu %u", pkts, bt_dev.le.mtu);
|
||||||
|
|
||||||
|
pkts = min(pkts, CONFIG_BLUETOOTH_CONN_TX_MAX);
|
||||||
|
|
||||||
k_sem_init(&bt_dev.le.pkts, pkts, pkts);
|
k_sem_init(&bt_dev.le.pkts, pkts, pkts);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2862,16 +2876,19 @@ static void read_buffer_size_complete(struct net_buf *buf)
|
||||||
static void le_read_buffer_size_complete(struct net_buf *buf)
|
static void le_read_buffer_size_complete(struct net_buf *buf)
|
||||||
{
|
{
|
||||||
struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data;
|
struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data;
|
||||||
|
uint8_t le_max_num;
|
||||||
|
|
||||||
BT_DBG("status %u", rp->status);
|
BT_DBG("status %u", rp->status);
|
||||||
|
|
||||||
bt_dev.le.mtu = sys_le16_to_cpu(rp->le_max_len);
|
bt_dev.le.mtu = sys_le16_to_cpu(rp->le_max_len);
|
||||||
|
if (!bt_dev.le.mtu) {
|
||||||
if (bt_dev.le.mtu) {
|
return;
|
||||||
k_sem_init(&bt_dev.le.pkts, rp->le_max_num, rp->le_max_num);
|
|
||||||
BT_DBG("ACL LE buffers: pkts %u mtu %u", rp->le_max_num,
|
|
||||||
bt_dev.le.mtu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BT_DBG("ACL LE buffers: pkts %u mtu %u", rp->le_max_num, bt_dev.le.mtu);
|
||||||
|
|
||||||
|
le_max_num = min(rp->le_max_num, CONFIG_BLUETOOTH_CONN_TX_MAX);
|
||||||
|
k_sem_init(&bt_dev.le.pkts, le_max_num, le_max_num);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@
|
||||||
/* k_poll event tags */
|
/* k_poll event tags */
|
||||||
enum {
|
enum {
|
||||||
BT_EVENT_CMD_TX,
|
BT_EVENT_CMD_TX,
|
||||||
BT_EVENT_CONN_TX,
|
BT_EVENT_CONN_TX_NOTIFY,
|
||||||
|
BT_EVENT_CONN_TX_QUEUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* bt_dev flags: the flags defined here represent BT controller state */
|
/* bt_dev flags: the flags defined here represent BT controller state */
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <bluetooth/rfcomm.h>
|
#include <bluetooth/rfcomm.h>
|
||||||
#include <bluetooth/hfp_hf.h>
|
#include <bluetooth/hfp_hf.h>
|
||||||
|
|
||||||
|
#include "hci_core.h"
|
||||||
|
#include "conn_internal.h"
|
||||||
#include "l2cap_internal.h"
|
#include "l2cap_internal.h"
|
||||||
#include "rfcomm_internal.h"
|
#include "rfcomm_internal.h"
|
||||||
#include "at.h"
|
#include "at.h"
|
||||||
|
|
|
@ -464,7 +464,8 @@ struct net_buf *bt_l2cap_create_pdu(struct net_buf_pool *pool, size_t reserve)
|
||||||
return bt_conn_create_pdu(pool, sizeof(struct bt_l2cap_hdr) + reserve);
|
return bt_conn_create_pdu(pool, sizeof(struct bt_l2cap_hdr) + reserve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf)
|
void bt_l2cap_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf,
|
||||||
|
bt_conn_tx_cb_t cb)
|
||||||
{
|
{
|
||||||
struct bt_l2cap_hdr *hdr;
|
struct bt_l2cap_hdr *hdr;
|
||||||
|
|
||||||
|
@ -474,7 +475,7 @@ void bt_l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf)
|
||||||
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));
|
hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr));
|
||||||
hdr->cid = sys_cpu_to_le16(cid);
|
hdr->cid = sys_cpu_to_le16(cid);
|
||||||
|
|
||||||
bt_conn_send(conn, buf);
|
bt_conn_send_cb(conn, buf, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void l2cap_send_reject(struct bt_conn *conn, uint8_t ident,
|
static void l2cap_send_reject(struct bt_conn *conn, uint8_t ident,
|
||||||
|
|
|
@ -247,7 +247,14 @@ struct net_buf *bt_l2cap_create_pdu(struct net_buf_pool *pool, size_t reserve);
|
||||||
struct net_buf *bt_l2cap_create_rsp(struct net_buf *buf, size_t reserve);
|
struct net_buf *bt_l2cap_create_rsp(struct net_buf *buf, size_t reserve);
|
||||||
|
|
||||||
/* Send L2CAP PDU over a connection */
|
/* Send L2CAP PDU over a connection */
|
||||||
void bt_l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf);
|
void bt_l2cap_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf,
|
||||||
|
bt_conn_tx_cb_t cb);
|
||||||
|
|
||||||
|
static inline void bt_l2cap_send(struct bt_conn *conn, uint16_t cid,
|
||||||
|
struct net_buf *buf)
|
||||||
|
{
|
||||||
|
bt_l2cap_send_cb(conn, cid, buf, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Receive a new L2CAP PDU from a connection */
|
/* Receive a new L2CAP PDU from a connection */
|
||||||
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf);
|
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf);
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <bluetooth/log.h>
|
#include <bluetooth/log.h>
|
||||||
#include <bluetooth/sdp.h>
|
#include <bluetooth/sdp.h>
|
||||||
|
|
||||||
|
#include "hci_core.h"
|
||||||
|
#include "conn_internal.h"
|
||||||
#include "l2cap_internal.h"
|
#include "l2cap_internal.h"
|
||||||
#include "sdp_internal.h"
|
#include "sdp_internal.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue