text: /* 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 };
  
  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, sn %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);
  	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, sn %u, ts %u\n",
  		chan, buf->len, info->flags, info->sn, info->ts);
  }
  
  static void iso_connected(struct bt_iso_chan *chan)
  {
  	printk("ISO Channel %p connected\n", chan);
  
  	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();
  }
  