blob: 7815cc9116084d2eafd78e5808f3f632eb837efc [file] [log] [blame]
/* main.c - Application main entry point */
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/iso.h>
#include "subsys/bluetooth/host/hci_core.h"
#include "subsys/bluetooth/controller/include/ll.h"
#include "subsys/bluetooth/controller/util/memq.h"
#include "subsys/bluetooth/controller/ll_sw/lll.h"
/* For VS data path */
#include "subsys/bluetooth/controller/ll_sw/isoal.h"
#include "subsys/bluetooth/controller/ll_sw/ull_iso_types.h"
#include "bs_types.h"
#include "bs_tracing.h"
#include "time_machine.h"
#include "bstests.h"
#define FAIL(...) \
do { \
bst_result = Failed; \
bs_trace_error_time_line(__VA_ARGS__); \
} while (0)
#define PASS(...) \
do { \
bst_result = Passed; \
bs_trace_info_time(1, __VA_ARGS__); \
} while (0)
extern enum bst_result_t bst_result;
static uint8_t mfg_data1[] = { 0xff, 0xff, 0x01, 0x02, 0x03, 0x04 };
static uint8_t mfg_data2[] = { 0xff, 0xff, 0x05 };
static const struct bt_data per_ad_data1[] = {
BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data1, 6),
};
static const struct bt_data per_ad_data2[] = {
BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data2, 3),
};
static uint8_t chan_map[] = { 0x1F, 0XF1, 0x1F, 0xF1, 0x1F };
static bool volatile is_iso_connected;
static void iso_connected(struct bt_iso_chan *chan);
static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason);
static void iso_recv(struct bt_iso_chan *chan,
const struct bt_iso_recv_info *info, struct net_buf *buf);
static struct bt_iso_chan_ops iso_ops = {
.connected = iso_connected,
.disconnected = iso_disconnected,
.recv = iso_recv,
};
static struct bt_iso_chan_path iso_path_rx = {
.pid = BT_HCI_DATAPATH_ID_HCI
};
static struct bt_iso_chan_qos bis_iso_qos;
static struct bt_iso_chan_io_qos iso_tx_qos;
static struct bt_iso_chan_io_qos iso_rx_qos = {
.path = &iso_path_rx
};
static struct bt_iso_chan bis_iso_chan = {
.ops = &iso_ops,
.qos = &bis_iso_qos,
};
#define BIS_ISO_CHAN_COUNT 1
static struct bt_iso_chan *bis_channels[BIS_ISO_CHAN_COUNT] = { &bis_iso_chan };
static uint32_t seq_num;
NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, BIS_ISO_CHAN_COUNT,
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH)
static uint8_t test_rx_buffer[CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX];
static bool is_iso_vs_emitted;
static isoal_status_t test_sink_sdu_alloc(const struct isoal_sink *sink_ctx,
const struct isoal_pdu_rx *valid_pdu,
struct isoal_sdu_buffer *sdu_buffer)
{
sdu_buffer->dbuf = test_rx_buffer;
sdu_buffer->size = sizeof(test_rx_buffer);
return ISOAL_STATUS_OK;
}
static isoal_status_t test_sink_sdu_emit(const struct isoal_sink *sink_ctx,
const struct isoal_sdu_produced *valid_sdu)
{
printk("Vendor sink SDU len %u, seq_num %u, ts %u\n",
sink_ctx->sdu_production.sdu_written, valid_sdu->seqn,
valid_sdu->timestamp);
is_iso_vs_emitted = true;
return ISOAL_STATUS_OK;
}
static isoal_status_t test_sink_sdu_write(void *dbuf,
const uint8_t *pdu_payload,
const size_t consume_len)
{
memcpy(dbuf, pdu_payload, consume_len);
return ISOAL_STATUS_OK;
}
bool ll_data_path_sink_create(struct ll_iso_datapath *datapath,
isoal_sink_sdu_alloc_cb *sdu_alloc,
isoal_sink_sdu_emit_cb *sdu_emit,
isoal_sink_sdu_write_cb *sdu_write)
{
ARG_UNUSED(datapath);
*sdu_alloc = test_sink_sdu_alloc;
*sdu_emit = test_sink_sdu_emit;
*sdu_write = test_sink_sdu_write;
printk("VS data path sink created\n");
return true;
}
#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */
static void test_iso_main(void)
{
struct bt_le_ext_adv *adv;
int err;
printk("\n*ISO broadcast test*\n");
printk("Bluetooth initializing...");
err = bt_enable(NULL);
if (err) {
FAIL("Could not init BT: %d\n", err);
return;
}
printk("success.\n");
printk("Create advertising set...");
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, &adv);
if (err) {
FAIL("Failed to create advertising set (err %d)\n", err);
return;
}
printk("success.\n");
printk("Setting Periodic Advertising parameters...");
err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT);
if (err) {
FAIL("Failed to set periodic advertising parameters (err %d)\n",
err);
return;
}
printk("success.\n");
printk("Enable Periodic Advertising...");
err = bt_le_per_adv_start(adv);
if (err) {
FAIL("Failed to enable periodic advertising (err %d)\n", err);
return;
}
printk("success.\n");
printk("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;
}
printk("success.\n");
#if TEST_LL_INTERFACE
printk("Creating BIG...");
uint16_t max_sdu = CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX;
uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE] = { 0 };
uint32_t sdu_interval = 10000; /* us */
uint16_t max_latency = 10; /* ms */
uint8_t encryption = 0;
uint8_t big_handle = 0;
uint8_t bis_count = 1; /* TODO: Add support for multiple BIS per BIG */
uint8_t phy = BIT(1);
uint8_t packing = 0;
uint8_t framing = 0;
uint8_t adv_handle;
uint8_t rtn = 0;
/* Assume that index == handle */
adv_handle = bt_le_ext_adv_get_index(adv);
err = ll_big_create(big_handle, adv_handle, bis_count, sdu_interval,
max_sdu, max_latency, rtn, phy, packing, framing,
encryption, bcode);
if (err) {
FAIL("Could not create BIG: %d\n", err);
return;
}
printk("success.\n");
#endif
printk("Creating BIG...\n");
struct bt_iso_big_create_param big_create_param;
struct bt_iso_big *big;
big_create_param.bis_channels = bis_channels;
big_create_param.num_bis = BIS_ISO_CHAN_COUNT;
big_create_param.encryption = false;
big_create_param.interval = 10000; /* us */
big_create_param.latency = 10; /* milliseconds */
big_create_param.packing = 0; /* 0 - sequential; 1 - interleaved */
big_create_param.framing = 0; /* 0 - unframed; 1 - framed */
iso_tx_qos.sdu = 502; /* bytes */
iso_tx_qos.rtn = 2;
iso_tx_qos.phy = BT_GAP_LE_PHY_2M;
bis_iso_qos.tx = &iso_tx_qos;
bis_iso_qos.rx = NULL;
err = bt_iso_big_create(adv, &big_create_param, &big);
if (err) {
FAIL("Could not create BIG: %d\n", err);
return;
}
printk("success.\n");
printk("Wait for ISO connected callback...");
while (!is_iso_connected) {
k_sleep(K_MSEC(100));
}
printk("ISO connected\n");
uint32_t iso_send_count = 0;
uint8_t iso_data[sizeof(iso_send_count)] = { 0 };
struct net_buf *buf;
buf = net_buf_alloc(&bis_tx_pool, K_FOREVER);
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));
err = bt_iso_chan_send(&bis_iso_chan, buf, seq_num++, BT_ISO_TIMESTAMP_NONE);
if (err < 0) {
net_buf_unref(buf);
FAIL("Unable to broadcast data (%d)", err);
return;
}
printk("Sending value %u\n", iso_send_count);
k_sleep(K_MSEC(5000));
printk("Update periodic advertising data 1...");
err = bt_le_per_adv_set_data(adv, per_ad_data1,
ARRAY_SIZE(per_ad_data1));
if (err) {
FAIL("Failed to update periodic advertising data 1 (%d).\n",
err);
}
printk("success.\n");
k_sleep(K_MSEC(2500));
printk("Periodic Advertising and ISO Channel Map Update...");
err = ll_chm_update(chan_map);
if (err) {
FAIL("Channel Map Update failed.\n");
}
printk("success.\n");
k_sleep(K_MSEC(2500));
printk("Update periodic advertising data 2...");
err = bt_le_per_adv_set_data(adv, per_ad_data2,
ARRAY_SIZE(per_ad_data2));
if (err) {
FAIL("Failed to update periodic advertising data 2 (%d).\n",
err);
}
printk("success.\n");
k_sleep(K_MSEC(5000));
#if TEST_LL_INTERFACE
printk("Terminating BIG...");
err = ll_big_terminate(big_handle, BT_HCI_ERR_LOCALHOST_TERM_CONN);
if (err) {
FAIL("Could not terminate BIG: %d\n", err);
return;
}
printk("success.\n");
#endif
printk("Terminating BIG...\n");
err = bt_iso_big_terminate(big);
if (err) {
FAIL("Could not terminate BIG: %d\n", err);
return;
}
printk("success.\n");
k_sleep(K_MSEC(10000));
printk("Stop Periodic Advertising...");
err = bt_le_per_adv_stop(adv);
if (err) {
FAIL("Failed to stop periodic advertising (err %d)\n", err);
return;
}
printk("success.\n");
PASS("ISO tests Passed\n");
return;
}
static const char *phy2str(uint8_t phy)
{
switch (phy) {
case 0: return "No packets";
case BT_GAP_LE_PHY_1M: return "LE 1M";
case BT_GAP_LE_PHY_2M: return "LE 2M";
case BT_GAP_LE_PHY_CODED: return "LE Coded";
default: return "Unknown";
}
}
static void iso_recv(struct bt_iso_chan *chan,
const struct bt_iso_recv_info *info, struct net_buf *buf)
{
printk("Incoming data channel %p len %u, flags %u, seq_num %u, ts %u\n",
chan, buf->len, info->flags, info->seq_num, info->ts);
}
static void iso_connected(struct bt_iso_chan *chan)
{
printk("ISO Channel %p connected\n", chan);
seq_num = 0U;
is_iso_connected = true;
}
static uint8_t volatile is_iso_disconnected;
static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
{
printk("ISO Channel %p disconnected with reason 0x%02x\n", chan, reason);
is_iso_disconnected = reason;
}
static bool volatile is_sync;
static void pa_sync_cb(struct bt_le_per_adv_sync *sync,
struct bt_le_per_adv_sync_synced_info *info)
{
char le_addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
"Interval 0x%04x (%u ms), PHY %s\n",
bt_le_per_adv_sync_get_index(sync), le_addr,
info->interval, info->interval * 5 / 4, phy2str(info->phy));
is_sync = true;
}
static void pa_terminated_cb(struct bt_le_per_adv_sync *sync,
const struct bt_le_per_adv_sync_term_info *info)
{
char le_addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
bt_le_per_adv_sync_get_index(sync), le_addr);
FAIL("PA terminated unexpectedly\n");
}
static bool volatile is_sync_recv;
static void pa_recv_cb(struct bt_le_per_adv_sync *sync,
const struct bt_le_per_adv_sync_recv_info *info,
struct net_buf_simple *buf)
{
char le_addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, "
"RSSI %i, CTE %u, data length %u\n",
bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power,
info->rssi, info->cte_type, buf->len);
is_sync_recv = true;
}
static void
pa_state_changed_cb(struct bt_le_per_adv_sync *sync,
const struct bt_le_per_adv_sync_state_info *info)
{
printk("PER_ADV_SYNC[%u]: state changed, receive %s.\n",
bt_le_per_adv_sync_get_index(sync),
info->recv_enabled ? "enabled" : "disabled");
}
static bool volatile is_big_info;
static void pa_biginfo_cb(struct bt_le_per_adv_sync *sync,
const struct bt_iso_biginfo *biginfo)
{
char le_addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(biginfo->addr, le_addr, sizeof(le_addr));
printk("BIG INFO[%u]: [DEVICE]: %s, sid 0x%02x, "
"num_bis %u, nse %u, interval 0x%04x (%u ms), "
"bn %u, pto %u, irc %u, max_pdu %u, "
"sdu_interval %u us, max_sdu %u, phy %s, "
"%s framing, %sencrypted\n",
bt_le_per_adv_sync_get_index(sync), le_addr, biginfo->sid,
biginfo->num_bis, biginfo->sub_evt_count,
biginfo->iso_interval,
(biginfo->iso_interval * 5 / 4),
biginfo->burst_number, biginfo->offset,
biginfo->rep_count, biginfo->max_pdu, biginfo->sdu_interval,
biginfo->max_sdu, phy2str(biginfo->phy),
biginfo->framing ? "with" : "without",
biginfo->encryption ? "" : "not ");
if (!is_big_info) {
is_big_info = true;
}
}
static struct bt_le_per_adv_sync_cb sync_cb = {
.synced = pa_sync_cb,
.term = pa_terminated_cb,
.recv = pa_recv_cb,
.state_changed = pa_state_changed_cb,
.biginfo = pa_biginfo_cb,
};
#define NAME_LEN 30
static bool data_cb(struct bt_data *data, void *user_data)
{
char *name = user_data;
switch (data->type) {
case BT_DATA_NAME_SHORTENED:
case BT_DATA_NAME_COMPLETE:
memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1));
return false;
default:
return true;
}
}
static bool volatile is_periodic;
static bt_addr_le_t per_addr;
static uint8_t per_sid;
static void scan_recv(const struct bt_le_scan_recv_info *info,
struct net_buf_simple *buf)
{
char le_addr[BT_ADDR_LE_STR_LEN];
char name[NAME_LEN];
(void)memset(name, 0, sizeof(name));
bt_data_parse(buf, data_cb, name);
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s "
"C:%u S:%u D:%u SR:%u E:%u Prim: %s, Secn: %s, "
"Interval: 0x%04x (%u ms), SID: %u\n",
le_addr, info->adv_type, info->tx_power, info->rssi, name,
(info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
(info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
(info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
(info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
(info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0,
phy2str(info->primary_phy), phy2str(info->secondary_phy),
info->interval, info->interval * 5 / 4, info->sid);
if (info->interval) {
if (!is_periodic) {
is_periodic = true;
per_sid = info->sid;
bt_addr_le_copy(&per_addr, info->addr);
}
}
}
static struct bt_le_scan_cb scan_callbacks = {
.recv = scan_recv,
};
static void test_iso_recv_main(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_HCI_LE_SCAN_ACTIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = 0x0004,
.window = 0x0004,
};
struct bt_le_per_adv_sync_param sync_create_param;
struct bt_le_per_adv_sync *sync = NULL;
int err;
printk("\n*ISO broadcast test*\n");
printk("Bluetooth initializing...");
err = bt_enable(NULL);
if (err) {
FAIL("Could not init BT: %d\n", err);
return;
}
printk("success.\n");
printk("Scan callbacks register...");
bt_le_scan_cb_register(&scan_callbacks);
printk("success.\n");
printk("Periodic Advertising callbacks register...");
bt_le_per_adv_sync_cb_register(&sync_cb);
printk("Success.\n");
printk("Start scanning...");
is_periodic = false;
err = bt_le_scan_start(&scan_param, NULL);
if (err) {
FAIL("Could not start scan: %d\n", err);
return;
}
printk("success.\n");
while (!is_periodic) {
k_sleep(K_MSEC(100));
}
printk("Periodic Advertising found (SID: %u)\n", per_sid);
printk("Creating Periodic Advertising Sync...");
is_sync = false;
bt_addr_le_copy(&sync_create_param.addr, &per_addr);
sync_create_param.options =
BT_LE_PER_ADV_SYNC_OPT_REPORTING_INITIALLY_DISABLED;
sync_create_param.sid = per_sid;
sync_create_param.skip = 0;
sync_create_param.timeout = 0xa;
err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
if (err) {
FAIL("Could not create sync: %d\n", err);
return;
}
printk("success.\n");
/* TODO: Enable when advertiser is added */
printk("Waiting for sync...");
while (!is_sync) {
k_sleep(K_MSEC(100));
}
printk("Stop scanning...");
err = bt_le_scan_stop();
if (err) {
FAIL("Could not stop scan: %d\n", err);
return;
}
printk("success.\n");
printk("Wait for BIG Info Advertising Report...");
is_big_info = false;
while (!is_big_info) {
k_sleep(K_MSEC(100));
}
printk("success.\n");
#if TEST_LL_INTERFACE
printk("Creating BIG Sync...");
uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE] = { 0 };
uint16_t sync_timeout = 10;
uint8_t big_handle = 0;
uint8_t bis_handle = 0;
uint8_t encryption = 0;
uint8_t bis_count = 1; /* TODO: Add support for multiple BIS per BIG */
uint8_t mse = 0;
err = ll_big_sync_create(big_handle, sync->handle, encryption, bcode,
mse, sync_timeout, bis_count, &bis_handle);
if (err) {
FAIL("Could not create BIG sync: %d\n", err);
return;
}
printk("success.\n");
k_sleep(K_MSEC(5000));
printk("Deleting Periodic Advertising Sync...");
err = bt_le_per_adv_sync_delete(sync);
if (err) {
FAIL("Failed to delete periodic advertising sync (err %d)\n",
err);
return;
}
printk("success.\n");
printk("Terminating BIG Sync...");
struct node_rx_hdr *node_rx = NULL;
err = ll_big_sync_terminate(big_handle, (void **)&node_rx);
if (err) {
FAIL("Could not terminate BIG sync: %d\n", err);
return;
}
printk("success.\n");
if (node_rx) {
FAIL("Generated Node Rx for synchronized BIG.\n");
}
k_sleep(K_MSEC(5000));
printk("Creating BIG Sync after terminate...");
err = ll_big_sync_create(big_handle, sync->handle, encryption, bcode,
mse, sync_timeout, bis_count, &bis_handle);
if (err) {
FAIL("Could not create BIG sync: %d\n", err);
return;
}
printk("success.\n");
printk("Terminating BIG Sync...");
node_rx = NULL;
err = ll_big_sync_terminate(big_handle, (void **)&node_rx);
if (err) {
FAIL("Could not terminate BIG sync: %d\n", err);
return;
}
printk("success.\n");
if (node_rx) {
node_rx->next = NULL;
ll_rx_mem_release((void **)&node_rx);
}
#else
struct bt_iso_big_sync_param big_param = { 0, };
struct bt_iso_big *big;
printk("ISO BIG create sync...");
is_iso_connected = false;
bis_iso_qos.tx = NULL;
bis_iso_qos.rx = &iso_rx_qos;
big_param.bis_channels = bis_channels;
big_param.num_bis = BIS_ISO_CHAN_COUNT;
big_param.bis_bitfield = BIT(1); /* BIS 1 selected */
big_param.mse = 1;
big_param.sync_timeout = 100; /* 1000 ms */
big_param.encryption = false;
iso_path_rx.pid = BT_HCI_DATAPATH_ID_HCI;
memset(big_param.bcode, 0, sizeof(big_param.bcode));
err = bt_iso_big_sync(sync, &big_param, &big);
if (err) {
FAIL("Could not create BIG sync: %d\n", err);
return;
}
printk("success.\n");
printk("Wait for ISO connected callback...");
while (!is_iso_connected) {
k_sleep(K_MSEC(100));
}
printk("ISO terminate BIG...");
is_iso_disconnected = 0U;
err = bt_iso_big_terminate(big);
if (err) {
FAIL("Could not terminate BIG sync: %d\n", err);
return;
}
printk("success.\n");
printk("Waiting for ISO disconnected callback...\n");
while (!is_iso_disconnected) {
k_sleep(K_MSEC(100));
}
printk("disconnected.\n");
if (is_iso_disconnected != BT_HCI_ERR_LOCALHOST_TERM_CONN) {
FAIL("Local Host Terminate Failed.\n");
}
printk("ISO BIG create sync (test remote disconnect)...");
is_iso_connected = false;
is_iso_disconnected = 0U;
err = bt_iso_big_sync(sync, &big_param, &big);
if (err) {
FAIL("Could not create BIG sync: %d\n", err);
return;
}
printk("success.\n");
printk("Wait for ISO connected callback...");
while (!is_iso_connected) {
k_sleep(K_MSEC(100));
}
printk("connected.\n");
printk("Waiting for ISO disconnected callback...\n");
while (!is_iso_disconnected) {
k_sleep(K_MSEC(100));
}
printk("disconnected.\n");
if (is_iso_disconnected != BT_HCI_ERR_REMOTE_USER_TERM_CONN) {
FAIL("Remote Host Terminate Failed.\n");
}
printk("Periodic sync receive enable...\n");
err = bt_le_per_adv_sync_recv_enable(sync);
if (err) {
printk("failed (err %d)\n", err);
return;
}
printk("receive enabled.\n");
uint8_t check_countdown = 3;
printk("Waiting for remote BIG terminate by checking for missing "
"%u BIG Info report...\n", check_countdown);
do {
is_sync_recv = false;
is_big_info = false;
while (!is_sync_recv) {
k_sleep(K_MSEC(100));
}
k_sleep(K_MSEC(100));
if (!is_big_info) {
if (!--check_countdown) {
break;
}
}
} while (1);
printk("success.\n");
printk("Deleting Periodic Advertising Sync...");
err = bt_le_per_adv_sync_delete(sync);
if (err) {
FAIL("Failed to delete periodic advertising sync (err %d)\n",
err);
return;
}
printk("success.\n");
#endif
PASS("ISO recv test Passed\n");
return;
}
#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH)
static void test_iso_recv_vs_dp_main(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_HCI_LE_SCAN_ACTIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = 0x0004,
.window = 0x0004,
};
struct bt_le_per_adv_sync_param sync_create_param;
struct bt_le_per_adv_sync *sync = NULL;
int err;
printk("Bluetooth initializing... ");
err = bt_enable(NULL);
if (err) {
FAIL("Could not init BT: %d\n", err);
return;
}
printk("success.\n");
printk("Scan callbacks register... ");
bt_le_scan_cb_register(&scan_callbacks);
printk("success.\n");
printk("Periodic Advertising callbacks register... ");
bt_le_per_adv_sync_cb_register(&sync_cb);
printk("success.\n");
printk("Start scanning... ");
is_periodic = false;
err = bt_le_scan_start(&scan_param, NULL);
if (err) {
FAIL("Could not start scan: %d\n", err);
return;
}
printk("success.\n");
while (!is_periodic) {
k_sleep(K_MSEC(100));
}
printk("Periodic Advertising found (SID: %u)\n", per_sid);
printk("Creating Periodic Advertising Sync... ");
is_sync = false;
bt_addr_le_copy(&sync_create_param.addr, &per_addr);
sync_create_param.options =
BT_LE_PER_ADV_SYNC_OPT_REPORTING_INITIALLY_DISABLED;
sync_create_param.sid = per_sid;
sync_create_param.skip = 0;
sync_create_param.timeout = 0xa;
err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
if (err) {
FAIL("Could not create sync: %d\n", err);
return;
}
printk("success.\n");
/* TODO: Enable when advertiser is added */
printk("Waiting for sync...\n");
while (!is_sync) {
k_sleep(K_MSEC(100));
}
printk("success.\n");
printk("Stop scanning... ");
err = bt_le_scan_stop();
if (err) {
FAIL("Could not stop scan: %d\n", err);
return;
}
printk("success.\n");
printk("Wait for BIG Info Advertising Report...\n");
is_big_info = false;
while (!is_big_info) {
k_sleep(K_MSEC(100));
}
printk("success.\n");
struct bt_iso_big_sync_param big_param = { 0, };
struct bt_iso_big *big;
printk("ISO BIG create sync... ");
is_iso_connected = false;
bis_iso_qos.tx = NULL;
bis_iso_qos.rx = &iso_rx_qos;
big_param.bis_channels = bis_channels;
big_param.num_bis = BIS_ISO_CHAN_COUNT;
big_param.bis_bitfield = BIT(1); /* BIS 1 selected */
big_param.mse = 1;
big_param.sync_timeout = 100; /* 1000 ms */
big_param.encryption = false;
memset(big_param.bcode, 0, sizeof(big_param.bcode));
is_iso_connected = false;
is_iso_disconnected = 0U;
is_iso_vs_emitted = false;
iso_path_rx.pid = BT_HCI_DATAPATH_ID_VS;
err = bt_iso_big_sync(sync, &big_param, &big);
if (err) {
FAIL("Could not create BIG sync: %d\n", err);
return;
}
printk("success.\n");
printk("Wait for ISO connected callback... ");
while (!is_iso_connected) {
k_sleep(K_MSEC(100));
}
/* Allow some SDUs to be received */
k_sleep(K_MSEC(100));
printk("ISO terminate BIG... ");
is_iso_disconnected = 0U;
err = bt_iso_big_terminate(big);
if (err) {
FAIL("Could not terminate BIG sync: %d\n", err);
return;
}
printk("success.\n");
printk("Waiting for ISO disconnected callback...\n");
while (!is_iso_disconnected) {
k_sleep(K_MSEC(100));
}
printk("disconnected.\n");
if (is_iso_disconnected != BT_HCI_ERR_LOCALHOST_TERM_CONN) {
FAIL("Local Host Terminate Failed.\n");
}
if (!is_iso_vs_emitted) {
FAIL("Emitting of VS SDUs failed.\n");
}
printk("success.\n");
printk("Deleting Periodic Advertising Sync... ");
err = bt_le_per_adv_sync_delete(sync);
if (err) {
FAIL("Failed to delete periodic advertising sync (err %d)\n",
err);
return;
}
printk("success.\n");
PASS("ISO recv VS test Passed\n");
}
#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */
static void test_iso_init(void)
{
bst_ticker_set_next_tick_absolute(60e6);
bst_result = In_progress;
}
static void test_iso_tick(bs_time_t HW_device_time)
{
if (bst_result != Passed) {
FAIL("test failed (not passed after seconds)\n");
}
}
static const struct bst_test_instance test_def[] = {
{
.test_id = "broadcast",
.test_descr = "ISO broadcast",
.test_post_init_f = test_iso_init,
.test_tick_f = test_iso_tick,
.test_main_f = test_iso_main
},
{
.test_id = "receive",
.test_descr = "ISO receive",
.test_post_init_f = test_iso_init,
.test_tick_f = test_iso_tick,
.test_main_f = test_iso_recv_main
},
#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH)
{
.test_id = "receive_vs_dp",
.test_descr = "ISO receive VS",
.test_post_init_f = test_iso_init,
.test_tick_f = test_iso_tick,
.test_main_f = test_iso_recv_vs_dp_main
},
#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */
BSTEST_END_MARKER
};
struct bst_test_list *test_iso_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_def);
}
bst_test_install_t test_installers[] = {
test_iso_install,
NULL
};
void main(void)
{
bst_main();
}