Bluetooth: ISO: Change CIG/BIG to use slist instead of array

A CIG may be updated later to include more CIS, and thus a slist
makes more sense.

The BIG doesn't need the change, but it makes more sense to
have similar handling for both.

This change also removes the requirement that the arrays
used to create the CIG/BIG need to static.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2021-10-15 14:22:42 +02:00 committed by Christopher Friedt
commit ba0a053f94
6 changed files with 85 additions and 76 deletions

View file

@ -108,6 +108,8 @@ struct bt_iso_chan {
struct bt_iso_chan_qos *qos; struct bt_iso_chan_qos *qos;
uint8_t state; uint8_t state;
bt_security_t required_sec_level; bt_security_t required_sec_level;
/** Node used internally by the stack */
sys_snode_t node;
}; };
/** @brief ISO Channel IO QoS structure. */ /** @brief ISO Channel IO QoS structure. */
@ -198,10 +200,7 @@ struct bt_iso_recv_info {
struct bt_iso_cig; struct bt_iso_cig;
struct bt_iso_cig_create_param { struct bt_iso_cig_create_param {
/** @brief Array of pointers to CIS channels /** @brief Array of pointers to CIS channels */
*
* This array shall remain valid for the duration of the CIG.
*/
struct bt_iso_chan **cis_channels; struct bt_iso_chan **cis_channels;
/** @brief Number channels in @p cis_channels /** @brief Number channels in @p cis_channels
@ -258,10 +257,7 @@ struct bt_iso_connect_param {
struct bt_iso_big; struct bt_iso_big;
struct bt_iso_big_create_param { struct bt_iso_big_create_param {
/** Array of pointers to BIS channels /** Array of pointers to BIS channels */
*
* This array shall remain valid for the duration of the BIG.
*/
struct bt_iso_chan **bis_channels; struct bt_iso_chan **bis_channels;
/** @brief Number channels in @p bis_channels /** @brief Number channels in @p bis_channels

View file

@ -216,7 +216,7 @@ BT_CONN_CB_DEFINE(conn_callbacks) = {
void main(void) void main(void)
{ {
int err; int err;
static struct bt_iso_chan *channels[1]; struct bt_iso_chan *channels[1];
struct bt_iso_cig_create_param param; struct bt_iso_cig_create_param param;
struct bt_iso_cig *cig; struct bt_iso_cig *cig;

View file

@ -338,7 +338,7 @@ static int create_big_sync(struct bt_iso_big **big, struct bt_le_per_adv_sync *s
uint32_t sem_timeout = per_interval_ms * PA_RETRY_COUNT; uint32_t sem_timeout = per_interval_ms * PA_RETRY_COUNT;
uint32_t sync_timeout_ms; uint32_t sync_timeout_ms;
static struct bt_iso_chan bis_iso_chan[CONFIG_BT_ISO_MAX_CHAN]; static struct bt_iso_chan bis_iso_chan[CONFIG_BT_ISO_MAX_CHAN];
static struct bt_iso_chan *bis[CONFIG_BT_ISO_MAX_CHAN]; struct bt_iso_chan *bis[CONFIG_BT_ISO_MAX_CHAN];
struct bt_iso_big_sync_param big_sync_param = { struct bt_iso_big_sync_param big_sync_param = {
.bis_channels = bis, .bis_channels = bis,
.num_bis = 0, .num_bis = 0,

View file

@ -1078,6 +1078,7 @@ static struct bt_iso_cig *get_free_cig(void)
if (!cigs[i].initialized) { if (!cigs[i].initialized) {
cigs[i].initialized = true; cigs[i].initialized = true;
cigs[i].id = i; cigs[i].id = i;
sys_slist_init(&cigs[i].cis);
return &cigs[i]; return &cigs[i];
} }
} }
@ -1087,10 +1088,10 @@ static struct bt_iso_cig *get_free_cig(void)
return NULL; return NULL;
} }
static int cig_init_cis(struct bt_iso_cig *cig) static int cig_init_cis(struct bt_iso_cig *cig, const struct bt_iso_cig_create_param *param)
{ {
for (int i = 0; i < cig->num_cis; i++) { for (uint8_t i = 0; i < param->num_cis; i++) {
struct bt_iso_chan *cis = cig->cis[i]; struct bt_iso_chan *cis = param->cis_channels[i];
CHECKIF(cis == NULL) { CHECKIF(cis == NULL) {
BT_DBG("CIS was NULL"); BT_DBG("CIS was NULL");
@ -1118,6 +1119,8 @@ static int cig_init_cis(struct bt_iso_cig *cig)
cis->iso->iso.cis_id = i; cis->iso->iso.cis_id = i;
bt_iso_chan_add(cis->iso, cis); bt_iso_chan_add(cis->iso, cis);
sys_slist_append(&cig->cis, &cis->node);
} }
return 0; return 0;
@ -1125,13 +1128,15 @@ static int cig_init_cis(struct bt_iso_cig *cig)
static void cleanup_cig(struct bt_iso_cig *cig) static void cleanup_cig(struct bt_iso_cig *cig)
{ {
for (int i = 0; i < cig->num_cis; i++) { struct bt_iso_chan *cis, *tmp;
struct bt_iso_chan *cis = cig->cis[i];
if (cis != NULL && cis->iso != NULL) { SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis, cis, tmp, node) {
if (cis->iso != NULL) {
bt_conn_unref(cis->iso); bt_conn_unref(cis->iso);
cis->iso = NULL; cis->iso = NULL;
} }
sys_slist_remove(&cig->cis, NULL, &cis->node);
} }
memset(cig, 0, sizeof(*cig)); memset(cig, 0, sizeof(*cig));
@ -1144,6 +1149,8 @@ int bt_iso_cig_create(const struct bt_iso_cig_create_param *param,
struct net_buf *rsp; struct net_buf *rsp;
struct bt_iso_cig *cig; struct bt_iso_cig *cig;
struct bt_hci_rp_le_set_cig_params *cig_rsp; struct bt_hci_rp_le_set_cig_params *cig_rsp;
struct bt_iso_chan *cis;
int i;
CHECKIF(out_cig == NULL) { CHECKIF(out_cig == NULL) {
BT_DBG("out_cig is NULL"); BT_DBG("out_cig is NULL");
@ -1211,15 +1218,13 @@ int bt_iso_cig_create(const struct bt_iso_cig_create_param *param,
return -ENOMEM; return -ENOMEM;
} }
cig->cis = param->cis_channels; err = cig_init_cis(cig, param);
cig->num_cis = param->num_cis;
err = cig_init_cis(cig);
if (err) { if (err) {
BT_DBG("Could not init CIS %d", err); BT_DBG("Could not init CIS %d", err);
cleanup_cig(cig); cleanup_cig(cig);
return err; return err;
} }
cig->num_cis = param->num_cis;
rsp = hci_le_set_cig_params(cig, param); rsp = hci_le_set_cig_params(cig, param);
if (rsp == NULL) { if (rsp == NULL) {
@ -1240,13 +1245,10 @@ int bt_iso_cig_create(const struct bt_iso_cig_create_param *param,
return err; return err;
} }
for (int i = 0; i < cig_rsp->num_handles; i++) { i = 0;
struct bt_iso_chan *chan; SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis, cis, node) {
chan = param->cis_channels[i];
/* Assign the connection handle */ /* Assign the connection handle */
chan->iso->handle = sys_le16_to_cpu(cig_rsp->handle[i]); cis->iso->handle = sys_le16_to_cpu(cig_rsp->handle[i++]);
} }
net_buf_unref(rsp); net_buf_unref(rsp);
@ -1258,6 +1260,7 @@ int bt_iso_cig_create(const struct bt_iso_cig_create_param *param,
int bt_iso_cig_terminate(struct bt_iso_cig *cig) int bt_iso_cig_terminate(struct bt_iso_cig *cig)
{ {
struct bt_iso_chan *cis;
int err; int err;
CHECKIF(cig == NULL) { CHECKIF(cig == NULL) {
@ -1265,9 +1268,9 @@ int bt_iso_cig_terminate(struct bt_iso_cig *cig)
return -EINVAL; return -EINVAL;
} }
for (int i = 0; i < cig->num_cis; i++) { SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis, cis, node) {
if (cig->cis[i]->state != BT_ISO_DISCONNECTED) { if (cis->state != BT_ISO_DISCONNECTED) {
BT_DBG("[%d]: Channel is not disconnected", i); BT_DBG("Channel %p is not disconnected", cis);
return -EINVAL; return -EINVAL;
} }
} }
@ -1450,6 +1453,7 @@ static struct bt_iso_big *get_free_big(void)
for (int i = 0; i < ARRAY_SIZE(bigs); i++) { for (int i = 0; i < ARRAY_SIZE(bigs); i++) {
if (!atomic_test_and_set_bit(bigs[i].flags, BT_BIG_INITIALIZED)) { if (!atomic_test_and_set_bit(bigs[i].flags, BT_BIG_INITIALIZED)) {
bigs[i].handle = i; bigs[i].handle = i;
sys_slist_init(&bigs[i].bis);
return &bigs[i]; return &bigs[i];
} }
} }
@ -1474,13 +1478,15 @@ static struct bt_iso_big *big_lookup_flag(int bit)
static void cleanup_big(struct bt_iso_big *big) static void cleanup_big(struct bt_iso_big *big)
{ {
for (int i = 0; i < big->num_bis; i++) { struct bt_iso_chan *bis, *tmp;
struct bt_iso_chan *bis = big->bis[i];
if (bis != NULL && bis->iso != NULL) { SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&big->bis, bis, tmp, node) {
if (bis->iso != NULL) {
bt_conn_unref(bis->iso); bt_conn_unref(bis->iso);
bis->iso = NULL; bis->iso = NULL;
} }
sys_slist_remove(&big->bis, NULL, &bis->node);
} }
memset(big, 0, sizeof(*big)); memset(big, 0, sizeof(*big));
@ -1488,17 +1494,22 @@ static void cleanup_big(struct bt_iso_big *big)
static void big_disconnect(struct bt_iso_big *big, uint8_t reason) static void big_disconnect(struct bt_iso_big *big, uint8_t reason)
{ {
for (int i = 0; i < big->num_bis; i++) { struct bt_iso_chan *bis;
big->bis[i]->iso->err = reason;
bt_iso_disconnected(big->bis[i]->iso); SYS_SLIST_FOR_EACH_CONTAINER(&big->bis, bis, node) {
bis->iso->err = reason;
bt_iso_disconnected(bis->iso);
} }
} }
static int big_init_bis(struct bt_iso_big *big, bool broadcaster) static int big_init_bis(struct bt_iso_big *big,
struct bt_iso_chan **bis_channels,
uint8_t num_bis,
bool broadcaster)
{ {
for (int i = 0; i < big->num_bis; i++) { for (uint8_t i = 0; i < num_bis; i++) {
struct bt_iso_chan *bis = big->bis[i]; struct bt_iso_chan *bis = bis_channels[i];
if (!bis) { if (!bis) {
BT_DBG("BIS was NULL"); BT_DBG("BIS was NULL");
@ -1540,6 +1551,8 @@ static int big_init_bis(struct bt_iso_big *big, bool broadcaster)
bis->iso->iso.bis_id = bt_conn_index(bis->iso); bis->iso->iso.bis_id = bt_conn_index(bis->iso);
bt_iso_chan_add(bis->iso, bis); bt_iso_chan_add(bis->iso, bis);
sys_slist_append(&big->bis, &bis->node);
} }
return 0; return 0;
@ -1554,6 +1567,7 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
struct net_buf *buf; struct net_buf *buf;
int err; int err;
static struct bt_iso_chan_qos *qos; static struct bt_iso_chan_qos *qos;
struct bt_iso_chan *bis;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG, sizeof(*req)); buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG, sizeof(*req));
@ -1561,8 +1575,11 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
return -ENOBUFS; return -ENOBUFS;
} }
bis = SYS_SLIST_PEEK_HEAD_CONTAINER(&big->bis, bis, node);
__ASSERT(bis != NULL, "bis was NULL");
/* All BIS will share the same QOS */ /* All BIS will share the same QOS */
qos = big->bis[0]->qos; qos = bis->qos;
req = net_buf_add(buf, sizeof(*req)); req = net_buf_add(buf, sizeof(*req));
req->big_handle = big->handle; req->big_handle = big->handle;
@ -1589,9 +1606,10 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
return err; return err;
} }
for (int i = 0; i < big->num_bis; i++) { SYS_SLIST_FOR_EACH_CONTAINER(&big->bis, bis, node) {
bt_iso_chan_set_state(big->bis[i], BT_ISO_CONNECT); bt_iso_chan_set_state(bis, BT_ISO_CONNECT);
} }
return err; return err;
} }
@ -1660,15 +1678,13 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param
return -ENOMEM; return -ENOMEM;
} }
big->bis = param->bis_channels; err = big_init_bis(big, param->bis_channels, param->num_bis, true);
big->num_bis = param->num_bis;
err = big_init_bis(big, true);
if (err) { if (err) {
BT_DBG("Could not init BIG %d", err); BT_DBG("Could not init BIG %d", err);
cleanup_big(big); cleanup_big(big);
return err; return err;
} }
big->num_bis = param->num_bis;
err = hci_le_create_big(padv, big, param); err = hci_le_create_big(padv, big, param);
if (err) { if (err) {
@ -1685,7 +1701,9 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param
void hci_le_big_complete(struct net_buf *buf) void hci_le_big_complete(struct net_buf *buf)
{ {
struct bt_hci_evt_le_big_complete *evt = (void *)buf->data; struct bt_hci_evt_le_big_complete *evt = (void *)buf->data;
struct bt_iso_chan *bis;
struct bt_iso_big *big; struct bt_iso_big *big;
int i;
if (evt->big_handle >= ARRAY_SIZE(bigs)) { if (evt->big_handle >= ARRAY_SIZE(bigs)) {
BT_WARN("Invalid BIG handle"); BT_WARN("Invalid BIG handle");
@ -1714,10 +1732,9 @@ void hci_le_big_complete(struct net_buf *buf)
return; return;
} }
for (int i = 0; i < big->num_bis; i++) { i = 0;
struct bt_iso_chan *bis = big->bis[i]; SYS_SLIST_FOR_EACH_CONTAINER(&big->bis, bis, node) {
bis->iso->handle = sys_le16_to_cpu(evt->handle[i++]);
bis->iso->handle = sys_le16_to_cpu(evt->handle[i]);
bt_conn_set_state(bis->iso, BT_CONN_CONNECTED); bt_conn_set_state(bis->iso, BT_CONN_CONNECTED);
} }
} }
@ -1790,23 +1807,20 @@ static int hci_le_big_sync_term(struct bt_iso_big *big)
int bt_iso_big_terminate(struct bt_iso_big *big) int bt_iso_big_terminate(struct bt_iso_big *big)
{ {
struct bt_iso_chan *bis;
int err; int err;
bool broadcaster; bool broadcaster;
if (!atomic_test_bit(big->flags, BT_BIG_INITIALIZED) || !big->num_bis || !big->bis) { if (!atomic_test_bit(big->flags, BT_BIG_INITIALIZED) || !big->num_bis) {
BT_DBG("BIG not initialized"); BT_DBG("BIG not initialized");
return -EINVAL; return -EINVAL;
} }
for (int i = 0; i < big->num_bis; i++) { bis = SYS_SLIST_PEEK_HEAD_CONTAINER(&big->bis, bis, node);
if (!big->bis[i]) { __ASSERT(bis != NULL, "bis was NULL");
BT_DBG("BIG BIS[%d] not initialized", i);
return -EINVAL;
}
}
/* They all have the same QOS dir so we can just check the first */ /* They all have the same QOS dir so we can just check the first */
broadcaster = big->bis[0]->qos->tx ? true : false; broadcaster = bis->qos->tx ? true : false;
if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && broadcaster) { if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && broadcaster) {
err = hci_le_terminate_big(big); err = hci_le_terminate_big(big);
@ -1815,8 +1829,8 @@ int bt_iso_big_terminate(struct bt_iso_big *big)
* the BIG in hci_le_big_terminate * the BIG in hci_le_big_terminate
*/ */
if (!err) { if (!err) {
for (int i = 0; i < big->num_bis; i++) { SYS_SLIST_FOR_EACH_CONTAINER(&big->bis, bis, node) {
bt_iso_chan_set_state(big->bis[i], BT_ISO_DISCONNECT); bt_iso_chan_set_state(bis, BT_ISO_DISCONNECT);
} }
} }
} else if (IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER)) { } else if (IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER)) {
@ -1841,7 +1855,9 @@ int bt_iso_big_terminate(struct bt_iso_big *big)
void hci_le_big_sync_established(struct net_buf *buf) void hci_le_big_sync_established(struct net_buf *buf)
{ {
struct bt_hci_evt_le_big_sync_established *evt = (void *)buf->data; struct bt_hci_evt_le_big_sync_established *evt = (void *)buf->data;
struct bt_iso_chan *bis;
struct bt_iso_big *big; struct bt_iso_big *big;
int i;
if (evt->big_handle >= ARRAY_SIZE(bigs)) { if (evt->big_handle >= ARRAY_SIZE(bigs)) {
BT_WARN("Invalid BIG handle"); BT_WARN("Invalid BIG handle");
@ -1869,12 +1885,9 @@ void hci_le_big_sync_established(struct net_buf *buf)
return; return;
} }
for (int i = 0; i < big->num_bis; i++) { i = 0;
struct bt_iso_chan *bis = big->bis[i]; SYS_SLIST_FOR_EACH_CONTAINER(&big->bis, bis, node) {
uint16_t bis_handle = sys_le16_to_cpu(evt->handle[i]); bis->iso->handle = sys_le16_to_cpu(evt->handle[i++]);
bis->iso->handle = bis_handle;
bt_conn_set_state(bis->iso, BT_CONN_CONNECTED); bt_conn_set_state(bis->iso, BT_CONN_CONNECTED);
} }
@ -1954,6 +1967,7 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
struct bt_iso_big **out_big) struct bt_iso_big **out_big)
{ {
int err; int err;
struct bt_iso_chan *bis;
struct bt_iso_big *big; struct bt_iso_big *big;
if (!atomic_test_bit(sync->flags, BT_PER_ADV_SYNC_SYNCED)) { if (!atomic_test_bit(sync->flags, BT_PER_ADV_SYNC_SYNCED)) {
@ -2000,15 +2014,13 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
return -ENOMEM; return -ENOMEM;
} }
big->bis = param->bis_channels; err = big_init_bis(big, param->bis_channels, param->num_bis, false);
big->num_bis = param->num_bis;
err = big_init_bis(big, false);
if (err) { if (err) {
BT_DBG("Could not init BIG %d", err); BT_DBG("Could not init BIG %d", err);
cleanup_big(big); cleanup_big(big);
return err; return err;
} }
big->num_bis = param->num_bis;
err = hci_le_big_create_sync(sync, big, param); err = hci_le_big_create_sync(sync, big, param);
if (err) { if (err) {
@ -2017,8 +2029,9 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
return err; return err;
} }
for (int i = 0; i < big->num_bis; i++) {
bt_iso_chan_set_state(big->bis[i], BT_ISO_CONNECT); SYS_SLIST_FOR_EACH_CONTAINER(&big->bis, bis, node) {
bt_iso_chan_set_state(bis, BT_ISO_CONNECT);
} }
*out_big = big; *out_big = big;

View file

@ -25,8 +25,8 @@ struct iso_data {
}; };
struct bt_iso_cig { struct bt_iso_cig {
/** Array of ISO channels to setup as CIS (the CIG). */ /** List of ISO channels to setup as CIS (the CIG). */
struct bt_iso_chan **cis; sys_slist_t cis;
/** Total number of CISes in the CIG. */ /** Total number of CISes in the CIG. */
uint8_t num_cis; uint8_t num_cis;
@ -49,8 +49,8 @@ enum {
}; };
struct bt_iso_big { struct bt_iso_big {
/** Array of ISO channels to setup as BIS (the BIG). */ /** List of ISO channels to setup as BIS (the BIG). */
struct bt_iso_chan **bis; sys_slist_t bis;
/** Total number of BISes in the BIG. */ /** Total number of BISes in the BIG. */
uint8_t num_bis; uint8_t num_bis;

View file

@ -137,7 +137,7 @@ static int cmd_cig_create(const struct shell *sh, size_t argc, char *argv[])
{ {
int err; int err;
struct bt_iso_cig_create_param param; struct bt_iso_cig_create_param param;
static struct bt_iso_chan *chans[CIS_ISO_CHAN_COUNT]; struct bt_iso_chan *chans[CIS_ISO_CHAN_COUNT];
if (cig != NULL) { if (cig != NULL) {
shell_error(sh, "Already created"); shell_error(sh, "Already created");