Bluetooth: controller: Implement CSA #2 for SubEvents

Implement the functions required to calculate the SubEvent 1
and SubEvent n mapped channel indices.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig
index 4d220c2..8fe0335 100644
--- a/subsys/bluetooth/controller/Kconfig
+++ b/subsys/bluetooth/controller/Kconfig
@@ -641,6 +641,11 @@
 	  and will be invoked whenever the controller code encounters
 	  an unrecoverable error.
 
+config BT_CTLR_TEST
+	bool "Run in-system unit tests"
+	help
+	  Run in-system unit tests
+
 endif # BT_CTLR
 
 config BT_CTLR_DEBUG_PINS_CPUAPP
diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.c b/subsys/bluetooth/controller/ll_sw/lll_chan.c
index ffca8d0..fd29837 100644
--- a/subsys/bluetooth/controller/ll_sw/lll_chan.c
+++ b/subsys/bluetooth/controller/ll_sw/lll_chan.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Nordic Semiconductor ASA
+ * Copyright (c) 2018-2021 Nordic Semiconductor ASA
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -17,7 +17,15 @@
 
 static uint8_t chan_sel_remap(uint8_t *chan_map, uint8_t chan_index);
 #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
-static uint16_t chan_prn(uint16_t counter, uint16_t chan_id);
+static uint16_t chan_prn_s(uint16_t counter, uint16_t chan_id);
+static uint16_t chan_prn_e(uint16_t counter, uint16_t chan_id);
+
+#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_SYNC_ISO)
+static uint8_t chan_sel_remap_index(uint8_t *chan_map, uint8_t chan_index);
+static uint16_t chan_prn_subevent_se(uint16_t chan_id,
+				     uint16_t *prn_subevent_lu);
+static uint8_t chan_d(uint8_t n);
+#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_SYNC_ISO */
 #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */
 
 #if defined(CONFIG_BT_CONN)
@@ -58,7 +66,7 @@
 	uint8_t chan_next;
 	uint16_t prn_e;
 
-	prn_e = chan_prn(counter, chan_id);
+	prn_e = chan_prn_e(counter, chan_id);
 	chan_next = prn_e % 37;
 
 	if ((chan_map[chan_next >> 3] & (1 << (chan_next % 8))) == 0U) {
@@ -73,6 +81,61 @@
 
 	return chan_next;
 }
+
+#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_SYNC_ISO)
+uint8_t lll_chan_iso_event(uint16_t counter, uint16_t chan_id,
+			   uint8_t *chan_map, uint8_t chan_count,
+			   uint16_t *prn_s, uint16_t *remap_idx)
+{
+	uint8_t chan_idx;
+	uint16_t prn_e;
+
+	*prn_s = chan_prn_s(counter, chan_id);
+	prn_e = *prn_s ^ chan_id;
+	chan_idx = prn_e % 37;
+
+	if ((chan_map[chan_idx >> 3] & (1 << (chan_idx % 8))) == 0U) {
+		*remap_idx = ((uint32_t)chan_count * prn_e) >> 16;
+		chan_idx = chan_sel_remap(chan_map, *remap_idx);
+
+	} else {
+		*remap_idx = chan_sel_remap_index(chan_map, chan_idx);
+	}
+
+	return chan_idx;
+}
+
+uint8_t lll_chan_iso_subevent(uint16_t chan_id, uint8_t *chan_map,
+			      uint8_t chan_count, uint16_t *prn_subevent_lu,
+			      uint16_t *remap_idx)
+{
+	uint16_t prn_subevent_se;
+	uint8_t chan_idx;
+	uint8_t d;
+	uint8_t x;
+
+	prn_subevent_se = chan_prn_subevent_se(chan_id, prn_subevent_lu);
+
+	d = chan_d(chan_count);
+	if ((chan_count + 1) > (d << 1)) {
+		x = (chan_count + 1) - (d << 1);
+	} else {
+		x = 0;
+	}
+
+	chan_idx = ((((uint32_t)prn_subevent_se * x) >> 16) +
+		    d + *remap_idx) % chan_count;
+
+	if ((chan_map[chan_idx >> 3] & (1 << (chan_idx % 8))) == 0U) {
+		*remap_idx = chan_idx;
+		chan_idx = chan_sel_remap(chan_map, *remap_idx);
+	} else {
+		*remap_idx = chan_idx;
+	}
+
+	return chan_idx;
+}
+#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_SYNC_ISO */
 #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */
 
 static uint8_t chan_sel_remap(uint8_t *chan_map, uint8_t chan_index)
@@ -110,33 +173,6 @@
 }
 
 #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
-#if defined(RADIO_UNIT_TEST)
-void lll_chan_sel_2_ut(void)
-{
-	uint8_t chan_map_1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x1F};
-	uint8_t chan_map_2[] = {0x00, 0x06, 0xE0, 0x00, 0x1E};
-	uint8_t m;
-
-	m = chan_sel_2(1, 0x305F, chan_map_1, 37);
-	LL_ASSERT(m == 20U);
-
-	m = chan_sel_2(2, 0x305F, chan_map_1, 37);
-	LL_ASSERT(m == 6U);
-
-	m = chan_sel_2(3, 0x305F, chan_map_1, 37);
-	LL_ASSERT(m == 21U);
-
-	m = chan_sel_2(6, 0x305F, chan_map_2, 9);
-	LL_ASSERT(m == 23U);
-
-	m = chan_sel_2(7, 0x305F, chan_map_2, 9);
-	LL_ASSERT(m == 9U);
-
-	m = chan_sel_2(8, 0x305F, chan_map_2, 9);
-	LL_ASSERT(m == 34U);
-}
-#endif /* RADIO_UNIT_TEST */
-
 /* Attribution:
  * http://graphics.stanford.edu/%7Eseander/bithacks.html#ReverseByteWith32Bits
  */
@@ -158,20 +194,306 @@
 	return ((uint32_t)a * 17U + b) & 0xFFFF;
 }
 
-static uint16_t chan_prn(uint16_t counter, uint16_t chan_id)
+static uint16_t chan_prn_s(uint16_t counter, uint16_t chan_id)
 {
 	uint8_t iterate;
-	uint16_t prn_e;
+	uint16_t prn_s;
 
-	prn_e = counter ^ chan_id;
+	prn_s = counter ^ chan_id;
 
 	for (iterate = 0U; iterate < 3; iterate++) {
-		prn_e = chan_perm(prn_e);
-		prn_e = chan_mam(prn_e, chan_id);
+		prn_s = chan_perm(prn_s);
+		prn_s = chan_mam(prn_s, chan_id);
 	}
 
+	return prn_s;
+}
+
+static uint16_t chan_prn_e(uint16_t counter, uint16_t chan_id)
+{
+	uint16_t prn_e;
+
+	prn_e = chan_prn_s(counter, chan_id);
 	prn_e ^= chan_id;
 
 	return prn_e;
 }
