diff --git a/nimble/controller/include/controller/ble_ll_iso.h b/nimble/controller/include/controller/ble_ll_iso.h index c36417077d..768dd9923e 100644 --- a/nimble/controller/include/controller/ble_ll_iso.h +++ b/nimble/controller/include/controller/ble_ll_iso.h @@ -74,7 +74,7 @@ int ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint8_t *llid, 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); + uint32_t sdu_interval_us, uint8_t bn, uint8_t pte, uint8_t framing); 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/include/controller/ble_ll_isoal.h b/nimble/controller/include/controller/ble_ll_isoal.h index 4e77b42990..8bc3f28783 100644 --- a/nimble/controller/include/controller/ble_ll_isoal.h +++ b/nimble/controller/include/controller/ble_ll_isoal.h @@ -20,16 +20,13 @@ #ifndef H_BLE_LL_ISOAL_ #define H_BLE_LL_ISOAL_ +#include #include #ifdef __cplusplus extern "C" { #endif -#if MYNEWT_VAL(BLE_LL_ISO) - -#include - struct ble_ll_isoal_mux { #if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL) uint8_t active; @@ -37,14 +34,16 @@ struct ble_ll_isoal_mux { /* Max PDU length */ uint8_t max_pdu; - /* Number of expected SDUs per ISO interval */ - uint8_t sdu_per_interval; + /* Number of expected PDUs per SDU */ uint8_t pdu_per_sdu; - /* Number of SDUs required to fill complete BIG/CIG event (i.e. with pt) */ - uint8_t sdu_per_event; - /* Number of SDUs available for current event */ - uint8_t sdu_in_event; + + /* Number of PDUs available for current event */ + uint8_t pdu_in_event; + /* Number of expected PDUs per ISO interval */ + uint8_t pdu_per_interval; + /* Number of PDUs required to fill complete BIG/CIG event (i.e. with pt) */ + uint8_t pdu_per_event; STAILQ_HEAD(, os_mbuf_pkthdr) sdu_q; uint16_t sdu_q_len; @@ -54,28 +53,42 @@ struct ble_ll_isoal_mux { uint32_t event_tx_timestamp; uint32_t last_tx_timestamp; uint16_t last_tx_packet_seq_num; + + /* The head SDU Segment is the Continuation of an SDU */ + uint8_t sc : 1; + uint8_t framed : 1; + uint8_t framing_mode : 1; }; +#define BLE_LL_ISOAL_SEGHDR(sc, cmplt, len) \ + ((uint16_t)((sc) & 0x01) | (((cmplt) & 0x01) << 1) | ((len) & 0xff) << 8) + +#define BLE_LL_ISOAL_SEGHDR_SC(word) ((word) & 0x01) +#define BLE_LL_ISOAL_SEGHDR_CMPLT(word) ((word >> 1) & 0x01) +#define BLE_LL_ISOAL_SEGHDR_LEN(word) ((word >> 8) & 0xff) + +#define BLE_LL_ISOAL_MUX_IS_FRAMED(framing) \ + ((framing) == BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE || \ + (framing) == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED) + void ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, uint32_t iso_interval_us, uint32_t sdu_interval_us, - uint8_t bn, uint8_t pte); + uint8_t bn, uint8_t pte, bool framed, bool framing_mode); void ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux); -int ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, - uint32_t timestamp); +void ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, + uint32_t timestamp); int ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux); int ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, uint8_t *llid, void *dptr); void ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, - struct os_mbuf *om, uint32_t timestamp); + struct os_mbuf *om); void ble_ll_isoal_init(void); void ble_ll_isoal_reset(void); -#endif /* BLE_LL_ISO */ - #ifdef __cplusplus } #endif diff --git a/nimble/controller/src/ble_ll_iso.c b/nimble/controller/src/ble_ll_iso.c index 6ac5c93ec5..1caba9930f 100644 --- a/nimble/controller/src/ble_ll_iso.c +++ b/nimble/controller/src/ble_ll_iso.c @@ -23,6 +23,7 @@ #include #include #include +#include #if MYNEWT_VAL(BLE_LL_ISO) @@ -129,11 +130,12 @@ ble_ll_iso_reset(void) } int -ble_ll_iso_data_handle(struct os_mbuf *om) +ble_ll_iso_data_in(struct os_mbuf *om) { struct ble_hci_iso *hci_iso; struct ble_hci_iso_data *hci_iso_data; struct ble_ll_iso_conn *conn; + struct ble_mbuf_hdr *blehdr; uint16_t data_hdr_len; uint16_t handle; uint16_t conn_handle; @@ -150,13 +152,24 @@ ble_ll_iso_data_handle(struct os_mbuf *om) ts_flag = BLE_HCI_ISO_TS_FLAG(handle); length = BLE_HCI_ISO_LENGTH(le16toh(hci_iso->length)); + conn = ble_ll_iso_conn_find_by_handle(conn_handle); + if (!conn) { + os_mbuf_free_chain(om); + return BLE_ERR_UNK_CONN_ID; + } + data_hdr_len = 0; if ((pb_flag == BLE_HCI_ISO_PB_FIRST) || (pb_flag == BLE_HCI_ISO_PB_COMPLETE)) { + blehdr = BLE_MBUF_HDR_PTR(om); + blehdr->txiso.packet_seq_num = ++conn->mux.sdu_counter; + blehdr->txiso.cpu_timestamp = ble_ll_tmr_get(); + if (ts_flag) { timestamp = get_le32(om->om_data + sizeof(*hci_iso)); data_hdr_len += sizeof(uint32_t); } + blehdr->txiso.hci_timestamp = timestamp; hci_iso_data = (void *)(om->om_data + sizeof(*hci_iso) + data_hdr_len); data_hdr_len += sizeof(*hci_iso_data); @@ -168,12 +181,6 @@ ble_ll_iso_data_handle(struct os_mbuf *om) return BLE_ERR_MEM_CAPACITY; } - conn = ble_ll_iso_conn_find_by_handle(conn_handle); - if (!conn) { - os_mbuf_free_chain(om); - return BLE_ERR_UNK_CONN_ID; - } - switch (pb_flag) { case BLE_HCI_ISO_PB_FIRST: BLE_LL_ASSERT(!conn->frag); @@ -200,7 +207,7 @@ ble_ll_iso_data_handle(struct os_mbuf *om) } if (om) { - ble_ll_isoal_mux_sdu_enqueue(&conn->mux, om, timestamp); + ble_ll_isoal_mux_sdu_enqueue(&conn->mux, om); } return 0; @@ -215,14 +222,17 @@ ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint8_t *llid, voi 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) + uint32_t sdu_interval_us, uint8_t bn, uint8_t pte, + uint8_t framing) { 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_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); OS_ENTER_CRITICAL(sr); STAILQ_INSERT_TAIL(&ll_iso_conn_q, conn, iso_conn_q_next); @@ -242,13 +252,14 @@ ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn) } int -ble_ll_iso_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp) +ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp) { - return ble_ll_isoal_mux_event_start(&conn->mux, timestamp); + ble_ll_isoal_mux_event_start(&conn->mux, timestamp); + return 0; } int -ble_ll_iso_event_done(struct ble_ll_iso_conn *conn) +ble_ll_iso_conn_event_done(struct ble_ll_iso_conn *conn) { conn->num_completed_pkt += ble_ll_isoal_mux_event_done(&conn->mux); return conn->num_completed_pkt; diff --git a/nimble/controller/src/ble_ll_iso_big.c b/nimble/controller/src/ble_ll_iso_big.c index dd781fdf63..f7a3dd87de 100644 --- a/nimble/controller/src/ble_ll_iso_big.c +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -86,8 +86,8 @@ struct big_params { uint16_t max_sdu; uint8_t max_pdu; uint8_t phy; + uint8_t framing; uint8_t interleaved : 1; - uint8_t framed : 1; uint8_t encrypted : 1; uint8_t broadcast_code[16]; }; @@ -110,6 +110,7 @@ struct ble_ll_iso_big { uint8_t nse; /* 1-31 */ uint8_t interleaved : 1; uint8_t framed : 1; + uint8_t framing_mode : 1; uint8_t encrypted : 1; uint8_t giv[8]; uint8_t gskd[16]; @@ -223,8 +224,8 @@ ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, uint32_t seed_aa) put_le24(buf, (big->irc << 20) | (big->bis_spacing)); buf += 3; - /* max_pdu, rfu */ - put_le16(buf, big->max_pdu); + /* max_pdu, rfu, framing_mode */ + put_le16(buf, big->max_pdu | (big->framing_mode) << 15); buf += 2; /* seed_access_address */ @@ -245,7 +246,8 @@ ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, uint32_t seed_aa) buf += 5; /* bis_payload_cnt, framing */ - memset(buf, 0x00, 5); + memset(buf, 0x01, 5); + buf[4] |= (big->framed << 7) & 0x80; } int @@ -306,7 +308,7 @@ ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, *dptr++ = (counter >> 8) & 0xff; *dptr++ = (counter >> 16) & 0xff; *dptr++ = (counter >> 24) & 0xff; - *dptr++ = (counter >> 32) & 0xff; + *dptr++ = ((counter >> 32) & 0x7f) | ((big->framed << 7) & 0x80); if (big->encrypted) { memcpy(dptr, big->giv, 8); @@ -799,8 +801,6 @@ ble_ll_iso_big_event_sched_cb(struct ble_ll_sched_item *sch) ble_ll_tx_power_set(g_ble_ll_tx_power); - BLE_LL_ASSERT(!big->framed); - /* XXX calculate this in advance at the end of previous event? */ big->tx.subevents_rem = big->num_bis * big->nse; STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { @@ -982,13 +982,11 @@ 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); - BLE_LL_ASSERT(!big->framed); - 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->bn, pte, bp->framing); } big_pool_free--; @@ -1024,7 +1022,8 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, big->irc = bp->irc; big->nse = bp->nse; big->interleaved = bp->interleaved; - big->framed = bp->framed; + big->framed = bp->framing != BLE_HCI_ISO_FRAMING_UNFRAMED; + big->framing_mode = bp->framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED; big->encrypted = bp->encrypted; big->sdu_interval = bp->sdu_interval; big->iso_interval = bp->iso_interval; @@ -1240,7 +1239,7 @@ ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t len) !IN_RANGE(le16toh(cmd->max_sdu), 0x0001, 0x0fff) || !IN_RANGE(le16toh(cmd->max_transport_latency), 0x0005, 0x0fa0) || !IN_RANGE(cmd->rtn, 0x00, 0x1e) || - (cmd->packing > 1) || (cmd->framing > 1) || (cmd->encryption) > 1) { + (cmd->packing > 1) || (cmd->framing > 2) || (cmd->encryption) > 1) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1255,7 +1254,7 @@ ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t len) bp.phy = BLE_PHY_CODED; } bp.interleaved = cmd->packing; - bp.framed = cmd->framing; + bp.framing = cmd->framing; bp.encrypted = cmd->encryption; memcpy(bp.broadcast_code, cmd->broadcast_code, 16); @@ -1333,7 +1332,7 @@ ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, uint8_t len) bp.phy = BLE_PHY_CODED; } bp.interleaved = cmd->packing; - bp.framed = cmd->framing; + bp.framing = cmd->framing; bp.encrypted = cmd->encryption; memcpy(bp.broadcast_code, cmd->broadcast_code, 16); @@ -1343,7 +1342,7 @@ ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, uint8_t len) iso_interval_us = bp.iso_interval * 1250; - if (!bp.framed) { + if (bp.framing == BLE_HCI_ISO_FRAMING_UNFRAMED) { /* sdu_interval shall be an integer multiple of iso_interval */ if (iso_interval_us % bp.sdu_interval) { return BLE_ERR_INV_HCI_CMD_PARMS; diff --git a/nimble/controller/src/ble_ll_isoal.c b/nimble/controller/src/ble_ll_isoal.c index a15bf95857..d11df61ab8 100644 --- a/nimble/controller/src/ble_ll_isoal.c +++ b/nimble/controller/src/ble_ll_isoal.c @@ -32,21 +32,25 @@ void ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, uint32_t iso_interval_us, uint32_t sdu_interval_us, - uint8_t bn, uint8_t pte) + uint8_t bn, uint8_t pte, bool framed, bool framing_mode) { memset(mux, 0, sizeof(*mux)); BLE_LL_ASSERT(iso_interval_us >= sdu_interval_us); - mux->max_pdu = max_pdu; /* Core 5.3, Vol 6, Part G, 2.1 */ - mux->sdu_per_interval = iso_interval_us / sdu_interval_us; - mux->pdu_per_sdu = bn / mux->sdu_per_interval; + uint8_t sdu_per_interval = iso_interval_us / sdu_interval_us; + mux->pdu_per_sdu = bn / sdu_per_interval; - mux->sdu_per_event = (1 + pte) * mux->sdu_per_interval; + mux->max_pdu = max_pdu; + mux->pdu_per_interval = bn; + mux->pdu_per_event = (1 + pte) * mux->pdu_per_interval; STAILQ_INIT(&mux->sdu_q); mux->sdu_q_len = 0; + + mux->framed = framed; + mux->framing_mode = framing_mode; } void @@ -74,17 +78,13 @@ ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux) } void -ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, struct os_mbuf *om, uint32_t timestamp) +ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, struct os_mbuf *om) { struct os_mbuf_pkthdr *pkthdr; - struct ble_mbuf_hdr *blehdr; os_sr_t sr; BLE_LL_ASSERT(mux); - blehdr = BLE_MBUF_HDR_PTR(om); - blehdr->txiso.packet_seq_num = ++mux->sdu_counter; - OS_ENTER_CRITICAL(sr); pkthdr = OS_MBUF_PKTHDR(om); STAILQ_INSERT_TAIL(&mux->sdu_q, pkthdr, omp_next); @@ -97,26 +97,77 @@ ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, struct os_mbuf *om, u OS_EXIT_CRITICAL(sr); } -int +static uint8_t +ble_ll_isoal_framed_pdu_num(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + uint16_t rem_len; + uint8_t data_len; + uint8_t hdr_len; + uint8_t pdu_offset = 0; + uint8_t pdu_idx = 0; + + if (STAILQ_EMPTY(&mux->sdu_q)) { + return 0; + } + + hdr_len = mux->sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + rem_len = OS_MBUF_PKTLEN(om); + + while (rem_len > 0) { + pdu_offset += hdr_len; + if (pdu_offset >= mux->max_pdu) { + /* Advance to next PDU as there is no room left for another SDU Segment */ + pdu_offset = hdr_len; + pdu_idx++; + } + + data_len = min(rem_len, mux->max_pdu - pdu_offset); + pdu_offset += data_len; + + rem_len -= data_len; + hdr_len = rem_len > 0 ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + } + + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + } + + return pdu_idx + 1; +} + +void ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, uint32_t timestamp) { + uint8_t num_pdu = 0; + + if (mux->framed) { + num_pdu = ble_ll_isoal_framed_pdu_num(mux); + } else { + num_pdu = mux->sdu_q_len * mux->pdu_per_sdu; + } + #if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL) /* If prefill is enabled, we always expect to have required number of SDUs * in queue, otherwise we disable mux until enough SDUs are queued again. */ - mux->sdu_in_event = mux->sdu_per_event; - if (mux->sdu_in_event > mux->sdu_q_len) { + mux->pdu_in_event = mux->pdu_per_event; + if (mux->pdu_in_event > num_pdu) { mux->active = 0; } if (!mux->active) { - mux->sdu_in_event = 0; + mux->pdu_in_event = 0; } #else - mux->sdu_in_event = min(mux->sdu_q_len, mux->sdu_per_event); + mux->pdu_in_event = min(num_pdu, mux->pdu_per_event); #endif mux->event_tx_timestamp = timestamp; - - return mux->sdu_in_event; } int @@ -126,11 +177,14 @@ ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux) struct ble_mbuf_hdr *blehdr; struct os_mbuf *om; struct os_mbuf *om_next; - uint8_t num_sdu; + uint8_t num_pdu; + uint8_t pdu_offset = 0; + uint8_t data_len = 0; + uint8_t hdr_len = 0; int pkt_freed = 0; os_sr_t sr; - num_sdu = min(mux->sdu_in_event, mux->sdu_per_interval); + num_pdu = min(mux->pdu_in_event, mux->pdu_per_interval); pkthdr = STAILQ_FIRST(&mux->sdu_q); if (pkthdr) { @@ -154,32 +208,66 @@ ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux) } #endif - while (pkthdr && num_sdu--) { - OS_ENTER_CRITICAL(sr); - STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); - BLE_LL_ASSERT(mux->sdu_q_len > 0); - mux->sdu_q_len--; - OS_EXIT_CRITICAL(sr); + if (mux->framed) { + pdu_offset = mux->sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + } + while (pkthdr && num_pdu) { om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); while (om) { - om_next = SLIST_NEXT(om, om_next); - os_mbuf_free(om); - pkt_freed++; - om = om_next; + data_len = min(om->om_len, mux->max_pdu - pdu_offset); + + os_mbuf_adj(om, data_len); + if (om->om_len == 0) { + om_next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + pkt_freed++; + om = om_next; + } + + pdu_offset += data_len; + if (pdu_offset >= mux->max_pdu) { + /* Advance to next PDU */ + pdu_offset = 0; + num_pdu--; + break; + } } - pkthdr = STAILQ_FIRST(&mux->sdu_q); + mux->sc = om != NULL; + + if (mux->framed) { + /* Get next segment header length */ + hdr_len = mux->sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + } + + if (mux->max_pdu <= pdu_offset + hdr_len) { + num_pdu--; + } + + pdu_offset += hdr_len; + + if (!mux->sc) { + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); + BLE_LL_ASSERT(mux->sdu_q_len > 0); + mux->sdu_q_len--; + OS_EXIT_CRITICAL(sr); + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + } } - mux->sdu_in_event = 0; + mux->pdu_in_event = 0; return pkt_freed; } -int -ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, - uint8_t *llid, void *dptr) +static int +ble_ll_isoal_mux_pdu_unframed_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr) { struct os_mbuf_pkthdr *pkthdr; struct os_mbuf *om; @@ -189,14 +277,14 @@ ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, uint16_t rem_len; uint8_t pdu_len; - sdu_idx = idx / mux->pdu_per_sdu; - pdu_idx = idx - sdu_idx * mux->pdu_per_sdu; - - if (sdu_idx >= mux->sdu_in_event) { + if (idx >= mux->pdu_in_event) { *llid = 0; return 0; } + sdu_idx = idx / mux->pdu_per_sdu; + pdu_idx = idx - sdu_idx * mux->pdu_per_sdu; + pkthdr = STAILQ_FIRST(&mux->sdu_q); while (pkthdr && sdu_idx--) { pkthdr = STAILQ_NEXT(pkthdr, omp_next); @@ -224,6 +312,112 @@ ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, return pdu_len; } +static int +ble_ll_isoal_mux_pdu_framed_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, uint8_t *dptr) +{ + struct ble_mbuf_hdr *blehdr; + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + uint32_t time_offset; + uint16_t seghdr; + uint16_t rem_len = 0; + uint16_t sdu_offset; + uint8_t hdr_len; + uint8_t frag_len; + uint8_t pdu_offset = 0; + bool sc = mux->sc; + bool cmplt; + + if (idx < mux->pdu_in_event) { + hdr_len = sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + + /* Skip the idx PDUs */ + sdu_offset = 0; + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && idx) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + rem_len = OS_MBUF_PKTLEN(om) - sdu_offset; + frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset); + + pdu_offset += hdr_len + frag_len; + sdu_offset += frag_len; + + /* Check if there's room for next segment */ + hdr_len = rem_len > 0 ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + if (mux->max_pdu <= pdu_offset + hdr_len) { + /* Advance to next PDU */ + pdu_offset = 0; + idx--; + } + + if (rem_len == 0) { + sdu_offset = 0; + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + sc = false; + } else { + sc = true; + } + } + + BLE_LL_ASSERT(pkthdr); + BLE_LL_ASSERT(pdu_offset == 0); + + while (pkthdr && mux->max_pdu > pdu_offset + hdr_len) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + rem_len = OS_MBUF_PKTLEN(om) - sdu_offset; + frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset); + + cmplt = rem_len == frag_len; + + seghdr = BLE_LL_ISOAL_SEGHDR(sc, cmplt, hdr_len - 2 + frag_len); + put_le16(dptr + pdu_offset, seghdr); + pdu_offset += 2; + + if (!sc) { + blehdr = BLE_MBUF_HDR_PTR(om); + + time_offset = mux->event_tx_timestamp - + blehdr->txiso.cpu_timestamp; + put_le24(dptr + pdu_offset, time_offset); + pdu_offset += 3; + } + os_mbuf_copydata(om, sdu_offset, frag_len, dptr + pdu_offset); + pdu_offset += frag_len; + + if (cmplt) { + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + sdu_offset = 0; + } else { + sdu_offset += frag_len; + } + + sc = !cmplt; + + /* Get next segment header length */ + hdr_len = sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + } + } + + *llid = 0b10; + + return pdu_offset; +} + +int +ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr) +{ + if (mux->framed) { + return ble_ll_isoal_mux_pdu_framed_get(mux, idx, llid, dptr); + } else { + return ble_ll_isoal_mux_pdu_unframed_get(mux, idx, llid, dptr); + } +} + void ble_ll_isoal_init(void) { diff --git a/nimble/controller/test/src/ble_ll_isoal.c b/nimble/controller/test/src/ble_ll_isoal.c index 7c01dfc8cb..f428114ebe 100644 --- a/nimble/controller/test/src/ble_ll_isoal.c +++ b/nimble/controller/test/src/ble_ll_isoal.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #define MBUF_TEST_POOL_BUF_SIZE (320) @@ -59,10 +60,13 @@ TEST_CASE_SELF(ble_ll_isoal_test_mux_init_free) struct ble_ll_isoal_mux mux; const uint32_t iso_interval_us = 10000; const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; const uint8_t bn = 1; const uint8_t max_pdu = 250; - ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, 0); + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); TEST_ASSERT(mux.pdu_per_sdu == (bn * sdu_interval_us) / iso_interval_us); @@ -75,18 +79,21 @@ TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_1_sdu_3_pdu) struct os_mbuf *om; const uint32_t iso_interval_us = 10000; const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; const uint8_t bn = 3; const uint8_t max_pdu = 40; const uint8_t sdu_len = 3 * max_pdu; static uint8_t data[40]; - int num_sdu; + int num_completed_pkt; int pdu_len; uint8_t llid = 0x00; int rc; _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); - ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, 0); + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); om = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); TEST_ASSERT_FATAL(om != NULL); @@ -94,10 +101,9 @@ TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_1_sdu_3_pdu) rc = os_mbuf_append(om, os_mbuf_test_data, sdu_len); TEST_ASSERT_FATAL(rc == 0); - ble_ll_isoal_mux_sdu_enqueue(&mux, om, 90950); + ble_ll_isoal_mux_sdu_enqueue(&mux, om); - num_sdu = ble_ll_isoal_mux_event_start(&mux, 90990); - TEST_ASSERT(num_sdu == 1); + ble_ll_isoal_mux_event_start(&mux, 90990); /* 1st PDU */ pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); @@ -117,8 +123,89 @@ TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_1_sdu_3_pdu) /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); - num_sdu = ble_ll_isoal_mux_event_done(&mux); - TEST_ASSERT(num_sdu == 1); + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_1_sdu_2_pdu) +{ + struct ble_ll_isoal_mux mux; + struct os_mbuf *sdu_1, *sdu_2; + const uint32_t iso_interval_us = 20000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; + const uint8_t bn = 6; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 3 * max_pdu; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + int rc; + + _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + /* SDU #2 */ + sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_2 != NULL); + rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2); + + ble_ll_isoal_mux_event_start(&mux, 90990); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #3 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + + /* PDU #4 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #5 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #6 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); ble_ll_isoal_mux_free(&mux); } @@ -129,35 +216,37 @@ TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_2_sdu_6_pdu) struct os_mbuf *sdu_1, *sdu_2; const uint32_t iso_interval_us = 20000; const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; const uint8_t bn = 6; const uint8_t max_pdu = 40; const uint8_t sdu_len = 3 * max_pdu; static uint8_t data[40]; - int num_sdu; + int num_completed_pkt; int pdu_len; uint8_t llid = 0x00; int rc; _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); - ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, 0); + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); /* SDU #1 */ sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); TEST_ASSERT_FATAL(sdu_1 != NULL); rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); TEST_ASSERT_FATAL(rc == 0); - ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1, 90950); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); /* SDU #2 */ sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); TEST_ASSERT_FATAL(sdu_2 != NULL); rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len); TEST_ASSERT_FATAL(rc == 0); - ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2, 90950); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2); - num_sdu = ble_ll_isoal_mux_event_start(&mux, 90990); - TEST_ASSERT(num_sdu == 2); + ble_ll_isoal_mux_event_start(&mux, 90990); /* PDU #1 */ pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); @@ -195,8 +284,713 @@ TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_2_sdu_6_pdu) /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); - num_sdu = ble_ll_isoal_mux_event_done(&mux); - TEST_ASSERT(num_sdu == 2); + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_segmentable_0_sdu_2_pdu) +{ + struct ble_ll_isoal_mux mux; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t bn = 2; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 40; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + + _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + ble_ll_isoal_mux_event_start(&mux, 90990); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_segmentable_0_sdu_2_pdu_1_sdu_not_in_event) +{ + struct ble_ll_isoal_mux mux; + struct os_mbuf *sdu_1; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t bn = 2; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 40; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + int rc; + + _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + ble_ll_isoal_mux_event_start(&mux, 90990); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_segmentable_1_sdu_2_pdu) +{ + struct ble_ll_isoal_mux mux; + struct os_mbuf *sdu_1; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t bn = 2; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 40; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + int rc; + + _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + ble_ll_isoal_mux_event_start(&mux, 90990); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Framed Data PDU. */ + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 7, "PDU length is incorrect %d", pdu_len); + /* Framed Data PDU. */ + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_segmentable_2_sdu_2_pdu) +{ + struct ble_ll_isoal_mux mux; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *sdu_1, *sdu_2; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t bn = 2; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 40; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint32_t timeoffset; + uint16_t seghdr; + uint8_t llid = 0x00; + int rc; + + _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu_1); + blehdr->txiso.packet_seq_num = 1; + blehdr->txiso.cpu_timestamp = 20000; + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + /* SDU #1 */ + sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_2 != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu_2); + blehdr->txiso.packet_seq_num = 2; + blehdr->txiso.cpu_timestamp = 30000; + rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2); + + ble_ll_isoal_mux_event_start(&mux, 30500); + + /** + * Event #1; PDU #1 + * +---------------------+------------------------+-----------------+ + * | Segmentation Header | TimeOffset (ISO SDU 1) | ISO SDU 1 Seg 1 | + * | 2 bytes | 3 bytes | 35 bytes | + * +---------------------+------------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 1 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 0, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 38, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[2]); + TEST_ASSERT(timeoffset == 10500, "Time offset is incorrect %d", timeoffset); + + /** + * Event #1; PDU #2 + * +---------------------+-----------------+---------------------+------------------------+-----------------+ + * | Segmentation Header | ISO SDU 1 Seg 2 | Segmentation Header | TimeOffset (ISO SDU 2) | ISO SDU 2 Seg 1 | + * | 2 bytes | 5 bytes | 2 bytes | 3 bytes | 28 bytes | + * +---------------------+-----------------+---------------------+------------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 2 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 5, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + + /* ISO SDU 2 Seg 1 */ + seghdr = get_le16(&data[7]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 0, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 31, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[9]); + TEST_ASSERT(timeoffset == 500, "Time offset is incorrect %d", timeoffset); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, 30500 + iso_interval_us); + + /** + * Event #2; PDU #1 + * +---------------------+-----------------+ + * | Segmentation Header | ISO SDU 2 Seg 2 | + * | 2 bytes | 12 bytes | + * +---------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 14, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* ISO SDU 2 Seg 2 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 12, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + + /** + * Event #2; PDU #2 Empty + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_segmentable_1_sdu_2_pdu_sdu_has_zero_length) +{ + struct ble_ll_isoal_mux mux; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *sdu_1; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t bn = 2; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 40; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint32_t timeoffset; + uint16_t seghdr; + uint8_t llid = 0x00; + int rc; + + _Static_assert(sdu_len <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu_1); + blehdr->txiso.packet_seq_num = 1; + blehdr->txiso.cpu_timestamp = 20000; + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, 0); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + ble_ll_isoal_mux_event_start(&mux, 30500); + + /** + * Event #1; PDU #1 + * +---------------------+------------------------+ + * | Segmentation Header | TimeOffset (ISO SDU 1) | + * | 2 bytes | 3 bytes | + * +---------------------+------------------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 5, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 1 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 3, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[2]); + TEST_ASSERT(timeoffset == 10500, "Time offset is incorrect %d", timeoffset); + + /** + * Event #1; PDU #2 Empty + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_ial_bis_fra_brd_bv_06_c) +{ + struct ble_ll_isoal_mux mux; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *sdu_1; + const uint8_t NSE = 4; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t Max_PDU = 40; + const uint8_t LLID = 0b10; + const uint8_t BN = 2; + const uint32_t SDU_Interval = 5000; + const uint32_t ISO_Interval = 10000; + const uint8_t Max_SDU = 32; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint32_t timeoffset; + uint16_t seghdr; + uint8_t llid = 0xff; + int rc; + + _Static_assert(Max_SDU <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, Max_PDU, ISO_Interval, SDU_Interval, BN, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu_1); + blehdr->txiso.packet_seq_num = 0; + blehdr->txiso.cpu_timestamp = 20000; + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, 27); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + ble_ll_isoal_mux_event_start(&mux, 30500); + + for (uint8_t i = 0; i < NSE; i++) { + /** + * Event #1; PDU #1 + * +---------------------+------------------------+-----------------+ + * | Segmentation Header | TimeOffset (ISO SDU 1) | ISO SDU 1 Seg 1 | + * | 2 bytes | 3 bytes | 27 bytes | + * +---------------------+------------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 32, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 1 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 30, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[2]); + TEST_ASSERT(timeoffset == 10500, "Time offset is incorrect %d", timeoffset); + } + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_ial_bis_fra_brd_bv_08_c) +{ + struct ble_ll_isoal_mux mux; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *sdu_1; + const uint8_t NSE = 2; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t Max_PDU = 40; + const uint8_t LLID = 0b10; + const uint8_t BN = 1; + const uint32_t SDU_Interval = 10000; + const uint32_t ISO_Interval = 10000; + const uint8_t Max_SDU = 32; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint32_t timeoffset; + uint16_t seghdr; + uint8_t llid = 0xff; + int rc; + + _Static_assert(Max_SDU <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, Max_PDU, ISO_Interval, SDU_Interval, BN, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu_1); + blehdr->txiso.packet_seq_num = 0; + blehdr->txiso.cpu_timestamp = 20000; + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, 27); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + ble_ll_isoal_mux_event_start(&mux, 30500); + + for (uint8_t i = 0; i < NSE; i++) { + /** + * Event #1; PDU #1 + * +---------------------+------------------------+-----------------+ + * | Segmentation Header | TimeOffset (ISO SDU 1) | ISO SDU 1 Seg 1 | + * | 2 bytes | 3 bytes | 27 bytes | + * +---------------------+------------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 32, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 1 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 30, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[2]); + TEST_ASSERT(timeoffset == 10500, "Time offset is incorrect %d", timeoffset); + + /** + * Event #1; PDU #2 Empty + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + } + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_ial_bis_fra_brd_bv_13_c) +{ + struct ble_ll_isoal_mux mux; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *sdu; + const uint8_t NSE = 10; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t Max_PDU = 251; + const uint8_t LLID = 0b10; + const uint8_t BN = 5; + const uint32_t SDU_Interval = 15000; + const uint32_t ISO_Interval = 30000; + const uint16_t Max_SDU = 503; + static uint8_t data[251]; + int num_completed_pkt; + int pdu_len; + uint32_t timeoffset; + uint16_t seghdr; + uint8_t llid = 0xff; + int rc; + + TEST_ASSERT(Max_SDU <= sizeof(os_mbuf_test_data), "incorrect sdu length"); + + ble_ll_isoal_mux_init(&mux, Max_PDU, ISO_Interval, SDU_Interval, BN, + 0, Framed, Framing_Mode); + + /* Round 1 */ + sdu = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu); + blehdr->txiso.packet_seq_num = 0; + blehdr->txiso.cpu_timestamp = 10000; + rc = os_mbuf_append(sdu, os_mbuf_test_data, 495); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu); + + ble_ll_isoal_mux_event_start(&mux, 10500); + + for (uint8_t i = 0; i < NSE / BN; i += BN) { + /** + * P0 + * +---------------------+------------------------+-----------------+ + * | Segmentation Header | TimeOffset (ISO SDU 1) | ISO SDU 1 Seg 1 | + * | 2 bytes | 3 bytes | 246 bytes | + * +---------------------+------------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 251, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 1 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 0, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 249, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[2]); + TEST_ASSERT(timeoffset == 500, "Time offset is incorrect %d", + timeoffset); + + /** + * P1 + * +---------------------+-----------------+ + * | Segmentation Header | ISO SDU 1 Seg 2 | + * | 2 bytes | 249 bytes | + * +---------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 251, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 2 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 249, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + + /** + * P2 + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /** + * P3 + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 3, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /** + * P4 + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 4, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + } + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + /* Round 2 */ + sdu = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu); + blehdr->txiso.packet_seq_num = 0; + blehdr->txiso.cpu_timestamp = 25000; + rc = os_mbuf_append(sdu, os_mbuf_test_data, 503); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu); + + ble_ll_isoal_mux_event_start(&mux, 40500); + + for (uint8_t i = 0; i < NSE / BN; i += BN) { + /** + * P0 + * +---------------------+------------------------+-----------------+ + * | Segmentation Header | TimeOffset (ISO SDU 1) | ISO SDU 1 Seg 1 | + * | 2 bytes | 3 bytes | 246 bytes | + * +---------------------+------------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 251, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 1 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 0, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 249, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + timeoffset = get_le24(&data[2]); + TEST_ASSERT(timeoffset == 15500, "Time offset is incorrect %d", + timeoffset); + + /** + * P1 + * +---------------------+-----------------+ + * | Segmentation Header | ISO SDU 1 Seg 2 | + * | 2 bytes | 249 bytes | + * +---------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 251, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 2 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 0, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 249, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + + /** + * P2 + * +---------------------+-----------------+ + * | Segmentation Header | ISO SDU 1 Seg 3 | + * | 2 bytes | 8 bytes | + * +---------------------+-----------------+ + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == 10, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* ISO SDU 1 Seg 3 */ + seghdr = get_le16(&data[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seghdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr) == 1, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seghdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seghdr) == 8, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seghdr)); + + /** + * P3 + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 3, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /** + * P4 + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 4, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + } + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); ble_ll_isoal_mux_free(&mux); } @@ -210,6 +1004,15 @@ TEST_SUITE(ble_ll_isoal_test_suite) ble_ll_isoal_test_mux_init_free(); ble_ll_isoal_mux_pdu_get_unframed_1_sdu_3_pdu(); ble_ll_isoal_mux_pdu_get_unframed_2_sdu_6_pdu(); + ble_ll_isoal_mux_pdu_get_segmentable_0_sdu_2_pdu(); + ble_ll_isoal_mux_pdu_get_segmentable_0_sdu_2_pdu_1_sdu_not_in_event(); + ble_ll_isoal_mux_pdu_get_segmentable_1_sdu_2_pdu(); + ble_ll_isoal_mux_pdu_get_segmentable_2_sdu_2_pdu(); + ble_ll_isoal_mux_pdu_get_segmentable_1_sdu_2_pdu_sdu_has_zero_length(); + + ble_ll_ial_bis_fra_brd_bv_06_c(); + ble_ll_ial_bis_fra_brd_bv_08_c(); + ble_ll_ial_bis_fra_brd_bv_13_c(); ble_ll_isoal_reset(); } diff --git a/nimble/include/nimble/ble.h b/nimble/include/nimble/ble.h index c42d5c5ba4..0723e2d4e2 100644 --- a/nimble/include/nimble/ble.h +++ b/nimble/include/nimble/ble.h @@ -128,6 +128,8 @@ struct ble_mbuf_hdr_txinfo struct ble_mbuf_hdr_txiso { uint16_t packet_seq_num; + uint32_t cpu_timestamp; + uint32_t hci_timestamp; }; /** diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 252b033973..d6abc3966c 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -2449,6 +2449,10 @@ struct hci_data_hdr #define BLE_HCI_ISO_DATA_PATH_ID_HCI 0x00 +#define BLE_HCI_ISO_FRAMING_UNFRAMED 0x00 +#define BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE 0x01 +#define BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED 0x02 + struct ble_hci_iso { uint16_t handle; uint16_t length;