This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 8bb24379f7821f1b6f0eaca50cfcb837288c1df6
Author: Mariusz Skamra <[email protected]>
AuthorDate: Thu Feb 20 16:29:05 2025 +0300

    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
---
 nimble/controller/include/controller/ble_ll_iso.h |  42 ++++-
 nimble/controller/src/ble_ll_hci.c                |   6 +
 nimble/controller/src/ble_ll_hci_supp_cmd.c       |   6 +
 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, 435 insertions(+), 26 deletions(-)

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 e969963ae..07b0aec1c 100644
--- a/nimble/controller/src/ble_ll_hci.c
+++ b/nimble/controller/src/ble_ll_hci.c
@@ -1284,6 +1284,9 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t 
len, uint16_t ocf,
     case BLE_HCI_OCF_LE_TERMINATE_BIG:
         rc = ble_ll_iso_big_hci_terminate(cmdbuf, len);
         break;
+    case BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST:
+        rc = ble_ll_iso_transmit_test(cmdbuf, len, rspbuf, rsplen);
+        break;
 #endif /* BLE_LL_ISO_BROADCASTER */
 #if MYNEWT_VAL(BLE_LL_ISO)
     case BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH:
@@ -1292,6 +1295,9 @@ 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_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 d9d6bd604..31edf1c2a 100644
--- a/nimble/controller/src/ble_ll_hci_supp_cmd.c
+++ b/nimble/controller/src/ble_ll_hci_supp_cmd.c
@@ -288,9 +288,15 @@ static const uint8_t octet_43 = OCTET(
     BIT(3) /* HCI LE Setup ISO Data Path */
     BIT(4) /* HCI LE Remove ISO Data Path */
 #endif
+#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER)
+    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 BLE_LL_HOST_CONTROLLED_FEATURES
     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 3ce5ddb74..1454ed6a5 100644
--- a/nimble/controller/src/ble_ll_iso_big.c
+++ b/nimble/controller/src/ble_ll_iso_big.c
@@ -683,7 +683,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;
@@ -923,12 +923,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;
@@ -984,9 +990,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 */
@@ -1005,11 +1011,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 <stdint.h>
+#include <controller/ble_ll_iso.h>
+#include <os/os_mbuf.h>
+#include <nimble/ble.h>
+#include <nimble/hci_common.h>
+#include <testutil/testutil.h>
+
+#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

Reply via email to