Bluetooth: BAP: Add unicast client and server write long support
Add support for long writes for the unicast client and server. This reuses the ATT buffer for long reads. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
486ea06fcb
commit
e8ade2356a
@ -11,6 +11,9 @@ CONFIG_BT_DEVICE_NAME="Hearing Aid sample"
|
||||
# Appearance: Generic Hearing aid (0x0A40)
|
||||
CONFIG_BT_DEVICE_APPEARANCE=2624
|
||||
|
||||
# Mandatory to support at least 1 for ASCS
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=1
|
||||
|
||||
CONFIG_BT_AUDIO=y
|
||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=1
|
||||
|
||||
@ -17,6 +17,8 @@ CONFIG_BT_CAP_ACCEPTOR=y
|
||||
|
||||
# BAP support
|
||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||
# Mandatory to support at least 1 for ASCS
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=1
|
||||
|
||||
# VCP support
|
||||
CONFIG_BT_VCP_VOL_REND=y
|
||||
|
||||
@ -8,5 +8,8 @@ CONFIG_BT_ASCS_ASE_SRC_COUNT=1
|
||||
# Support an ISO channel per ASE
|
||||
CONFIG_BT_ISO_MAX_CHAN=4
|
||||
|
||||
# Mandatory to support at least 1 for ASCS
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=1
|
||||
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_DEVICE_NAME="Unicast Audio Server"
|
||||
|
||||
@ -27,6 +27,8 @@ LOG_MODULE_REGISTER(bt_ascs, CONFIG_BT_ASCS_LOG_LEVEL);
|
||||
#include "common/bt_str.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
#include "../host/att_internal.h"
|
||||
|
||||
#include "audio_internal.h"
|
||||
#include "bap_iso.h"
|
||||
#include "bap_endpoint.h"
|
||||
@ -80,6 +82,19 @@ static struct bt_ascs_ase {
|
||||
MAX(MIN_CONFIG_STATE_SIZE + MAX_CODEC_CONFIG, \
|
||||
MIN_QOS_STATE_SIZE + MAX_METADATA))
|
||||
|
||||
/* Verify that the prepare count is large enough to cover the maximum value we support a client
|
||||
* writing
|
||||
*/
|
||||
BUILD_ASSERT(
|
||||
BT_ATT_BUF_SIZE - 3 >= ASE_BUF_SIZE ||
|
||||
DIV_ROUND_UP(ASE_BUF_SIZE, (BT_ATT_BUF_SIZE - 3)) <= CONFIG_BT_ATT_PREPARE_COUNT,
|
||||
"CONFIG_BT_ATT_PREPARE_COUNT not large enough to cover the maximum supported ASCS value");
|
||||
|
||||
/* It is mandatory to support long writes in ASCS unconditionally, and thus
|
||||
* CONFIG_BT_ATT_PREPARE_COUNT must be at least 1 to support the feature
|
||||
*/
|
||||
BUILD_ASSERT(CONFIG_BT_ATT_PREPARE_COUNT > 0, "CONFIG_BT_ATT_PREPARE_COUNT shall be at least 1");
|
||||
|
||||
static const struct bt_bap_unicast_server_cb *unicast_server_cb;
|
||||
|
||||
static K_SEM_DEFINE(ase_buf_sem, 1, 1);
|
||||
|
||||
@ -92,6 +92,7 @@ static struct unicast_client {
|
||||
union {
|
||||
struct bt_gatt_read_params read_params;
|
||||
struct bt_gatt_discover_params disc_params;
|
||||
struct bt_gatt_write_params write_params;
|
||||
};
|
||||
|
||||
/* The att_buf needs to use the maximum ATT attribute size as a single
|
||||
@ -129,7 +130,11 @@ static int unicast_client_send_start(struct bt_bap_ep *ep)
|
||||
struct net_buf_simple *buf;
|
||||
int err;
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_START_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(ep->stream->conn, BT_ASCS_START_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 1U;
|
||||
@ -1556,19 +1561,22 @@ static void unicast_client_ep_set_cp(struct bt_conn *conn, uint16_t handle)
|
||||
}
|
||||
}
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(ep_buf, CONFIG_BT_L2CAP_TX_MTU);
|
||||
|
||||
struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(uint8_t op)
|
||||
struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(struct bt_conn *conn, uint8_t op)
|
||||
{
|
||||
struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
|
||||
struct bt_ascs_ase_cp *hdr;
|
||||
|
||||
/* Reset buffer before using */
|
||||
net_buf_simple_reset(&ep_buf);
|
||||
if (client->busy) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdr = net_buf_simple_add(&ep_buf, sizeof(*hdr));
|
||||
/* Reset buffer before using */
|
||||
reset_att_buf(client);
|
||||
|
||||
hdr = net_buf_simple_add(&client->net_buf, sizeof(*hdr));
|
||||
hdr->op = op;
|
||||
|
||||
return &ep_buf;
|
||||
return &client->net_buf;
|
||||
}
|
||||
|
||||
static int unicast_client_ep_config(struct bt_bap_ep *ep, struct net_buf_simple *buf,
|
||||
@ -1822,16 +1830,60 @@ static int unicast_client_ep_release(struct bt_bap_ep *ep, struct net_buf_simple
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gatt_write_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params)
|
||||
{
|
||||
struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
|
||||
|
||||
LOG_DBG("conn %p err %u", conn, err);
|
||||
|
||||
memset(params, 0, sizeof(*params));
|
||||
client->busy = false;
|
||||
|
||||
/* TBD: Should we do anything in case of error here? */
|
||||
}
|
||||
|
||||
int bt_bap_unicast_client_ep_send(struct bt_conn *conn, struct bt_bap_ep *ep,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
const uint8_t att_write_header_size = 3; /* opcode (1) + handle (2) */
|
||||
const uint16_t max_write_size = bt_gatt_get_mtu(conn) - att_write_header_size;
|
||||
struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
|
||||
struct bt_bap_unicast_client_ep *client_ep =
|
||||
CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
|
||||
int err;
|
||||
|
||||
LOG_DBG("conn %p ep %p buf %p len %u", conn, ep, buf, buf->len);
|
||||
|
||||
return bt_gatt_write_without_response(conn, client_ep->cp_handle, buf->data, buf->len,
|
||||
false);
|
||||
if (buf->len > max_write_size) {
|
||||
if (client->busy) {
|
||||
LOG_DBG("Client connection is busy");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
client->write_params.func = gatt_write_cb;
|
||||
client->write_params.handle = client_ep->cp_handle;
|
||||
client->write_params.offset = 0U;
|
||||
client->write_params.data = buf->data;
|
||||
client->write_params.length = buf->len;
|
||||
#if defined(CONFIG_BT_EATT)
|
||||
client->write_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
|
||||
#endif /* CONFIG_BT_EATT */
|
||||
|
||||
err = bt_gatt_write(conn, &client->write_params);
|
||||
if (err != 0) {
|
||||
LOG_DBG("bt_gatt_write failed: %d", err);
|
||||
}
|
||||
|
||||
client->busy = true;
|
||||
} else {
|
||||
err = bt_gatt_write_without_response(conn, client_ep->cp_handle, buf->data,
|
||||
buf->len, false);
|
||||
if (err != 0) {
|
||||
LOG_DBG("bt_gatt_write_without_response failed: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void unicast_client_reset(struct bt_bap_ep *ep)
|
||||
@ -2523,7 +2575,11 @@ int bt_bap_unicast_client_config(struct bt_bap_stream *stream, const struct bt_c
|
||||
struct net_buf_simple *buf;
|
||||
int err;
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_CONFIG_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_CONFIG_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
op = net_buf_simple_add(buf, sizeof(*op));
|
||||
op->num_ases = 0x01;
|
||||
@ -2616,7 +2672,11 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group
|
||||
}
|
||||
|
||||
/* Generate the control point write */
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_QOS_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(conn, BT_ASCS_QOS_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
op = net_buf_simple_add(buf, sizeof(*op));
|
||||
|
||||
@ -2668,7 +2728,11 @@ int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_codec_d
|
||||
|
||||
LOG_DBG("stream %p", stream);
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_ENABLE_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_ENABLE_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x01;
|
||||
@ -2691,7 +2755,11 @@ int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_codec
|
||||
|
||||
LOG_DBG("stream %p", stream);
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_METADATA_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_METADATA_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x01;
|
||||
@ -2713,7 +2781,11 @@ int bt_bap_unicast_client_start(struct bt_bap_stream *stream)
|
||||
|
||||
LOG_DBG("stream %p", stream);
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_START_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_START_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x00;
|
||||
@ -2765,7 +2837,11 @@ int bt_bap_unicast_client_disable(struct bt_bap_stream *stream)
|
||||
|
||||
LOG_DBG("stream %p", stream);
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_DISABLE_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_DISABLE_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x01;
|
||||
@ -2787,7 +2863,11 @@ int bt_bap_unicast_client_stop(struct bt_bap_stream *stream)
|
||||
|
||||
LOG_DBG("stream %p", stream);
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_STOP_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_STOP_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x00;
|
||||
@ -2822,7 +2902,11 @@ int bt_bap_unicast_client_release(struct bt_bap_stream *stream)
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(BT_ASCS_RELEASE_OP);
|
||||
buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_RELEASE_OP);
|
||||
if (buf == NULL) {
|
||||
LOG_DBG("Could not create PDU");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x01;
|
||||
|
||||
@ -24,7 +24,7 @@ int bt_bap_unicast_client_stop(struct bt_bap_stream *stream);
|
||||
|
||||
int bt_bap_unicast_client_release(struct bt_bap_stream *stream);
|
||||
|
||||
struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(uint8_t op);
|
||||
struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(struct bt_conn *conn, uint8_t op);
|
||||
|
||||
int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *buf,
|
||||
struct bt_codec_qos *qos);
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
/* att_internal.h - Attribute protocol handling */
|
||||
|
||||
#include <zephyr/bluetooth/l2cap.h>
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
|
||||
@ -12,6 +12,9 @@ CONFIG_BT_ASCS_MAX_ACTIVE_ASES=1
|
||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
# Mandatory to support at least 1 for ASCS
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=1
|
||||
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
CONFIG_BT_ASCS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_ISO_LOG_LEVEL_DBG=y
|
||||
|
||||
@ -16,7 +16,7 @@ CONFIG_BT_L2CAP_ECRED=y
|
||||
CONFIG_BT_EATT=y
|
||||
CONFIG_BT_SIGNING=y
|
||||
CONFIG_BT_FIXED_PASSKEY=y
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=2
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=5
|
||||
CONFIG_BT_SHELL=y
|
||||
CONFIG_BT_DEVICE_NAME="audio test shell"
|
||||
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
|
||||
|
||||
@ -8,6 +8,7 @@ CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_DEVICE_NAME="bsim_test_audio"
|
||||
# TBS Client may require up to 12 buffers
|
||||
CONFIG_BT_L2CAP_TX_BUF_COUNT=12
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=5
|
||||
CONFIG_BT_MAX_CONN=5
|
||||
CONFIG_BT_MAX_PAIRED=5
|
||||
CONFIG_BT_GATT_DYNAMIC_DB=y
|
||||
|
||||
Loading…
Reference in New Issue
Block a user