Bluetooth: BAP: BA: Replace bools with atomic
Replace the boolean values for the BAP Broadcast Assistant with an atomic value. This prevents a rare, but possible, race condition. The busy flag has been replaced with 3 atomic values which provide better granularity in error handling, and allows for some concurrent write and read requests. To describe the new behavior, the return values in the documentation has been updated, and the error handling in the API functions has improved. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
081aa2fc94
commit
ae6c20d324
3 changed files with 255 additions and 93 deletions
|
@ -2321,7 +2321,13 @@ struct bt_bap_broadcast_assistant_cb {
|
|||
* new connection, will delete all previous data.
|
||||
*
|
||||
* @param conn The connection
|
||||
* @return int Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
*
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_discover(struct bt_conn *conn);
|
||||
|
||||
|
@ -2340,7 +2346,14 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn);
|
|||
* Used to let the server know that we are scanning.
|
||||
* @param start_scan Start scanning if true. If false, the application should
|
||||
* enable scan itself.
|
||||
* @return int Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL of if @p conn has not done discovery
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -EAGAIN Bluetooth has not been enabled.
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn,
|
||||
bool start_scan);
|
||||
|
@ -2349,7 +2362,14 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn,
|
|||
* @brief Stop remote scanning for BISes for a server.
|
||||
*
|
||||
* @param conn Connection to the server.
|
||||
* @return int Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL of if @p conn has not done discovery
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -EAGAIN Bluetooth has not been enabled.
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn);
|
||||
|
||||
|
@ -2410,7 +2430,12 @@ struct bt_bap_broadcast_assistant_add_src_param {
|
|||
* @param conn Connection to the server.
|
||||
* @param param Parameter struct.
|
||||
*
|
||||
* @return Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL or %p conn has not done discovery or if @p param is invalid
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_add_src(
|
||||
struct bt_conn *conn, const struct bt_bap_broadcast_assistant_add_src_param *param);
|
||||
|
@ -2443,7 +2468,12 @@ struct bt_bap_broadcast_assistant_mod_src_param {
|
|||
* @param conn Connection to the server.
|
||||
* @param param Parameter struct.
|
||||
*
|
||||
* @return Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL or %p conn has not done discovery or if @p param is invalid
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_mod_src(
|
||||
struct bt_conn *conn, const struct bt_bap_broadcast_assistant_mod_src_param *param);
|
||||
|
@ -2455,7 +2485,12 @@ int bt_bap_broadcast_assistant_mod_src(
|
|||
* @param src_id Source ID of the receive state.
|
||||
* @param broadcast_code The broadcast code.
|
||||
*
|
||||
* @return Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL or %p conn has not done discovery or @p src_id is invalid
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_set_broadcast_code(
|
||||
struct bt_conn *conn, uint8_t src_id,
|
||||
|
@ -2467,7 +2502,12 @@ int bt_bap_broadcast_assistant_set_broadcast_code(
|
|||
* @param conn Connection to the server.
|
||||
* @param src_id Source ID of the receive state.
|
||||
*
|
||||
* @return Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL or %p conn has not done discovery or @p src_id is invalid
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id);
|
||||
|
||||
|
@ -2478,7 +2518,12 @@ int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id);
|
|||
* @param idx The index of the receive start (0 up to the value from
|
||||
* bt_bap_broadcast_assistant_discover_cb)
|
||||
*
|
||||
* @return Error value. 0 on success, GATT error or ERRNO on fail.
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL @p conn is NULL or %p conn has not done discovery or @p src_id is invalid
|
||||
* @retval -EBUSY Another operation is already in progress for this @p conn
|
||||
* @retval -ENOTCONN @p conn is not connected
|
||||
* @retval -ENOMEM Could not allocated memory for the request
|
||||
* @retval -ENOEXEC Unexpected scan or GATT error
|
||||
*/
|
||||
int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn, uint8_t idx);
|
||||
|
||||
|
|
|
@ -62,6 +62,14 @@ struct bap_broadcast_assistant_recv_state_info {
|
|||
bt_addr_le_t addr;
|
||||
};
|
||||
|
||||
enum bap_broadcast_assistant_flag {
|
||||
BAP_BA_FLAG_BUSY,
|
||||
BAP_BA_FLAG_DISCOVER_IN_PROGRESS,
|
||||
BAP_BA_FLAG_SCANNING,
|
||||
|
||||
BAP_BA_FLAG_NUM_FLAGS, /* keep as last */
|
||||
};
|
||||
|
||||
struct bap_broadcast_assistant_instance {
|
||||
struct bt_conn *conn;
|
||||
bool scanning;
|
||||
|
@ -73,20 +81,27 @@ struct bap_broadcast_assistant_instance {
|
|||
uint16_t cp_handle;
|
||||
uint16_t recv_state_handles[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
|
||||
|
||||
bool busy;
|
||||
struct bt_gatt_subscribe_params recv_state_sub_params
|
||||
[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
|
||||
struct bt_gatt_discover_params recv_state_disc_params
|
||||
[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
|
||||
struct bt_gatt_read_params read_params;
|
||||
struct bt_gatt_write_params write_params;
|
||||
struct bt_gatt_discover_params disc_params;
|
||||
struct bt_gatt_discover_params
|
||||
recv_state_disc_params[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
|
||||
|
||||
/* We ever only allow a single outstanding operation per instance, so we can resuse the
|
||||
* memory for the GATT params
|
||||
*/
|
||||
union {
|
||||
struct bt_gatt_read_params read_params;
|
||||
struct bt_gatt_write_params write_params;
|
||||
struct bt_gatt_discover_params disc_params;
|
||||
};
|
||||
|
||||
struct k_work_delayable bap_read_work;
|
||||
uint16_t long_read_handle;
|
||||
|
||||
struct bap_broadcast_assistant_recv_state_info recv_states
|
||||
[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
|
||||
struct bap_broadcast_assistant_recv_state_info
|
||||
recv_states[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
|
||||
|
||||
ATOMIC_DEFINE(flags, BAP_BA_FLAG_NUM_FLAGS);
|
||||
};
|
||||
|
||||
static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs);
|
||||
|
@ -97,6 +112,8 @@ static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
|
|||
#define ATT_BUF_SIZE BT_ATT_MAX_ATTRIBUTE_LEN
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(att_buf, ATT_BUF_SIZE);
|
||||
|
||||
static int read_recv_state(struct bap_broadcast_assistant_instance *inst, uint8_t idx);
|
||||
|
||||
static int16_t lookup_index_by_handle(struct bap_broadcast_assistant_instance *inst,
|
||||
uint16_t handle)
|
||||
{
|
||||
|
@ -132,8 +149,15 @@ static struct bap_broadcast_assistant_instance *inst_by_conn(struct bt_conn *con
|
|||
static void bap_broadcast_assistant_discover_complete(struct bt_conn *conn, int err,
|
||||
uint8_t recv_state_count)
|
||||
{
|
||||
struct bap_broadcast_assistant_instance *inst = inst_by_conn(conn);
|
||||
struct bt_bap_broadcast_assistant_cb *listener, *next;
|
||||
|
||||
net_buf_simple_reset(&att_buf);
|
||||
if (inst != NULL) {
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS);
|
||||
}
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs,
|
||||
listener, next, _node) {
|
||||
if (listener->discover) {
|
||||
|
@ -299,11 +323,11 @@ static int parse_recv_state(const void *data, uint16_t length,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bap_long_op_reset(struct bap_broadcast_assistant_instance *inst)
|
||||
static void bap_long_read_reset(struct bap_broadcast_assistant_instance *inst)
|
||||
{
|
||||
inst->busy = false;
|
||||
inst->long_read_handle = 0;
|
||||
net_buf_simple_reset(&att_buf);
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
}
|
||||
|
||||
static uint8_t parse_and_send_recv_state(struct bt_conn *conn, uint16_t handle,
|
||||
|
@ -359,7 +383,7 @@ static uint8_t broadcast_assistant_bap_ntf_read_func(struct bt_conn *conn, uint8
|
|||
if (err) {
|
||||
LOG_DBG("Failed to read: %u", err);
|
||||
memset(read, 0, sizeof(*read));
|
||||
bap_long_op_reset(inst);
|
||||
bap_long_read_reset(inst);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -371,7 +395,7 @@ static uint8_t broadcast_assistant_bap_ntf_read_func(struct bt_conn *conn, uint8
|
|||
LOG_DBG("Buffer full, invalid server response of size %u",
|
||||
length + att_buf.len);
|
||||
memset(read, 0, sizeof(*read));
|
||||
bap_long_op_reset(inst);
|
||||
bap_long_read_reset(inst);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -385,11 +409,10 @@ static uint8_t broadcast_assistant_bap_ntf_read_func(struct bt_conn *conn, uint8
|
|||
/* we reset the buffer so that it is ready for new data */
|
||||
memset(read, 0, sizeof(*read));
|
||||
data_length = att_buf.len;
|
||||
bap_long_op_reset(inst);
|
||||
bap_long_read_reset(inst);
|
||||
|
||||
/* do the parse and callback to send notify to application*/
|
||||
parse_and_send_recv_state(conn, handle,
|
||||
att_buf.data, data_length, &recv_state);
|
||||
parse_and_send_recv_state(conn, handle, att_buf.data, data_length, &recv_state);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
@ -403,12 +426,10 @@ static void long_bap_read(struct bt_conn *conn, uint16_t handle)
|
|||
return;
|
||||
}
|
||||
|
||||
if (inst->busy) {
|
||||
LOG_DBG("conn %p busy %u", conn, inst->busy);
|
||||
if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("conn %p", conn);
|
||||
|
||||
/* If the client is busy reading or writing something else, reschedule the
|
||||
* long read.
|
||||
*/
|
||||
/* If the client is busy reading reschedule the long read */
|
||||
struct bt_conn_info conn_info;
|
||||
|
||||
err = bt_conn_get_info(conn, &conn_info);
|
||||
|
@ -423,7 +444,7 @@ static void long_bap_read(struct bt_conn *conn, uint16_t handle)
|
|||
K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval)));
|
||||
if (err < 0) {
|
||||
LOG_DBG("Failed to reschedule read work: %d", err);
|
||||
bap_long_op_reset(inst);
|
||||
bap_long_read_reset(inst);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -436,10 +457,9 @@ static void long_bap_read(struct bt_conn *conn, uint16_t handle)
|
|||
|
||||
err = bt_gatt_read(conn, &inst->read_params);
|
||||
if (err != 0) {
|
||||
/* TODO: If read failed due to buffers, retry */
|
||||
LOG_DBG("Failed to read: %d", err);
|
||||
bap_long_op_reset(inst);
|
||||
} else {
|
||||
inst->busy = true;
|
||||
bap_long_read_reset(inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,6 +492,11 @@ static uint8_t notify_handler(struct bt_conn *conn,
|
|||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) {
|
||||
/* If we are discovering then we ignore notifications as the handles may change */
|
||||
return BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
LOG_DBG("[UNSUBSCRIBED] %u", handle);
|
||||
params->value_handle = 0U;
|
||||
|
@ -503,9 +528,10 @@ static uint8_t notify_handler(struct bt_conn *conn,
|
|||
*/
|
||||
inst->long_read_handle = handle;
|
||||
|
||||
if (!inst->busy) {
|
||||
if (!atomic_test_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
net_buf_simple_add_mem(&att_buf, data, length);
|
||||
}
|
||||
|
||||
long_bap_read(conn, handle);
|
||||
} else {
|
||||
return parse_and_send_recv_state(conn, handle, data, length, &recv_state);
|
||||
|
@ -570,45 +596,57 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err,
|
|||
if (cb_err != 0) {
|
||||
LOG_DBG("err %d", cb_err);
|
||||
|
||||
if (inst->busy) {
|
||||
inst->busy = false;
|
||||
if (atomic_test_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) {
|
||||
bap_broadcast_assistant_discover_complete(conn, cb_err, 0);
|
||||
} else {
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
bap_broadcast_assistant_recv_state_changed(conn, cb_err, NULL);
|
||||
}
|
||||
} else if (handle == last_handle) {
|
||||
if (inst->busy) {
|
||||
if (atomic_test_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) {
|
||||
const uint8_t recv_state_cnt = inst->recv_state_cnt;
|
||||
|
||||
inst->busy = false;
|
||||
bap_broadcast_assistant_discover_complete(conn, cb_err, recv_state_cnt);
|
||||
} else {
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
bap_broadcast_assistant_recv_state_changed(conn, cb_err,
|
||||
active_recv_state ?
|
||||
&recv_state : NULL);
|
||||
}
|
||||
} else {
|
||||
for (uint8_t i = 0U; i < inst->recv_state_cnt; i++) {
|
||||
if (handle == inst->recv_state_handles[i]) {
|
||||
if (i + 1 < ARRAY_SIZE(inst->recv_state_handles)) {
|
||||
(void)bt_bap_broadcast_assistant_read_recv_state(conn,
|
||||
i + 1);
|
||||
}
|
||||
break;
|
||||
if (handle != inst->recv_state_handles[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 1 < ARRAY_SIZE(inst->recv_state_handles)) {
|
||||
cb_err = read_recv_state(inst, i + 1);
|
||||
if (cb_err != 0) {
|
||||
LOG_DBG("Failed to read receive state: %d", cb_err);
|
||||
|
||||
if (atomic_test_bit(inst->flags,
|
||||
BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) {
|
||||
bap_broadcast_assistant_discover_complete(
|
||||
conn, cb_err, 0);
|
||||
} else {
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
bap_broadcast_assistant_recv_state_changed(
|
||||
conn, cb_err, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
static void discover_init(void)
|
||||
static void discover_init(struct bap_broadcast_assistant_instance *inst)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(broadcast_assistants); i++) {
|
||||
k_work_init_delayable(&broadcast_assistants[i].bap_read_work,
|
||||
delayed_bap_read_handler);
|
||||
}
|
||||
k_work_init_delayable(&inst->bap_read_work, delayed_bap_read_handler);
|
||||
net_buf_simple_reset(&att_buf);
|
||||
atomic_set_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,9 +670,8 @@ static uint8_t char_discover_func(struct bt_conn *conn,
|
|||
LOG_DBG("Found %u BASS receive states", inst->recv_state_cnt);
|
||||
(void)memset(params, 0, sizeof(*params));
|
||||
|
||||
err = bt_bap_broadcast_assistant_read_recv_state(conn, 0);
|
||||
err = read_recv_state(inst, 0);
|
||||
if (err != 0) {
|
||||
inst->busy = false;
|
||||
bap_broadcast_assistant_discover_complete(conn, err, 0);
|
||||
}
|
||||
|
||||
|
@ -677,9 +714,6 @@ static uint8_t char_discover_func(struct bt_conn *conn,
|
|||
LOG_DBG("Could not subscribe to handle 0x%04x: %d",
|
||||
sub_params->value_handle, err);
|
||||
|
||||
inst->busy = false;
|
||||
LOG_DBG("no handle discover callback");
|
||||
|
||||
bap_broadcast_assistant_discover_complete(conn, err, 0);
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
|
@ -706,7 +740,6 @@ static uint8_t service_discover_func(struct bt_conn *conn,
|
|||
LOG_DBG("Could not discover BASS");
|
||||
(void)memset(params, 0, sizeof(*params));
|
||||
|
||||
inst->busy = false;
|
||||
err = BT_GATT_ERR(BT_ATT_ERR_NOT_SUPPORTED);
|
||||
|
||||
bap_broadcast_assistant_discover_complete(conn, err, 0);
|
||||
|
@ -730,7 +763,6 @@ static uint8_t service_discover_func(struct bt_conn *conn,
|
|||
err = bt_gatt_discover(conn, &inst->disc_params);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Discover failed (err %d)", err);
|
||||
inst->busy = false;
|
||||
bap_broadcast_assistant_discover_complete(conn, err, 0);
|
||||
}
|
||||
}
|
||||
|
@ -749,11 +781,11 @@ static void bap_broadcast_assistant_write_cp_cb(struct bt_conn *conn, uint8_t er
|
|||
return;
|
||||
}
|
||||
|
||||
inst->busy = false;
|
||||
|
||||
/* we reset the buffer, so that we are ready for new notifications and writes */
|
||||
net_buf_simple_reset(&att_buf);
|
||||
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
|
||||
switch (opcode) {
|
||||
case BT_BAP_BASS_OP_SCAN_STOP:
|
||||
|
@ -823,11 +855,18 @@ static int bt_bap_broadcast_assistant_common_cp(struct bt_conn *conn,
|
|||
inst->write_params.func = bap_broadcast_assistant_write_cp_cb;
|
||||
|
||||
err = bt_gatt_write(conn, &inst->write_params);
|
||||
if (err == 0) {
|
||||
inst->busy = true;
|
||||
if (err != 0) {
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
/* Report expected possible errors */
|
||||
if (err == -ENOTCONN || err == -ENOMEM) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -906,7 +945,6 @@ static bool broadcast_src_is_duplicate(struct bap_broadcast_assistant_instance *
|
|||
|
||||
static int broadcast_assistant_reset(struct bap_broadcast_assistant_instance *inst)
|
||||
{
|
||||
inst->busy = false;
|
||||
inst->scanning = false;
|
||||
inst->pa_sync = 0U;
|
||||
inst->recv_state_cnt = 0U;
|
||||
|
@ -985,22 +1023,25 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn)
|
|||
|
||||
inst = &broadcast_assistants[bt_conn_index(conn)];
|
||||
|
||||
if (inst->busy) {
|
||||
/* Do not allow new discoveries while we are reading or writing */
|
||||
if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("Instance is busy");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = broadcast_assistant_reset(inst);
|
||||
if (err != 0) {
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
LOG_DBG("Failed to reset broadcast assistant: %d", err);
|
||||
|
||||
return -EINVAL;
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
inst->conn = bt_conn_ref(conn);
|
||||
|
||||
/* Discover BASS on peer, setup handles and notify */
|
||||
discover_init();
|
||||
discover_init(inst);
|
||||
|
||||
(void)memcpy(&uuid, BT_UUID_BASS, sizeof(uuid));
|
||||
inst->disc_params.func = service_discover_func;
|
||||
|
@ -1010,10 +1051,18 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn)
|
|||
inst->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||
err = bt_gatt_discover(conn, &inst->disc_params);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS);
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
inst->busy = true;
|
||||
/* Report expected possible errors */
|
||||
if (err == -ENOTCONN || err == -ENOMEM) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Unexpected err %d from bt_gatt_discover", err);
|
||||
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1073,15 +1122,26 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan)
|
|||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
/* Do not allow writes while we are discovering as the handles may change */
|
||||
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* TODO: Remove the start_scan parameter and support from the assistant */
|
||||
if (start_scan) {
|
||||
static bool cb_registered;
|
||||
|
||||
if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_SCANNING)) {
|
||||
LOG_DBG("Already scanning");
|
||||
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (!cb_registered) {
|
||||
bt_le_scan_cb_register(&scan_cb);
|
||||
cb_registered = true;
|
||||
|
@ -1091,10 +1151,18 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan)
|
|||
if (err != 0) {
|
||||
LOG_DBG("Could not start scan (%d)", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_SCANNING);
|
||||
|
||||
inst->scanning = true;
|
||||
/* Report expected possible errors */
|
||||
if (err == -EAGAIN) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Unexpected err %d from bt_le_scan_start", err);
|
||||
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset buffer before using */
|
||||
|
@ -1103,7 +1171,21 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan)
|
|||
|
||||
cp->opcode = BT_BAP_BASS_OP_SCAN_START;
|
||||
|
||||
return bt_bap_broadcast_assistant_common_cp(conn, &att_buf);
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_SCANNING);
|
||||
err = bt_bap_broadcast_assistant_common_cp(conn, &att_buf);
|
||||
if (err != 0 && start_scan) {
|
||||
/* bt_bap_broadcast_assistant_common_cp clears the busy flag on error */
|
||||
err = bt_le_scan_stop();
|
||||
if (err != 0) {
|
||||
LOG_DBG("Could not stop scan (%d)", err);
|
||||
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_SCANNING);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn)
|
||||
|
@ -1127,21 +1209,23 @@ int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn)
|
|||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (inst->scanning) {
|
||||
if (atomic_test_bit(inst->flags, BAP_BA_FLAG_SCANNING)) {
|
||||
err = bt_le_scan_stop();
|
||||
if (err != 0) {
|
||||
LOG_DBG("Could not stop scan (%d)", err);
|
||||
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inst->scanning = false;
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_SCANNING);
|
||||
}
|
||||
|
||||
/* Reset buffer before using */
|
||||
|
@ -1171,23 +1255,23 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if this operation would result in a duplicate before proceeding */
|
||||
if (broadcast_src_is_duplicate(inst, param->broadcast_id, param->adv_sid,
|
||||
param->addr.type)) {
|
||||
LOG_DBG("Broadcast source already exists");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (inst->cp_handle == 0) {
|
||||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Check if this operation would result in a duplicate before proceeding */
|
||||
if (broadcast_src_is_duplicate(inst, param->broadcast_id,
|
||||
param->adv_sid, param->addr.type)) {
|
||||
LOG_DBG("Broadcast source already exists");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Reset buffer before using */
|
||||
net_buf_simple_reset(&att_buf);
|
||||
cp = net_buf_simple_add(&att_buf, sizeof(*cp));
|
||||
|
@ -1219,6 +1303,10 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
|
|||
if (att_buf.len + subgroup_size > att_buf.size) {
|
||||
LOG_DBG("MTU is too small to send %zu octets", att_buf.len + subgroup_size);
|
||||
|
||||
/* TODO: Validate parameters before setting the busy flag to reduce cleanup
|
||||
*/
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1228,6 +1316,9 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
|
|||
|
||||
CHECKIF(param->pa_sync == 0 && subgroup->bis_sync != 0) {
|
||||
LOG_DBG("Only syncing to BIS is not allowed");
|
||||
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1268,7 +1359,7 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
|
|||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
|
@ -1320,6 +1411,11 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
|
|||
|
||||
if (att_buf.len + subgroup_size > att_buf.size) {
|
||||
LOG_DBG("MTU is too small to send %zu octets", att_buf.len + subgroup_size);
|
||||
|
||||
/* TODO: Validate parameters before setting the busy flag to reduce cleanup
|
||||
*/
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
subgroup = net_buf_simple_add(&att_buf, subgroup_size);
|
||||
|
@ -1328,6 +1424,9 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
|
|||
|
||||
CHECKIF(param->pa_sync == 0 && subgroup->bis_sync != 0) {
|
||||
LOG_DBG("Only syncing to BIS is not allowed");
|
||||
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1366,7 +1465,7 @@ int bt_bap_broadcast_assistant_set_broadcast_code(
|
|||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
|
@ -1407,7 +1506,7 @@ int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id)
|
|||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
|
@ -1423,6 +1522,22 @@ int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id)
|
|||
return bt_bap_broadcast_assistant_common_cp(conn, &att_buf);
|
||||
}
|
||||
|
||||
static int read_recv_state(struct bap_broadcast_assistant_instance *inst, uint8_t idx)
|
||||
{
|
||||
int err;
|
||||
|
||||
inst->read_params.func = read_recv_state_cb;
|
||||
inst->read_params.handle_count = 1;
|
||||
inst->read_params.single.handle = inst->recv_state_handles[idx];
|
||||
|
||||
err = bt_gatt_read(inst->conn, &inst->read_params);
|
||||
if (err != 0) {
|
||||
(void)memset(&inst->read_params, 0, sizeof(inst->read_params));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn,
|
||||
uint8_t idx)
|
||||
{
|
||||
|
@ -1450,16 +1565,17 @@ int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn,
|
|||
LOG_DBG("handle not set");
|
||||
|
||||
return -EINVAL;
|
||||
} else if (atomic_test_and_set_bit(inst->flags, BAP_BA_FLAG_BUSY)) {
|
||||
LOG_DBG("instance busy");
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
inst->read_params.func = read_recv_state_cb;
|
||||
inst->read_params.handle_count = 1;
|
||||
inst->read_params.single.handle = inst->recv_state_handles[idx];
|
||||
|
||||
err = bt_gatt_read(conn, &inst->read_params);
|
||||
err = read_recv_state(inst, idx);
|
||||
if (err != 0) {
|
||||
(void)memset(&inst->read_params, 0,
|
||||
sizeof(inst->read_params));
|
||||
atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -326,6 +326,7 @@ static void test_bass_discover(void)
|
|||
int err;
|
||||
|
||||
printk("Discovering BASS\n");
|
||||
UNSET_FLAG(flag_discovery_complete);
|
||||
err = bt_bap_broadcast_assistant_discover(default_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to discover BASS %d\n", err);
|
||||
|
@ -335,7 +336,7 @@ static void test_bass_discover(void)
|
|||
WAIT_FOR_FLAG(flag_discovery_complete);
|
||||
|
||||
/* Verify that we can discover again */
|
||||
flag_discovery_complete = false;
|
||||
UNSET_FLAG(flag_discovery_complete);
|
||||
err = bt_bap_broadcast_assistant_discover(default_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to discover BASS for the second time: %d\n", err);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue