From a33bdc63eff65e9e6e03d715cabd2461e18d5dfc Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 20 Feb 2025 16:29:05 +0300 Subject: [PATCH] nimble/ll/iso: Add HCI LE ISO Transmit Test command This adds command implementation along with unit test. Fixes: LL/IST/BRD/BV-01-C --- .../include/controller/ble_ll_iso.h | 42 +++- nimble/controller/src/ble_ll_hci.c | 6 + nimble/controller/src/ble_ll_hci_supp_cmd.c | 4 + nimble/controller/src/ble_ll_iso.c | 187 ++++++++++++++++- nimble/controller/src/ble_ll_iso_big.c | 22 +- nimble/controller/test/src/ble_ll_iso.c | 191 ++++++++++++++++++ nimble/controller/test/src/ble_ll_test.c | 2 + nimble/include/nimble/hci_common.h | 5 + 8 files changed, 433 insertions(+), 26 deletions(-) create mode 100644 nimble/controller/test/src/ble_ll_iso.c diff --git a/nimble/controller/include/controller/ble_ll_iso.h b/nimble/controller/include/controller/ble_ll_iso.h index 768dd9923..8d6cbde56 100644 --- a/nimble/controller/include/controller/ble_ll_iso.h +++ b/nimble/controller/include/controller/ble_ll_iso.h @@ -27,10 +27,30 @@ extern "C" { #endif +struct ble_ll_iso_data_path { + uint8_t data_path_id; + uint8_t enabled : 1; +}; +struct ble_ll_iso_test_mode { + struct { + uint32_t rand; + uint8_t payload_type; + uint8_t enabled : 1; + } transmit; +}; struct ble_ll_iso_conn { /* Connection handle */ uint16_t handle; + /* Maximum SDU size */ + uint16_t max_sdu; + + /* ISO Data Path */ + struct ble_ll_iso_data_path data_path; + + /* ISO Test Mode */ + struct ble_ll_iso_test_mode test_mode; + /* ISOAL Multiplexer */ struct ble_ll_isoal_mux mux; @@ -48,7 +68,6 @@ int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, int ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd); int ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len); @@ -59,10 +78,10 @@ int ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); void ble_ll_iso_init(void); void ble_ll_iso_reset(void); @@ -70,11 +89,20 @@ void ble_ll_iso_reset(void); /* ISO Data handler */ int ble_ll_iso_data_in(struct os_mbuf *om); -int ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint8_t *llid, void *dptr); +int ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint32_t pkt_counter, uint8_t *llid, void *dptr); + +struct ble_ll_iso_conn_init_param { + uint32_t iso_interval_us; + uint32_t sdu_interval_us; + uint16_t conn_handle; + uint16_t max_sdu; + uint8_t max_pdu; + uint8_t framing; + uint8_t pte; + uint8_t bn; +}; -void ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, uint16_t conn_handle, - uint8_t max_pdu, uint32_t iso_interval_us, - uint32_t sdu_interval_us, uint8_t bn, uint8_t pte, uint8_t framing); +void ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, struct ble_ll_iso_conn_init_param *param); void ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn); int ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp); diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index 953636785..429a04178 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -1292,6 +1292,12 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH: rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len, rspbuf, rsplen); break; + case BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST: + rc = ble_ll_iso_transmit_test(cmdbuf, len, rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_ISO_TEST_END: + rc = ble_ll_iso_end_test(cmdbuf, len, rspbuf, rsplen); + break; case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC: rc = ble_ll_iso_read_tx_sync(cmdbuf, len, rspbuf, rsplen); break; diff --git a/nimble/controller/src/ble_ll_hci_supp_cmd.c b/nimble/controller/src/ble_ll_hci_supp_cmd.c index eb4182ed6..8e2fcbf6c 100644 --- a/nimble/controller/src/ble_ll_hci_supp_cmd.c +++ b/nimble/controller/src/ble_ll_hci_supp_cmd.c @@ -276,10 +276,14 @@ static const uint8_t octet_43 = OCTET( #if MYNEWT_VAL(BLE_LL_ISO) BIT(3) /* HCI LE Setup ISO Data Path */ BIT(4) /* HCI LE Remove ISO Data Path */ + BIT(5) /* HCI LE ISO Transmit Test */ #endif ); static const uint8_t octet_44 = OCTET( +#if MYNEWT_VAL(BLE_LL_ISO) + BIT(0) /* HCI LE ISO Test End */ +#endif #if MYNEWT_VAL(BLE_VERSION) >= 52 BIT(1) /* HCI LE Set Host Feature */ #endif diff --git a/nimble/controller/src/ble_ll_iso.c b/nimble/controller/src/ble_ll_iso.c index 034996d5f..03a31d5fa 100644 --- a/nimble/controller/src/ble_ll_iso.c +++ b/nimble/controller/src/ble_ll_iso.c @@ -46,6 +46,14 @@ ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, return BLE_ERR_UNK_CONN_ID; } + if (conn->mux.bn == 0) { + return BLE_ERR_UNSUPPORTED; + } + + if (conn->data_path.enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + /* Only input for now since we only support BIS */ if (cmd->data_path_dir) { return BLE_ERR_CMD_DISALLOWED; @@ -56,6 +64,9 @@ ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, return BLE_ERR_CMD_DISALLOWED; } + conn->data_path.enabled = 1; + conn->data_path.data_path_id = cmd->data_path_id; + rsp->conn_handle = cmd->conn_handle; *rsplen = sizeof(*rsp); @@ -68,8 +79,23 @@ ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, { const struct ble_hci_le_remove_iso_data_path_cp *cmd = (const void *)cmdbuf; struct ble_hci_le_remove_iso_data_path_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *conn; + uint16_t conn_handle; + + conn_handle = le16toh(cmd->conn_handle); + + conn = ble_ll_iso_conn_find_by_handle(conn_handle); + if (!conn) { + return BLE_ERR_UNK_CONN_ID; + } + + /* Only input for now since we only support BIS */ + if (cmd->data_path_dir) { + return BLE_ERR_CMD_DISALLOWED; + } + + conn->data_path.enabled = 0; - /* XXX accepts anything for now */ rsp->conn_handle = cmd->conn_handle; *rsplen = sizeof(*rsp); @@ -101,6 +127,76 @@ ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t cmdlen, return 0; } +int +ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_iso_transmit_test_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_iso_transmit_test_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *conn; + uint16_t handle; + + handle = le16toh(cmd->conn_handle); + + conn = ble_ll_iso_conn_find_by_handle(handle); + if (!conn) { + return BLE_ERR_UNK_CONN_ID; + } + + if (conn->mux.bn == 0) { + return BLE_ERR_UNSUPPORTED; + } + + if (conn->data_path.enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (cmd->payload_type > BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH) { + return BLE_ERR_INV_LMP_LL_PARM; + } + + conn->data_path.enabled = 1; + conn->data_path.data_path_id = BLE_HCI_ISO_DATA_PATH_ID_HCI; + conn->test_mode.transmit.enabled = 1; + conn->test_mode.transmit.payload_type = cmd->payload_type; + + rsp->conn_handle = cmd->conn_handle; + + *rsplen = sizeof(*rsp); + + return 0; +} + +int +ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_iso_test_end_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_iso_test_end_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *iso_conn; + uint16_t handle; + + handle = le16toh(cmd->conn_handle); + iso_conn = ble_ll_iso_conn_find_by_handle(handle); + if (!iso_conn) { + return BLE_ERR_UNK_CONN_ID; + } + + if (!iso_conn->test_mode.transmit.enabled) { + return BLE_ERR_UNSUPPORTED; + } + + iso_conn->data_path.enabled = 0; + iso_conn->test_mode.transmit.enabled = 0; + + rsp->conn_handle = cmd->conn_handle; + rsp->received_sdu_count = 0; + rsp->missed_sdu_count = 0; + rsp->failed_sdu_count = 0; + + *rsplen = sizeof(*rsp); + + return 0; +} + struct ble_ll_iso_conn * ble_ll_iso_conn_find_by_handle(uint16_t conn_handle) { @@ -213,26 +309,93 @@ ble_ll_iso_data_in(struct os_mbuf *om) return 0; } +static int +ble_ll_iso_test_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint32_t pkt_counter, uint8_t *llid, uint8_t *dptr) +{ + uint32_t payload_len; + uint16_t rem_len; + uint8_t sdu_idx; + uint8_t pdu_idx; + int pdu_len; + + BLE_LL_ASSERT(!conn->mux.framed); + + sdu_idx = idx / conn->mux.pdu_per_sdu; + pdu_idx = idx - sdu_idx * conn->mux.pdu_per_sdu; + + switch (conn->test_mode.transmit.payload_type) { + case BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH: + *llid = 0b00; + pdu_len = 0; + break; + case BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH: + payload_len = max(conn->test_mode.transmit.rand + (sdu_idx * pdu_idx), 4); + + rem_len = payload_len - pdu_idx * conn->mux.max_pdu; + if (rem_len == 0) { + *llid = 0b01; + pdu_len = 0; + } else { + *llid = rem_len > conn->mux.max_pdu; + pdu_len = min(conn->mux.max_pdu, rem_len); + } + + memset(dptr, 0, pdu_len); + + if (payload_len == rem_len) { + put_le32(dptr, pkt_counter); + } + + break; + case BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH: + payload_len = conn->max_sdu; + + rem_len = payload_len - pdu_idx * conn->mux.max_pdu; + if (rem_len == 0) { + *llid = 0b01; + pdu_len = 0; + } else { + *llid = rem_len > conn->mux.max_pdu; + pdu_len = min(conn->mux.max_pdu, rem_len); + } + + memset(dptr, 0, pdu_len); + + if (payload_len == rem_len) { + put_le32(dptr, pkt_counter); + } + + break; + default: + BLE_LL_ASSERT(0); + } + + return pdu_len; +} + int -ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint8_t *llid, void *dptr) +ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint32_t pkt_counter, uint8_t *llid, void *dptr) { + if (conn->test_mode.transmit.enabled) { + return ble_ll_iso_test_pdu_get(conn, idx, pkt_counter, llid, dptr); + } + return ble_ll_isoal_mux_pdu_get(&conn->mux, idx, llid, dptr); } void -ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, uint16_t conn_handle, - uint8_t max_pdu, uint32_t iso_interval_us, - uint32_t sdu_interval_us, uint8_t bn, uint8_t pte, - uint8_t framing) +ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, struct ble_ll_iso_conn_init_param *param) { os_sr_t sr; memset(conn, 0, sizeof(*conn)); - conn->handle = conn_handle; - ble_ll_isoal_mux_init(&conn->mux, max_pdu, iso_interval_us, sdu_interval_us, - bn, pte, BLE_LL_ISOAL_MUX_IS_FRAMED(framing), - framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED); + conn->handle = param->conn_handle; + conn->max_sdu = param->max_sdu; + + ble_ll_isoal_mux_init(&conn->mux, param->max_pdu, param->iso_interval_us, param->sdu_interval_us, + param->bn, param->pte, BLE_LL_ISOAL_MUX_IS_FRAMED(param->framing), + param->framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED); OS_ENTER_CRITICAL(sr); STAILQ_INSERT_TAIL(&ll_iso_conn_q, conn, iso_conn_q_next); @@ -254,6 +417,10 @@ ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn) int ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp) { + if (conn->test_mode.transmit.enabled) { + conn->test_mode.transmit.rand = ble_ll_rand() % conn->max_sdu; + } + ble_ll_isoal_mux_event_start(&conn->mux, timestamp); return 0; diff --git a/nimble/controller/src/ble_ll_iso_big.c b/nimble/controller/src/ble_ll_iso_big.c index efc81c4a3..9630474be 100644 --- a/nimble/controller/src/ble_ll_iso_big.c +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -670,7 +670,7 @@ ble_ll_iso_big_subevent_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) } #if 1 - pdu_len = ble_ll_iso_pdu_get(&bis->conn, idx, &llid, dptr); + pdu_len = ble_ll_iso_pdu_get(&bis->conn, idx, big->bis_counter + idx, &llid, dptr); #else llid = 0; pdu_len = big->max_pdu; @@ -910,12 +910,18 @@ static int ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, struct big_params *bp) { + struct ble_ll_iso_conn_init_param conn_init_param = { + .iso_interval_us = bp->iso_interval * 1250, + .sdu_interval_us = bp->sdu_interval, + .max_sdu = bp->max_sdu, + .max_pdu = bp->max_pdu, + .framing = bp->framing, + .bn = bp->bn, + }; struct ble_ll_iso_big *big = NULL; struct ble_ll_iso_bis *bis; struct ble_ll_adv_sm *advsm; uint32_t seed_aa; - uint16_t conn_handle; - uint8_t pte; uint8_t gc; uint8_t idx; int rc; @@ -971,9 +977,9 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, /* Core 5.3, Vol 6, Part B, 4.4.6.6 */ gc = bp->nse / bp->bn; if (bp->irc == gc) { - pte = 0; + conn_init_param.pte = 0; } else { - pte = bp->pto * (gc - bp->irc); + conn_init_param.pte = bp->pto * (gc - bp->irc); } /* Allocate BISes */ @@ -992,11 +998,9 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, bis->num = big->num_bis; bis->crc_init = (big->crc_init << 8) | (big->num_bis); - conn_handle = BLE_LL_CONN_HANDLE(BLE_LL_CONN_HANDLE_TYPE_BIS, idx); + conn_init_param.conn_handle = BLE_LL_CONN_HANDLE(BLE_LL_CONN_HANDLE_TYPE_BIS, idx); - ble_ll_iso_conn_init(&bis->conn, conn_handle, bp->max_pdu, - bp->iso_interval * 1250, bp->sdu_interval, - bp->bn, pte, bp->framing); + ble_ll_iso_conn_init(&bis->conn, &conn_init_param); } bis_pool_free -= num_bis; diff --git a/nimble/controller/test/src/ble_ll_iso.c b/nimble/controller/test/src/ble_ll_iso.c new file mode 100644 index 000000000..2f88214c9 --- /dev/null +++ b/nimble/controller/test/src/ble_ll_iso.c @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define TSPX_max_tx_nse 3 +#define TSPX_max_tx_payload 32 + +/* LL.TS.p24 4.11.2 Common Parameters */ +struct test_ll_common_params { + uint8_t TxNumBIS; + uint8_t RxNumBIS; + uint8_t NumDataPDUs; + uint8_t RTN; + uint8_t NSE; + uint8_t IRC; + uint8_t PTO; + uint8_t BN; + uint8_t Transport_Latency; + uint8_t SDU_Interval; + uint8_t ISO_Interval; + uint8_t BIG_Sync_Timeout; + uint8_t Data_Size; + uint8_t PHY; + uint8_t Packing; + uint8_t Framing; + uint8_t Encryption; + uint8_t PADV_Interval; + uint8_t Sync_Timeout; +}; + +const struct test_ll_common_params test_ll_common_params_bn_1 = { + .TxNumBIS = 1, + .RxNumBIS = 1, + .NumDataPDUs = 20, + .RTN = TSPX_max_tx_nse, + .NSE = TSPX_max_tx_nse, + .IRC = TSPX_max_tx_nse, + .PTO = 0, + .BN = 1, + .Transport_Latency = 20, + .SDU_Interval = 10, + .ISO_Interval = 10, + .BIG_Sync_Timeout = 100, + .Data_Size = 0, + .PHY = 0x01, + .Packing = 0x00, + .Framing = 0x00, + .Encryption = 0x00, + .PADV_Interval = 20, + .Sync_Timeout = 100, +}; + +TEST_CASE_SELF(test_ll_ist_brd_bv_01_c) { + const uint8_t payload_types[] = { + BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH, + BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH, + BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH + }; + const struct test_ll_common_params *params = &test_ll_common_params_bn_1; + struct ble_hci_le_setup_iso_data_path_cp setup_iso_data_path_cp; + struct ble_hci_le_setup_iso_data_path_rp setup_iso_data_path_rp; + struct ble_hci_le_iso_transmit_test_cp iso_transmit_test_cp; + struct ble_hci_le_iso_transmit_test_rp iso_transmit_test_rp; + struct ble_hci_le_iso_test_end_cp iso_test_end_cp; + struct ble_hci_le_iso_test_end_rp iso_test_end_rp; + struct ble_ll_iso_conn_init_param conn_param = { + .iso_interval_us = params->SDU_Interval * 1000, + .sdu_interval_us = params->SDU_Interval * 1000, + .conn_handle = 0x0001, + .max_sdu = TSPX_max_tx_payload, + .max_pdu = TSPX_max_tx_payload, + .framing = params->Framing, + .bn = params->BN + }; + struct ble_ll_iso_conn conn; + uint8_t payload_type; + uint8_t pdu[100]; + uint8_t llid; + uint8_t rsplen = 0; + int rc; + + ble_ll_iso_conn_init(&conn, &conn_param); + + for (uint8_t i = 0; i < ARRAY_SIZE(payload_types); i++) { + payload_type = payload_types[i]; + + /* 2. The Upper Tester sends the HCI_LE_ISO_Transmit_Test command with Payload_Type as + * specified in Table 4.12-2 and receives a successful HCI_Command_Complete event from the IUT in response. + */ + rsplen = 0xFF; + iso_transmit_test_cp.conn_handle = htole16(conn.handle); + iso_transmit_test_cp.payload_type = payload_type; + rc = ble_ll_iso_transmit_test((uint8_t *)&iso_transmit_test_cp, sizeof(iso_transmit_test_cp), + (uint8_t *)&iso_transmit_test_rp, &rsplen); + TEST_ASSERT(rc == 0); + TEST_ASSERT(rsplen == sizeof(iso_transmit_test_rp)); + TEST_ASSERT(iso_transmit_test_rp.conn_handle == iso_transmit_test_cp.conn_handle); + + /* 3. The IUT sends isochronous data PDUs with Payload as specified in Table 4.12-2. The SDU + * Count value meets the requirements for unframed PDUs as specified in [14] Section 7.1. + * 4. Repeat step 3 for a total of 5 payloads. + */ + for (uint8_t j = 0; j < 5; j++) { + rc = ble_ll_iso_conn_event_start(&conn, 30000); + TEST_ASSERT(rc == 0); + + for (uint8_t k = 0; k < conn_param.bn; k++) { + llid = 0xFF; + rc = ble_ll_iso_pdu_get(&conn, k, k, &llid, pdu); + if (payload_type == BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH) { + TEST_ASSERT(rc == 0); + TEST_ASSERT(llid == 0b00); + } else if (payload_type == BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH) { + TEST_ASSERT(rc >= 4); + TEST_ASSERT(llid == 0b00); + } else if (payload_type == BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH) { + TEST_ASSERT(rc == conn_param.max_pdu); + TEST_ASSERT(llid == 0b00); + } + } + + rc = ble_ll_iso_conn_event_done(&conn); + TEST_ASSERT(rc == 0); + } + + /* 5. The Upper Tester sends an HCI_LE_Setup_ISO_Data_Path command to the IUT. + * 6. The IUT sends an HCI_Command_Complete event to the Upper Tester with Status set to 0x0C. + */ + setup_iso_data_path_cp.conn_handle = htole16(conn.handle); + setup_iso_data_path_cp.data_path_dir = 0x00; + setup_iso_data_path_cp.data_path_id = 0x00; + rc = ble_ll_iso_setup_iso_data_path((uint8_t *)&setup_iso_data_path_cp, sizeof(setup_iso_data_path_cp), + (uint8_t *)&setup_iso_data_path_rp, &rsplen); + TEST_ASSERT(rc == 0x0C); + + /* 7. The Upper Tester sends the HCI_LE_ISO_Test_End command to the IUT and receives an + * HCI_Command_Status event from the IUT with the Status field set to Success. The returned + * Received_SDU_Count, Missed_SDU_Count, and Failed_SDU_Count are all zero. + */ + rsplen = 0xFF; + iso_test_end_cp.conn_handle = htole16(conn.handle); + rc = ble_ll_iso_end_test((uint8_t *)&iso_test_end_cp, sizeof(iso_test_end_cp), + (uint8_t *)&iso_test_end_rp, &rsplen); + TEST_ASSERT(rc == 0); + TEST_ASSERT(rsplen == sizeof(iso_test_end_rp)); + TEST_ASSERT(iso_test_end_rp.conn_handle == iso_test_end_cp.conn_handle); + TEST_ASSERT(iso_test_end_rp.received_sdu_count == 0); + TEST_ASSERT(iso_test_end_rp.missed_sdu_count == 0); + TEST_ASSERT(iso_test_end_rp.failed_sdu_count == 0); + } + + ble_ll_iso_conn_free(&conn); +} + +TEST_SUITE(ble_ll_iso_test_suite) { + ble_ll_iso_init(); + + test_ll_ist_brd_bv_01_c(); + + ble_ll_iso_reset(); +} diff --git a/nimble/controller/test/src/ble_ll_test.c b/nimble/controller/test/src/ble_ll_test.c index 7bfbf9bd2..818430c57 100644 --- a/nimble/controller/test/src/ble_ll_test.c +++ b/nimble/controller/test/src/ble_ll_test.c @@ -26,6 +26,7 @@ TEST_SUITE_DECL(ble_ll_aa_test_suite); TEST_SUITE_DECL(ble_ll_crypto_test_suite); TEST_SUITE_DECL(ble_ll_csa2_test_suite); TEST_SUITE_DECL(ble_ll_isoal_test_suite); +TEST_SUITE_DECL(ble_ll_iso_test_suite); int main(int argc, char **argv) @@ -34,6 +35,7 @@ main(int argc, char **argv) ble_ll_crypto_test_suite(); ble_ll_csa2_test_suite(); ble_ll_isoal_test_suite(); + ble_ll_iso_test_suite(); return tu_any_failed; } diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index f1d2eb46d..24843de3c 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1647,6 +1647,11 @@ struct ble_hci_vs_set_scan_cfg_cp { #define BLE_HCI_PRIVACY_NETWORK (0) #define BLE_HCI_PRIVACY_DEVICE (1) +/* --- LE iso transmit test payload type options (OCF 0x0070) */ +#define BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH (0x00) +#define BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH (0x01) +#define BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH (0x02) + /* --- LE set advertising coded PHY options (OCF 0x007F) */ #define BLE_HCI_ADVERTISING_PHY_OPT_NO_PREF 0x0 #define BLE_HCI_ADVERTISING_PHY_OPT_S2_PREF 0x1