Bluetooth: ISO: Add CIG reconfigure function
Add function to reconfigure and even add additional CIS to a CIG. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
be1912b66a
commit
65620363e3
2 changed files with 141 additions and 15 deletions
|
@ -518,6 +518,28 @@ int bt_iso_server_register(struct bt_iso_server *server);
|
|||
int bt_iso_cig_create(const struct bt_iso_cig_param *param,
|
||||
struct bt_iso_cig **out_cig);
|
||||
|
||||
/** @brief Reconfigure a CIG as a central
|
||||
*
|
||||
* This function can be used to update a CIG. It will update the group specific
|
||||
* parameters, and, if supplied, change the QoS parameters of the individual
|
||||
* CIS. If the cis_channels in @p param contains CIS that was not originally
|
||||
* in the call to bt_iso_cig_create(), these will be added to the group.
|
||||
* It is not possible to remove any CIS from the group after creation.
|
||||
*
|
||||
* This can be called at any time before connecting an ISO to a remote device.
|
||||
* Once any CIS in the group has connected, the group cannot be changed.
|
||||
*
|
||||
* Once a CIG is created, the channels supplied in the @p param can be
|
||||
* connected using bt_iso_chan_connect.
|
||||
*
|
||||
* @param cig Connected Isochronous Group object.
|
||||
* @param param The parameters used to reconfigure the CIG.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int bt_iso_cig_reconfigure(struct bt_iso_cig *cig,
|
||||
const struct bt_iso_cig_param *param);
|
||||
|
||||
/** @brief Terminates a CIG as a central
|
||||
*
|
||||
* All the CIS in the CIG shall be disconnected first.
|
||||
|
|
|
@ -1088,12 +1088,19 @@ static struct bt_iso_cig *get_free_cig(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool cis_is_in_cig(const struct bt_iso_cig *cig,
|
||||
const struct bt_iso_chan *cis)
|
||||
{
|
||||
return cig->id == cis->iso->iso.cig_id;
|
||||
}
|
||||
|
||||
static int cig_init_cis(struct bt_iso_cig *cig,
|
||||
const struct bt_iso_cig_param *param)
|
||||
{
|
||||
for (uint8_t i = 0; i < param->num_cis; i++) {
|
||||
struct bt_iso_chan *cis = param->cis_channels[i];
|
||||
|
||||
if (cis->iso == NULL) {
|
||||
cis->iso = iso_new();
|
||||
if (cis->iso == NULL) {
|
||||
BT_ERR("Unable to allocate CIS connection");
|
||||
|
@ -1102,11 +1109,12 @@ static int cig_init_cis(struct bt_iso_cig *cig,
|
|||
|
||||
cis->iso->iso.cig_id = cig->id;
|
||||
cis->iso->iso.is_bis = false;
|
||||
cis->iso->iso.cis_id = i;
|
||||
cis->iso->iso.cis_id = cig->num_cis++;
|
||||
|
||||
bt_iso_chan_add(cis->iso, cis);
|
||||
|
||||
sys_slist_append(&cig->cis_channels, &cis->node);
|
||||
} /* else already initialized */
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1146,11 +1154,6 @@ static bool valid_cig_param(const struct bt_iso_cig_param *param)
|
|||
BT_DBG("cis_channels[%d]: Invalid QOS", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cis->iso != NULL) {
|
||||
BT_DBG("cis_channels[%d]: already allocated", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (param->framing != BT_ISO_FRAMING_UNFRAMED &&
|
||||
|
@ -1209,6 +1212,7 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param,
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* TBD: Should we allow creating empty CIGs? */
|
||||
CHECKIF(param->cis_channels == NULL) {
|
||||
BT_DBG("NULL CIS channels");
|
||||
return -EINVAL;
|
||||
|
@ -1224,6 +1228,15 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < param->num_cis; i++) {
|
||||
struct bt_iso_chan *cis = param->cis_channels[i];
|
||||
|
||||
if (cis->iso != NULL) {
|
||||
BT_DBG("cis_channels[%d]: already allocated", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
cig = get_free_cig();
|
||||
|
||||
if (!cig) {
|
||||
|
@ -1236,7 +1249,6 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param,
|
|||
cleanup_cig(cig);
|
||||
return err;
|
||||
}
|
||||
cig->num_cis = param->num_cis;
|
||||
|
||||
rsp = hci_le_set_cig_params(cig, param);
|
||||
if (rsp == NULL) {
|
||||
|
@ -1270,6 +1282,98 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void restore_cig(struct bt_iso_cig *cig, uint8_t existing_num_cis)
|
||||
{
|
||||
struct bt_iso_chan *cis, *tmp;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) {
|
||||
/* Remove all newly added by comparing the cis_id to the number
|
||||
* of CIS that was previously added before
|
||||
* bt_iso_cig_reconfigure was called
|
||||
*/
|
||||
if (cis->iso != NULL &&
|
||||
cis->iso->iso.cis_id >= existing_num_cis) {
|
||||
bt_conn_unref(cis->iso);
|
||||
cis->iso = NULL;
|
||||
|
||||
sys_slist_remove(&cig->cis_channels, NULL, &cis->node);
|
||||
cig->num_cis--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int bt_iso_cig_reconfigure(struct bt_iso_cig *cig,
|
||||
const struct bt_iso_cig_param *param)
|
||||
{
|
||||
struct bt_hci_rp_le_set_cig_params *cig_rsp;
|
||||
uint8_t existing_num_cis;
|
||||
struct bt_iso_chan *cis;
|
||||
struct net_buf *rsp;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
CHECKIF(cig == NULL) {
|
||||
BT_DBG("cig is NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(!valid_cig_param(param)) {
|
||||
BT_DBG("Invalid CIG params");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < param->num_cis; i++) {
|
||||
struct bt_iso_chan *cis = param->cis_channels[i];
|
||||
|
||||
if (cis->iso != NULL && !cis_is_in_cig(cig, cis)) {
|
||||
BT_DBG("Cannot reconfigure other CIG's (id 0x%02X) CIS "
|
||||
"with this CIG (id 0x%02X)",
|
||||
cis->iso->iso.cig_id, cig->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Used to restore CIG in case of error */
|
||||
existing_num_cis = cig->num_cis;
|
||||
|
||||
err = cig_init_cis(cig, param);
|
||||
if (err != 0) {
|
||||
BT_DBG("Could not init CIS %d", err);
|
||||
restore_cig(cig, existing_num_cis);
|
||||
return err;
|
||||
}
|
||||
|
||||
rsp = hci_le_set_cig_params(cig, param);
|
||||
if (rsp == NULL) {
|
||||
BT_WARN("Unexpected response to hci_le_set_cig_params");
|
||||
err = -EIO;
|
||||
restore_cig(cig, existing_num_cis);
|
||||
return err;
|
||||
}
|
||||
|
||||
cig_rsp = (void *)rsp->data;
|
||||
|
||||
if (rsp->len < sizeof(cig_rsp) ||
|
||||
cig_rsp->num_handles != param->num_cis) {
|
||||
BT_WARN("Unexpected response to hci_le_set_cig_params");
|
||||
err = -EIO;
|
||||
net_buf_unref(rsp);
|
||||
restore_cig(cig, existing_num_cis);
|
||||
return err;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis_channels, cis, node) {
|
||||
/* Assign the connection handle */
|
||||
cis->iso->handle = sys_le16_to_cpu(cig_rsp->handle[i++]);
|
||||
}
|
||||
|
||||
net_buf_unref(rsp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_iso_cig_terminate(struct bt_iso_cig *cig)
|
||||
{
|
||||
struct bt_iso_chan *cis;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue