Commit da402c08 authored by Morten Priess's avatar Morten Priess Committed by Fabio Baltieri
Browse files

Bluetooth: controller: Implements ISO Test Mode HCI commands



Implements the flollowing HCI commands:
- HCI_LE_ISO_Transmit_Test
- HCI_LE_ISO_Receive_Test
- HCI_LE_ISO_Read_Test_Counters
- HCI_LE_ISO_Test_End

Signed-off-by: default avatarMorten Priess <mtpr@oticon.com>
parent 2a9b06b7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -2008,6 +2008,10 @@ struct bt_hci_rp_le_remove_iso_path {
	uint16_t handle;
} __packed;

#define BT_HCI_ISO_TEST_ZERO_SIZE_SDU     0
#define BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU 1
#define BT_HCI_ISO_TEST_MAX_SIZE_SDU      2

#define BT_HCI_OP_LE_ISO_TRANSMIT_TEST          BT_OP(BT_OGF_LE, 0x0070)
struct bt_hci_cp_le_iso_transmit_test {
	uint16_t handle;
+5 −0
Original line number Diff line number Diff line
@@ -1060,6 +1060,11 @@ void isoal_source_disable(isoal_source_handle_t hdl)
	isoal_global.source_state[hdl].pdu_production.mode = ISOAL_PRODUCTION_MODE_DISABLED;
}

struct isoal_source *isoal_source_get(isoal_source_handle_t hdl)
{
	return &isoal_global.source_state[hdl];
}

/**
 * @brief Disable and deallocate existing source
 * @param hdl[in]  Handle of existing instance
+2 −0
Original line number Diff line number Diff line
@@ -431,6 +431,8 @@ void isoal_source_enable(isoal_source_handle_t hdl);

void isoal_source_disable(isoal_source_handle_t hdl);

struct isoal_source *isoal_source_get(isoal_source_handle_t hdl);

void isoal_source_destroy(isoal_source_handle_t hdl);

isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl,
+0 −3
Original line number Diff line number Diff line
@@ -6387,9 +6387,6 @@ static uint8_t cis_req_recv(struct ll_conn *conn, memq_link_t *link,
	void *node;

	conn->llcp_cis.cig_id = req->cig_id;
	conn->llcp_cis.c_max_sdu = (uint16_t)(req->c_max_sdu_packed[1] & 0x0F) << 8 |
					      req->c_max_sdu_packed[0];
	conn->llcp_cis.p_max_sdu = (uint16_t)(req->p_max_sdu[1] & 0x0F) << 8 | req->p_max_sdu[0];
	conn->llcp_cis.cis_offset_min = sys_get_le24(req->cis_offset_min);
	conn->llcp_cis.cis_offset_max = sys_get_le24(req->cis_offset_max);
	conn->llcp_cis.conn_event_count = sys_le16_to_cpu(req->conn_event_count);
+60 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@

#include "isoal.h"
#include "ull_iso_types.h"
#include "ull_iso_internal.h"
#include "ull_conn_types.h"
#include "lll_conn_iso.h"
#include "ull_conn_iso_types.h"
@@ -109,8 +110,7 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_acquire(void)
	struct ll_conn_iso_stream *cis = mem_acquire(&cis_free);

	if (cis) {
		cis->hdr.datapath_in = NULL;
		cis->hdr.datapath_out = NULL;
		(void)memset(&cis->hdr, 0U, sizeof(cis->hdr));
	}

	return cis;
@@ -752,3 +752,61 @@ static void disable(uint16_t handle)
	cig->lll.handle = LLL_HANDLE_INVALID;
	cig->lll.resume_cis = LLL_HANDLE_INVALID;
}

/* An ISO interval has elapsed for a Connected Isochronous Group */
void ull_conn_iso_transmit_test_cig_interval(uint16_t handle, uint32_t ticks_at_expire)
{
	struct ll_conn_iso_stream *cis;
	struct ll_conn_iso_group *cig;
	uint32_t sdu_interval;
	uint32_t iso_interval;
	uint16_t handle_iter;
	uint64_t sdu_counter;
	uint8_t tx_sdu_count;

	cig = ll_conn_iso_group_get(handle);
	LL_ASSERT(cig);

	handle_iter = UINT16_MAX;

	if (cig->lll.role) {
		/* Peripheral */
		sdu_interval = cig->p_sdu_interval;
	} else {
		/* Central */
		sdu_interval = cig->c_sdu_interval;
	}

	iso_interval = cig->iso_interval * PERIODIC_INT_UNIT_US;

	/* Handle ISO Transmit Test for all active CISes in the group */
	for (uint8_t i = 0; i < cig->lll.num_cis; i++)  {
		cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter);
		LL_ASSERT(cis);

		if (!cis->hdr.test_mode.tx_enabled || cis->lll.handle == LLL_HANDLE_INVALID) {
			continue;
		}

		/* Calculate number of SDUs to transmit in the next ISO event. Ensure no overflow
		 * on 64-bit sdu_counter:
		 *   (39 bits x 22 bits (4x10^6 us) = 61 bits / 8 bits (255 us) = 53 bits)
		 */
		sdu_counter = ceiling_fraction((cis->lll.event_count + 1U) * iso_interval,
					       sdu_interval);

		if (cis->hdr.test_mode.tx_sdu_counter == 0U) {
			/* First ISO event. Align SDU counter for next event */
			cis->hdr.test_mode.tx_sdu_counter = sdu_counter;
			tx_sdu_count = 0U;
		} else {
			/* Calculate number of SDUs to produce for next ISO event */
			tx_sdu_count = sdu_counter - cis->hdr.test_mode.tx_sdu_counter;
		}

		/* Now process all SDUs due for next ISO event */
		for (uint8_t sdu = 0; sdu < tx_sdu_count; sdu++) {
			ll_iso_transmit_test_send_sdu(cis->lll.handle, ticks_at_expire);
		}
	}
}
Loading