blob: 711aeb39aaf6a0c69ff090177fe535d369dad069 [file] [log] [blame]
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/byteorder.h>
#define BUF_ALLOC_TIMEOUT (10) /* milliseconds */
#define BIG_TERMINATE_TIMEOUT_US (60 * USEC_PER_SEC) /* microseconds */
#define BIG_SDU_INTERVAL_US (10000)
#define BIS_ISO_CHAN_COUNT 2
NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, BIS_ISO_CHAN_COUNT,
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
static K_SEM_DEFINE(sem_big_cmplt, 0, BIS_ISO_CHAN_COUNT);
static K_SEM_DEFINE(sem_big_term, 0, BIS_ISO_CHAN_COUNT);
#define INITIAL_TIMEOUT_COUNTER (BIG_TERMINATE_TIMEOUT_US / BIG_SDU_INTERVAL_US)
static uint32_t seq_num;
static void iso_connected(struct bt_iso_chan *chan)
{
printk("ISO Channel %p connected\n", chan);
seq_num = 0U;
k_sem_give(&sem_big_cmplt);
}
static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
{
printk("ISO Channel %p disconnected with reason 0x%02x\n",
chan, reason);
k_sem_give(&sem_big_term);
}
static struct bt_iso_chan_ops iso_ops = {
.connected = iso_connected,
.disconnected = iso_disconnected,
};
static struct bt_iso_chan_io_qos iso_tx_qos = {
.sdu = sizeof(uint32_t), /* bytes */
.rtn = 1,
.phy = BT_GAP_LE_PHY_2M,
};
static struct bt_iso_chan_qos bis_iso_qos = {
.tx = &iso_tx_qos,
};
static struct bt_iso_chan bis_iso_chan[] = {
{ .ops = &iso_ops, .qos = &bis_iso_qos, },
{ .ops = &iso_ops, .qos = &bis_iso_qos, },
};
static struct bt_iso_chan *bis[] = {
&bis_iso_chan[0],
&bis_iso_chan[1],
};
static struct bt_iso_big_create_param big_create_param = {
.num_bis = BIS_ISO_CHAN_COUNT,
.bis_channels = bis,
.interval = BIG_SDU_INTERVAL_US, /* in microseconds */
.latency = 10, /* in milliseconds */
.packing = 0, /* 0 - sequential, 1 - interleaved */
.framing = 0, /* 0 - unframed, 1 - framed */
};
void main(void)
{
uint32_t timeout_counter = INITIAL_TIMEOUT_COUNTER;
struct bt_le_ext_adv *adv;
struct bt_iso_big *big;
int err;
uint32_t iso_send_count = 0;
uint8_t iso_data[sizeof(iso_send_count)] = { 0 };
printk("Starting ISO Broadcast Demo\n");
/* Initialize the Bluetooth Subsystem */
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
/* Create a non-connectable non-scannable advertising set */
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, &adv);
if (err) {
printk("Failed to create advertising set (err %d)\n", err);
return;
}
/* Set periodic advertising parameters */
err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT);
if (err) {
printk("Failed to set periodic advertising parameters"
" (err %d)\n", err);
return;
}
/* Enable Periodic Advertising */
err = bt_le_per_adv_start(adv);
if (err) {
printk("Failed to enable periodic advertising (err %d)\n", err);
return;
}
/* Start extended advertising */
err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
if (err) {
printk("Failed to start extended advertising (err %d)\n", err);
return;
}
/* Create BIG */
err = bt_iso_big_create(adv, &big_create_param, &big);
if (err) {
printk("Failed to create BIG (err %d)\n", err);
return;
}
for (uint8_t chan = 0U; chan < BIS_ISO_CHAN_COUNT; chan++) {
printk("Waiting for BIG complete chan %u...\n", chan);
err = k_sem_take(&sem_big_cmplt, K_FOREVER);
if (err) {
printk("failed (err %d)\n", err);
return;
}
printk("BIG create complete chan %u.\n", chan);
}
while (true) {
int ret;
k_sleep(K_USEC(big_create_param.interval));
for (uint8_t chan = 0U; chan < BIS_ISO_CHAN_COUNT; chan++) {
struct net_buf *buf;
buf = net_buf_alloc(&bis_tx_pool,
K_MSEC(BUF_ALLOC_TIMEOUT));
if (!buf) {
printk("Data buffer allocate timeout on channel"
" %u\n", chan);
return;
}
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
sys_put_le32(iso_send_count, iso_data);
net_buf_add_mem(buf, iso_data, sizeof(iso_data));
ret = bt_iso_chan_send(&bis_iso_chan[chan], buf,
seq_num, BT_ISO_TIMESTAMP_NONE);
if (ret < 0) {
printk("Unable to broadcast data on channel %u"
" : %d", chan, ret);
net_buf_unref(buf);
return;
}
}
iso_send_count++;
seq_num++;
if ((iso_send_count % 100) == 0) {
printk("Sending value %u\n", iso_send_count);
}
timeout_counter--;
if (!timeout_counter) {
timeout_counter = INITIAL_TIMEOUT_COUNTER;
printk("BIG Terminate...");
err = bt_iso_big_terminate(big);
if (err) {
printk("failed (err %d)\n", err);
return;
}
printk("done.\n");
for (uint8_t chan = 0U; chan < BIS_ISO_CHAN_COUNT;
chan++) {
printk("Waiting for BIG terminate complete"
" chan %u...\n", chan);
err = k_sem_take(&sem_big_term, K_FOREVER);
if (err) {
printk("failed (err %d)\n", err);
return;
}
printk("BIG terminate complete chan %u.\n",
chan);
}
printk("Create BIG...");
err = bt_iso_big_create(adv, &big_create_param, &big);
if (err) {
printk("failed (err %d)\n", err);
return;
}
printk("done.\n");
for (uint8_t chan = 0U; chan < BIS_ISO_CHAN_COUNT;
chan++) {
printk("Waiting for BIG complete chan %u...\n",
chan);
err = k_sem_take(&sem_big_cmplt, K_FOREVER);
if (err) {
printk("failed (err %d)\n", err);
return;
}
printk("BIG create complete chan %u.\n", chan);
}
}
}
}