+
+#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_SYNC_ISO)
+static uint8_t chan_sel_remap_index(uint8_t *chan_map, uint8_t chan_index)
+{
+	uint8_t octet_count;
+	uint8_t remap_index;
+
+	remap_index = 0U;
+	octet_count = 5U;
+	while (octet_count--) {
+		uint8_t octet;
+		uint8_t bit_count;
+
+		octet = *chan_map;
+		bit_count = 8U;
+		while (bit_count--) {
+			if (!chan_index) {
+				return remap_index;
+			}
+			chan_index--;
+
+			if (octet & BIT(0)) {
+				remap_index++;
+			}
+			octet >>= 1;
+		}
+
+		chan_map++;
+	}
+
+	return 0;
+}
+
+static uint16_t chan_prn_subevent_se(uint16_t chan_id,
+				     uint16_t *prn_subevent_lu)
+{
+	uint16_t prn_subevent_se;
+	uint16_t lu;
+
+	lu = *prn_subevent_lu;
+	lu = chan_perm(lu);
+	lu = chan_mam(lu, chan_id);
+
+	*prn_subevent_lu = lu;
+
+	prn_subevent_se = lu ^ chan_id;
+
+	return prn_subevent_se;
+}
+
+static uint8_t chan_d(uint8_t n)
+{
+	uint8_t x, y;
+
+	if (n > 5) {
+		x = n - 5;
+	} else {
+		x = 0;
+	}
+
+	if (n > 10) {
+		y = (n - 10) >> 1;
+	} else {
+		y = 0;
+	}
+
+	return MAX(1, MAX(MIN(3, x), MIN(11, y)));
+}
+#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_SYNC_ISO */
+
+#if defined(CONFIG_BT_CTLR_TEST)
+void lll_chan_sel_2_ut(void)
+{
+	uint8_t chan_map_1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x1F};
+	uint8_t chan_map_2[] = {0x00, 0x06, 0xE0, 0x00, 0x1E};
+	uint8_t m;
+
+	m = lll_chan_sel_2(0, 0x305F, chan_map_1, 37);
+	LL_ASSERT(m == 25U);
+
+	m = lll_chan_sel_2(1, 0x305F, chan_map_1, 37);
+	LL_ASSERT(m == 20U);
+
+	m = lll_chan_sel_2(2, 0x305F, chan_map_1, 37);
+	LL_ASSERT(m == 6U);
+
+	m = lll_chan_sel_2(3, 0x305F, chan_map_1, 37);
+	LL_ASSERT(m == 21U);
+
+	m = lll_chan_sel_2(6, 0x305F, chan_map_2, 9);
+	LL_ASSERT(m == 23U);
+
+	m = lll_chan_sel_2(7, 0x305F, chan_map_2, 9);
+	LL_ASSERT(m == 9U);
+
+	m = lll_chan_sel_2(8, 0x305F, chan_map_2, 9);
+	LL_ASSERT(m == 34U);
+
+
+
+#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_SYNC_ISO)
+	uint16_t prn_subevent_lu;
+	uint16_t prn_subevent_se;
+	uint16_t remap_idx;
+	uint16_t prn_s;
+
+	/* BIS subevent 2, event counter 0, test prnSubEvent_se */
+	prn_s = 56857 ^ 0x305F;
+	prn_subevent_lu = prn_s;
+	prn_subevent_se = chan_prn_subevent_se(0x305F, &prn_subevent_lu);
+	LL_ASSERT(prn_subevent_se == 11710);
+
+	/* BIS subevent 3, event counter 0 */
+	prn_subevent_se = chan_prn_subevent_se(0x305F, &prn_subevent_lu);
+	LL_ASSERT(prn_subevent_se == 16649);
+
+	/* BIS subevent 4, event counter 0 */
+	prn_subevent_se = chan_prn_subevent_se(0x305F, &prn_subevent_lu);
+	LL_ASSERT(prn_subevent_se == 38198);
+
+
+
+	/* BIS subevent 1, event counter 0 */
+	m = lll_chan_iso_event(0, 0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 56857);
+	LL_ASSERT(m == 25U);
+	LL_ASSERT(remap_idx == 25U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 1U);
+	LL_ASSERT(m == 1U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 16U);
+	LL_ASSERT(m == 16U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 36U);
+	LL_ASSERT(m == 36U);
+
+
+	/* BIS subevent 1, event counter 1 */
+	m = lll_chan_iso_event(1, 0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 1685);
+	LL_ASSERT(m == 20U);
+	LL_ASSERT(remap_idx == 20U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 36U);
+	LL_ASSERT(m == 36U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 12U);
+	LL_ASSERT(m == 12U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 34U);
+	LL_ASSERT(m == 34U);
+
+
+	/* BIS subevent 1, event counter 2 */
+	m = lll_chan_iso_event(2, 0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 38301);
+	LL_ASSERT(m == 6U);
+	LL_ASSERT(remap_idx == 6U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 18U);
+	LL_ASSERT(m == 18U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 32U);
+	LL_ASSERT(m == 32U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 21U);
+	LL_ASSERT(m == 21U);
+
+
+	/* BIS subevent 1, event counter 3 */
+	m = lll_chan_iso_event(3, 0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 27475);
+	LL_ASSERT(m == 21U);
+	LL_ASSERT(remap_idx == 21U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 4U);
+	LL_ASSERT(m == 4U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 22U);
+	LL_ASSERT(m == 22U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_1, 37, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 8U);
+	LL_ASSERT(m == 8U);
+
+
+
+	/* BIS subevent 1, event counter 6 */
+	m = lll_chan_iso_event(6, 0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 10975);
+	LL_ASSERT(remap_idx == 4U);
+	LL_ASSERT(m == 23U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 7U);
+	LL_ASSERT(m == 35U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 2U);
+	LL_ASSERT(m == 21U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 8U);
+	LL_ASSERT(m == 36U);
+
+
+	/* BIS subevent 1, event counter 7 */
+	m = lll_chan_iso_event(7, 0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 5490);
+	LL_ASSERT(remap_idx == 0U);
+	LL_ASSERT(m == 9U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 3U);
+	LL_ASSERT(m == 22U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 8U);
+	LL_ASSERT(m == 36U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 5U);
+	LL_ASSERT(m == 33U);
+
+
+	/* BIS subevent 1, event counter 8 */
+	m = lll_chan_iso_event(8, 0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT((prn_s ^ 0x305F) == 46970);
+	LL_ASSERT(remap_idx == 6U);
+	LL_ASSERT(m == 34U);
+
+	/* BIS subvent 2 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 0U);
+	LL_ASSERT(m == 9U);
+
+	/* BIS subvent 3 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 5U);
+	LL_ASSERT(m == 33U);
+
+	/* BIS subvent 4 */
+	m = lll_chan_iso_subevent(0x305F, chan_map_2, 9, &prn_s, &remap_idx);
+	LL_ASSERT(remap_idx == 1U);
+	LL_ASSERT(m == 10U);
+#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_SYNC_ISO */
+}
+#endif /* CONFIG_BT_CTLR_TEST */
 #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */
diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.h b/subsys/bluetooth/controller/ll_sw/lll_chan.h
index d384650..6105cb6 100644
--- a/subsys/bluetooth/controller/ll_sw/lll_chan.h
+++ b/subsys/bluetooth/controller/ll_sw/lll_chan.h
@@ -1,11 +1,21 @@
 /*
- * Copyright (c) 2018-2019 Nordic Semiconductor ASA
+ * Copyright (c) 2018-2021 Nordic Semiconductor ASA
  *
  * SPDX-License-Identifier: Apache-2.0
  */
 
 uint8_t lll_chan_sel_1(uint8_t *chan_use, uint8_t hop, uint16_t latency, uint8_t *chan_map,
 		    uint8_t chan_count);
+
 uint16_t lll_chan_id(uint8_t *access_addr);
 uint8_t lll_chan_sel_2(uint16_t counter, uint16_t chan_id, uint8_t *chan_map,
 		    uint8_t chan_count);
+
+uint8_t lll_chan_iso_event(uint16_t counter, uint16_t chan_id,
+			   uint8_t *chan_map, uint8_t chan_count,
+			   uint16_t *prn_s, uint16_t *remap_idx);
+uint8_t lll_chan_iso_subevent(uint16_t chan_id, uint8_t *chan_map,
+			      uint8_t chan_count, uint16_t *prn_subevent_lu,
+			      uint16_t *remap_idx);
+
+void lll_chan_sel_2_ut(void);
diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c
index e93f667..6067399 100644
--- a/subsys/bluetooth/controller/ll_sw/ull.c
+++ b/subsys/bluetooth/controller/ll_sw/ull.c
@@ -34,6 +34,7 @@
 #include "lll/lll_adv_types.h"
 #include "lll_adv.h"
 #include "lll/lll_adv_pdu.h"
+#include "lll_chan.h"
 #include "lll_scan.h"
 #include "lll/lll_df_types.h"
 #include "lll_sync.h"
@@ -619,6 +620,10 @@
 		ull_filter_reset(true);
 	}
 
+#if defined(CONFIG_BT_CTLR_TEST)
+	lll_chan_sel_2_ut();
+#endif /* CONFIG_BT_CTLR_TEST */
+
 	return  0;
 }