diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index 8fcae3461e3899..fba78369c9c115 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -34,10 +34,22 @@ #include -LOG_MODULE_REGISTER(bt_ctlr_isoal, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(bt_ctlr_isoal, LOG_LEVEL_INF); + +#define ISOAL_LOG_DBG(...) LOG_DBG(__VA_ARGS__) + +#if defined(ISOAL_DEBUG_VERBOSE) +#define ISOAL_LOG_DBGV(...) LOG_DBG(__VA_ARGS__) +#else +#define ISOAL_LOG_DBGV(...) (void) 0 +#endif /* ISOAL_DEBUG_VERBOSE */ #include "hal/debug.h" +#define FSM_TO_STR(s) (s == ISOAL_START ? "START" : \ + (s == ISOAL_CONTINUE ? "CONTINUE" : \ + (s == ISOAL_ERR_SPOOL ? "ERR SPOOL" : "???"))) + #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) /* Given the minimum payload, this defines the minimum number of bytes that * should be remaining in a TX PDU such that it would make inserting a new @@ -123,7 +135,61 @@ uint32_t isoal_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us) return result; } +/** + * @brief Check if a time difference calculation is valid and return the difference. + * @param time_before Subtrahend + * @param time_after Minuend + * @param result Difference if valid + * @return Validity - valid if time_after leads time_before with + * consideration for wrapping such that the + * difference can be calculated. + */ +static bool isoal_get_time_diff(uint32_t time_before, uint32_t time_after, uint32_t *result) +{ + bool valid = false; + + LL_ASSERT(time_before <= ISOAL_TIME_WRAPPING_POINT_US); + LL_ASSERT(time_after <= ISOAL_TIME_WRAPPING_POINT_US); + + if (time_before > time_after) { + if (time_before >= ISOAL_TIME_MID_POINT_US && + time_after <= ISOAL_TIME_MID_POINT_US) { + if ((time_before - time_after) <= ISOAL_TIME_SPAN_HALF_US) { + /* Time_before is after time_after and the result is invalid. */ + } else { + /* time_after has wrapped */ + *result = time_after + ISOAL_TIME_SPAN_FULL_US - time_before; + valid = true; + } + } + + /* Time_before is after time_after and the result is invalid. */ + } else { + /* Time_before <= time_after */ + *result = time_after - time_before; + if (*result <= ISOAL_TIME_SPAN_HALF_US) { + /* result is valid if it is within half the maximum + * time span. + */ + valid = true; + } else { + /* time_before has wrapped and the calculation is not + * valid as time_before is ahead of time_after. + */ + } + } + + return valid; +} + #if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) + +#define SET_RX_SDU_TIMESTAMP(_sink, _timestamp, _value) \ + _timestamp = _value; \ + ISOAL_LOG_DBGV("[%p] %s updated (%ld)", _sink, #_timestamp, _value); + +static void isoal_rx_framed_update_sdu_release(struct isoal_sink *sink); + /** * @brief Find free sink from statically-sized pool and allocate it * @details Implemented as linear search since pool is very small @@ -210,6 +276,7 @@ isoal_status_t isoal_sink_create( session->handle = handle; session->framed = framed; session->sdu_interval = sdu_interval; + session->iso_interval = iso_interval; session->burst_number = burst_number; /* Todo: Next section computing various constants, should potentially be a @@ -249,25 +316,27 @@ isoal_status_t isoal_sink_create( * BIG_Sync_Delay + SDU_interval + ISO_Interval - Time_Offset. */ if (role == BT_CONN_ROLE_PERIPHERAL) { - isoal_global.sink_state[*hdl].session.latency_unframed = - stream_sync_delay + ((flush_timeout - 1UL) * iso_interval_us); - - isoal_global.sink_state[*hdl].session.latency_framed = - stream_sync_delay + sdu_interval + (flush_timeout * iso_interval_us); + if (framed) { + session->sdu_sync_const = stream_sync_delay + sdu_interval + + (flush_timeout * iso_interval_us); + } else { + session->sdu_sync_const = stream_sync_delay + + ((flush_timeout - 1UL) * iso_interval_us); + } } else if (role == BT_CONN_ROLE_CENTRAL) { - isoal_global.sink_state[*hdl].session.latency_unframed = - stream_sync_delay - group_sync_delay - - (((iso_interval_us / sdu_interval) - 1UL) * iso_interval_us); - - isoal_global.sink_state[*hdl].session.latency_framed = - stream_sync_delay - group_sync_delay; + if (framed) { + session->sdu_sync_const = stream_sync_delay - group_sync_delay; + } else { + session->sdu_sync_const = stream_sync_delay - group_sync_delay - + (((iso_interval_us / sdu_interval) - 1UL) * + iso_interval_us); + } } else if (role == BT_ROLE_BROADCAST) { - isoal_global.sink_state[*hdl].session.latency_unframed = - group_sync_delay; - - isoal_global.sink_state[*hdl].session.latency_framed = - group_sync_delay + sdu_interval + iso_interval_us; - + if (framed) { + session->sdu_sync_const = group_sync_delay + sdu_interval + iso_interval_us; + } else { + session->sdu_sync_const = group_sync_delay; + } } else { LL_ASSERT(0); } @@ -283,20 +352,6 @@ isoal_status_t isoal_sink_create( return err; } -/** - * @brief Get reference to configuration struct - * - * @param hdl[in] Handle to new sink - * @return Reference to parameter struct, to be configured by caller - */ -struct isoal_sink_config *isoal_get_sink_param_ref(isoal_sink_handle_t hdl) -{ - LL_ASSERT(hdl < CONFIG_BT_CTLR_ISOAL_SINKS); - LL_ASSERT(isoal_global.sink_allocated[hdl] == ISOAL_ALLOC_STATE_TAKEN); - - return &isoal_global.sink_state[hdl].session.param; -} - /** * @brief Atomically enable latch-in of packets and SDU production * @param hdl[in] Handle of existing instance @@ -481,6 +536,9 @@ static isoal_status_t isoal_rx_buffered_emit_sdu(struct isoal_sink *sink, bool e sdu_status.collated_status = sdu_frag.sdu.status; } + ISOAL_LOG_DBG("[%p] SDU %u @TS=%u err=%X len=%u released\n", + sink, sdu_frag.sdu.sn, sdu_frag.sdu.timestamp, + sdu_status.collated_status, sdu_status.total_sdu_size); err |= session->sdu_emit(sink, &sdu_frag, &sdu_status); #if defined(ISOAL_BUFFER_RX_SDUS_ENABLE) @@ -498,12 +556,14 @@ static isoal_status_t isoal_rx_buffered_emit_sdu(struct isoal_sink *sink, bool e static isoal_status_t isoal_rx_try_emit_sdu(struct isoal_sink *sink, bool end_of_sdu) { + struct isoal_sink_session *session; struct isoal_sdu_production *sp; struct isoal_sdu_produced *sdu; isoal_status_t err; err = ISOAL_STATUS_OK; sp = &sink->sdu_production; + session = &sink->session; sdu = &sp->sdu; /* Emit a SDU */ @@ -541,6 +601,12 @@ static isoal_status_t isoal_rx_try_emit_sdu(struct isoal_sink *sink, bool end_of err = isoal_rx_buffered_emit_sdu(sink, end_of_sdu); sp->sdu_allocated = false; + if (end_of_sdu) { + isoal_rx_framed_update_sdu_release(sink); + sp->sdu_status = ISOAL_SDU_STATUS_VALID; + session->sn++; + } + /* update next state */ sink->sdu_production.sdu_state = next_state; } @@ -714,7 +780,6 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, sp->sdu_state = BT_ISO_START; sp->pdu_cnt = 1; sp->only_padding = pdu_padding; - session->sn++; seq_err = false; /* The incoming time stamp for each PDU is expected to be the @@ -733,7 +798,7 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, * event that the PDU is associated with. */ anchorpoint = meta->timestamp; - latency = session->latency_unframed; + latency = session->sdu_sync_const; sdu = &sp->sdu; sdu->timestamp = isoal_get_wrapped_time_us(anchorpoint, latency); @@ -872,6 +937,8 @@ static isoal_status_t isoal_rx_unframed_consume(struct isoal_sink *sink, sp->prev_pdu_is_end = !pdu_err && llid == PDU_BIS_LLID_COMPLETE_END; sp->prev_pdu_is_padding = !pdu_err && pdu_padding; + sp->initialized = true; + return err; } @@ -898,6 +965,105 @@ static isoal_sdu_status_t isoal_check_seg_header(struct pdu_iso_sdu_sh *seg_hdr, return ISOAL_SDU_STATUS_LOST_DATA; } +/* Check available time reference and release any missing / lost SDUs + * + * Time tracking and release of lost SDUs for framed: + * + * Time tracking is implemented based on using the incoming time-stamps of the + * PDUs, which should correspond to the BIG / CIG reference anchorpoint of the + * current event, to track how time has advanced. The reference used is the + * reconstructed SDU synchronisation reference point. For the CIS peripheral and + * BIS receiver, this reference is ahead of the time-stamp (anchorpoint), + * however for the CIS central this reference will be before (i.e. in the past). + * Where the time offset is not available, an ISO interval is used in place of + * the time offset to create an approximate reference. + * + * This information is in-turn used to decided if SDUs are missing or lost and + * when they should be released. This approach is inherrently bursty with the + * most probable worst case burst being 2 x (ISO interval / SDU Interval) SDUs, + * which would occur when only padding is seen in one event followed by all the + * SDUs from the next event in one PDU. + */ +static isoal_status_t isoal_rx_framed_release_lost_sdus(struct isoal_sink *sink, + const struct isoal_pdu_rx *pdu_meta, + bool timestamp_valid, + uint32_t next_sdu_timestamp) +{ + struct isoal_sink_session *session; + struct isoal_sdu_production *sp; + struct isoal_sdu_produced *sdu; + isoal_status_t err; + uint32_t time_elapsed; + + sp = &sink->sdu_production; + session = &sink->session; + sdu = &sp->sdu; + + err = ISOAL_STATUS_OK; + + if (isoal_get_time_diff(sdu->timestamp, next_sdu_timestamp, &time_elapsed)) { + /* Time elapsed >= 0 */ + uint8_t lost_sdus; + + if (timestamp_valid) { + /* If there is a valid new time reference, then + * calculate the gap between the next SDUs expected + * time stamp and the actual reference, rounding at the + * mid point. + * 0 Next SDU is the SDU that provided the new time + * reference, no lost SDUs + * >0 Number of lost SDUs + */ + lost_sdus = (time_elapsed + (session->sdu_interval / 2)) / + session->sdu_interval; + ISOAL_LOG_DBGV("[%p] Next SDU timestamp (%lu) accurate", + sink, next_sdu_timestamp); + } else { + /* If there is no valid new time reference, then lost + * SDUs should only be released for every full + * SDU interval. This should include consideration that + * the next expected SDU's time stamp is the base for + * time_elapsed (i.e. +1). + */ + ISOAL_LOG_DBGV("[%p] Next SDU timestamp (%lu) approximate", + sink, next_sdu_timestamp); + lost_sdus = time_elapsed ? (time_elapsed / session->sdu_interval) + 1 : 0; + } + + ISOAL_LOG_DBGV("[%p] Releasing %u lost SDUs", sink, lost_sdus); + + while (lost_sdus > 0 && !err) { + sp->sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; + + err = isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); + lost_sdus--; + } + } + + return err; +} + +/* Update time tracking after release of an SDU. + * At present only required for framed PDUs. + */ +static void isoal_rx_framed_update_sdu_release(struct isoal_sink *sink) +{ + struct isoal_sink_session *session; + struct isoal_sdu_production *sp; + struct isoal_sdu_produced *sdu; + uint32_t timestamp; + + sp = &sink->sdu_production; + session = &sink->session; + sdu = &sp->sdu; + + if (session->framed) { + /* Update to the expected release time of the next SDU */ + timestamp = isoal_get_wrapped_time_us(sdu->timestamp, session->sdu_interval); + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + } +} + /** * @brief Consume a framed PDU: Copy contents into SDU(s) and emit to a sink * @details Destination sink may have an already partially built SDU @@ -915,6 +1081,7 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, struct isoal_sdu_produced *sdu; struct pdu_iso_sdu_sh *seg_hdr; struct node_rx_iso_meta *meta; + uint32_t iso_interval_us; uint32_t anchorpoint; uint8_t *end_of_pdu; uint32_t timeoffset; @@ -932,6 +1099,8 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, meta = pdu_meta->meta; sdu = &sp->sdu; + iso_interval_us = session->iso_interval * ISO_INT_UNIT_US; + err = ISOAL_STATUS_OK; next_state = ISOAL_START; pdu_err = (pdu_meta->meta->status != ISOAL_PDU_STATUS_VALID); @@ -954,6 +1123,21 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, seg_hdr = NULL; } + /* Calculate an approximate timestamp */ + timestamp = isoal_get_wrapped_time_us(meta->timestamp, + session->sdu_sync_const - iso_interval_us); + if (!sp->initialized) { + /* This should be the first PDU received in this session */ + /* Initialize a temporary timestamp for the next SDU */ + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + } + + if (pdu_padding && !pdu_err && !seq_err) { + /* Check and release missed SDUs on receiving padding PDUs */ + ISOAL_LOG_DBGV("[%p] Recevied padding", sink); + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, timestamp); + } + while (seg_hdr) { bool append = true; const uint8_t sc = seg_hdr->sc; @@ -962,29 +1146,38 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, if (sp->fsm == ISOAL_START) { sp->sdu_status = ISOAL_SDU_STATUS_VALID; sp->sdu_state = BT_ISO_START; - session->sn++; } + ISOAL_LOG_DBGV("[%p] State %s", sink, FSM_TO_STR(sp->fsm)); switch (sp->fsm) { case ISOAL_START: - timeoffset = seg_hdr->timeoffset; - anchorpoint = meta->timestamp; - latency = session->latency_framed; - timestamp = isoal_get_wrapped_time_us(anchorpoint, latency - timeoffset); - - if (!sc && !cmplt) { - /* The start of a new SDU, where not all SDU data is included in - * the current PDU, and additional PDUs are required to complete - * the SDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_CONTINUE; - } else if (!sc && cmplt) { - /* The start of a new SDU that contains the full SDU data in the - * current PDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_START; + if (!sc) { + /* Start segment, included time-offset */ + timeoffset = seg_hdr->timeoffset; + anchorpoint = meta->timestamp; + latency = session->sdu_sync_const; + timestamp = isoal_get_wrapped_time_us(anchorpoint, + latency - timeoffset); + ISOAL_LOG_DBGV("[%p] Segment Start @TS=%ld", sink, timestamp); + + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, true, + timestamp); + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + + if (cmplt) { + /* The start of a new SDU that contains the full SDU data in + * the current PDU. + */ + ISOAL_LOG_DBGV("[%p] Segment Single", sink); + next_state = ISOAL_START; + } else { + /* The start of a new SDU, where not all SDU data is + * included in the current PDU, and additional PDUs are + * required to complete the SDU. + */ + next_state = ISOAL_CONTINUE; + } + } else { /* Unsupported case */ err = ISOAL_STATUS_ERR_UNSPECIFIED; @@ -997,12 +1190,14 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, * to the previous data and additional PDUs are required to * complete the SDU. */ + ISOAL_LOG_DBGV("[%p] Segment Continue", sink); next_state = ISOAL_CONTINUE; } else if (sc && cmplt) { /* The continuation of a previous SDU. * Frame data is appended to previously received SDU data and * completes in the current PDU. */ + ISOAL_LOG_DBGV("[%p] Segment End", sink); next_state = ISOAL_START; } else { /* Unsupported case */ @@ -1012,45 +1207,48 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, case ISOAL_ERR_SPOOL: /* In error state, search for valid next start of SDU */ - timeoffset = seg_hdr->timeoffset; - anchorpoint = meta->timestamp; - latency = session->latency_framed; - timestamp = isoal_get_wrapped_time_us(anchorpoint, latency - timeoffset); - - if (!sc && !cmplt) { - /* The start of a new SDU, where not all SDU data is included in - * the current PDU, and additional PDUs are required to complete - * the SDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_CONTINUE; - } else if (!sc && cmplt) { - /* The start of a new SDU that contains the full SDU data in the - * current PDU. - */ - sdu->timestamp = timestamp; - next_state = ISOAL_START; + + if (!sc) { + /* Start segment, included time-offset */ + timeoffset = seg_hdr->timeoffset; + anchorpoint = meta->timestamp; + latency = session->sdu_sync_const; + timestamp = isoal_get_wrapped_time_us(anchorpoint, + latency - timeoffset); + ISOAL_LOG_DBGV("[%p] Segment Start @TS=%ld", sink, timestamp); + + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, true, + timestamp); + SET_RX_SDU_TIMESTAMP(sink, sdu->timestamp, timestamp); + + if (cmplt) { + /* The start of a new SDU that contains the full SDU data + * in the current PDU. + */ + ISOAL_LOG_DBGV("[%p] Segment Single", sink); + next_state = ISOAL_START; + } else { + /* The start of a new SDU, where not all SDU data is + * included in the current PDU, and additional PDUs are + * required to complete the SDU. + */ + next_state = ISOAL_CONTINUE; + } + } else { /* Start not found yet, stay in Error state */ + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, + timestamp); append = false; next_state = ISOAL_ERR_SPOOL; } - /* TODO: Confirm if the sequence number must be updated even for an SDU - * with errors. - * BT Core V5.3 : Vol 6 Low Energy Controller : Part G IS0-AL: - * 2 ISOAL Features : - * The sequence number shall be incremented for each SDU_Interval, - * whether or not an SDU was received from or sent to the upper layer. - */ - if (next_state != ISOAL_ERR_SPOOL) { /* While in the Error state, received a valid start of the next SDU, * so SDU status and sequence number should be updated. */ sp->sdu_status = ISOAL_SDU_STATUS_VALID; /* sp->sdu_state will be set by next_state decided above */ - session->sn++; } break; } @@ -1072,11 +1270,12 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, /* Todo: check if effective len=0 what happens then? * We should possibly be able to send empty packets with only time stamp */ - + ISOAL_LOG_DBGV("[%p] Appending %lu bytes", sink, length); err |= isoal_rx_append_to_sdu(sink, pdu_meta, offset, length, cmplt, false); } /* Update next state */ + ISOAL_LOG_DBGV("[%p] Decoding: Next State %s", sink, FSM_TO_STR(next_state)); sp->fsm = next_state; /* Find next segment header, set to null if past end of PDU */ @@ -1100,6 +1299,7 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, */ next_state = ISOAL_ERR_SPOOL; + /* This maps directly to the HCI ISO Data packet Packet_Status_Flag by way of the * sdu_status in the SDU emitted. * BT Core V5.3 : Vol 4 HCI I/F : Part G HCI Func. Spec.: @@ -1112,41 +1312,48 @@ static isoal_status_t isoal_rx_framed_consume(struct isoal_sink *sink, * 0b10 Part(s) of the SDU were not received correctly. This is reported as * "lost data". */ + isoal_sdu_status_t next_sdu_status = ISOAL_SDU_STATUS_VALID; if (seq_err || seg_err) { - sp->sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; + next_sdu_status |= ISOAL_SDU_STATUS_LOST_DATA; } else if (pdu_err) { - sp->sdu_status |= meta->status; + next_sdu_status |= meta->status; } - if (sp->fsm == ISOAL_START) { - /* Sequence number should be incremented if an error - * occurs at the beginning. + switch (sp->fsm) { + case ISOAL_START: + /* First release lost SDUs and then release a new SDU + * with errors. Since we have an SDU to release + * following any lost SDUs, lost SDUs handling should be + * similar to when a valid timestamp exists. */ - session->sn++; + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, true, timestamp); + sp->sdu_status = next_sdu_status; + err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); + break; - if (sdu->timestamp == 0) { - /* Last timestamp is not valid so set an - * approximate timestamp - */ - anchorpoint = meta->timestamp; - latency = session->latency_framed; - timestamp = isoal_get_wrapped_time_us(anchorpoint, latency); + case ISOAL_CONTINUE: + /* If error occurs while an SDU is in production, + * release the SDU with errors and then check for lost + * SDUs. Since the SDU is already in production, the + * time stamp already set should be valid. + */ + sp->sdu_status = next_sdu_status; + err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, timestamp); + break; - sdu->timestamp = timestamp; - } else { - /* Advance the timestamp by an SDU interval */ - sdu->timestamp += session->sdu_interval; - } + case ISOAL_ERR_SPOOL: + err |= isoal_rx_framed_release_lost_sdus(sink, pdu_meta, false, timestamp); + break; } - /* Flush current SDU with error if any */ - err |= isoal_rx_append_to_sdu(sink, pdu_meta, 0, 0, true, false); - /* Update next state */ + ISOAL_LOG_DBGV("[%p] Error: Next State %s", sink, FSM_TO_STR(next_state)); sink->sdu_production.fsm = next_state; } sp->prev_pdu_id = meta->payload_number; + sp->initialized = true; return err; } @@ -1178,53 +1385,6 @@ isoal_status_t isoal_rx_pdu_recombine(isoal_sink_handle_t sink_hdl, #endif /* CONFIG_BT_CTLR_SYNC_ISO || CONFIG_BT_CTLR_CONN_ISO */ #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) -/** - * @brief Check if a time difference calculation is valid and return the difference. - * @param time_before Subtrahend - * @param time_after Minuend - * @param result Difference if valid - * @return Validity - valid if time_after leads time_before with - * consideration for wrapping such that the - * difference can be calculated. - */ -static bool isoal_get_time_diff(uint32_t time_before, uint32_t time_after, uint32_t *result) -{ - bool valid = false; - - LL_ASSERT(time_before <= ISOAL_TIME_WRAPPING_POINT_US); - LL_ASSERT(time_after <= ISOAL_TIME_WRAPPING_POINT_US); - - if (time_before > time_after) { - if (time_before >= ISOAL_TIME_MID_POINT_US && - time_after <= ISOAL_TIME_MID_POINT_US) { - if ((time_before - time_after) <= ISOAL_TIME_SPAN_HALF_US) { - /* Time_before is after time_after and the result is invalid. */ - } else { - /* time_after has wrapped */ - *result = time_after + ISOAL_TIME_SPAN_FULL_US - time_before; - valid = true; - } - } - - /* Time_before is after time_after and the result is invalid. */ - } else { - /* Time_before <= time_after */ - *result = time_after - time_before; - if (*result <= ISOAL_TIME_SPAN_HALF_US) { - /* result is valid if it is within half the maximum - * time span. - */ - valid = true; - } else { - /* time_before has wrapped and the calculation is not - * valid as time_before is ahead of time_after. - */ - } - } - - return valid; -} - /** * @brief Find free source from statically-sized pool and allocate it * @details Implemented as linear search since pool is very small @@ -1369,20 +1529,6 @@ isoal_status_t isoal_source_create( return err; } -/** - * @brief Get reference to configuration struct - * - * @param hdl[in] Handle to new source - * @return Reference to parameter struct, to be configured by caller - */ -struct isoal_source_config *isoal_get_source_param_ref(isoal_source_handle_t hdl) -{ - LL_ASSERT(hdl < CONFIG_BT_CTLR_ISOAL_SOURCES); - LL_ASSERT(isoal_global.source_allocated[hdl] == ISOAL_ALLOC_STATE_TAKEN); - - return &isoal_global.source_state[hdl].session.param; -} - /** * @brief Atomically enable latch-in of packets and PDU production * @param hdl[in] Handle of existing instance diff --git a/subsys/bluetooth/controller/ll_sw/isoal.h b/subsys/bluetooth/controller/ll_sw/isoal.h index 67068749cf60e2..304a54f77d40db 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.h +++ b/subsys/bluetooth/controller/ll_sw/isoal.h @@ -247,25 +247,18 @@ typedef isoal_status_t (*isoal_sink_sdu_write_cb)( const size_t consume_len ); - -struct isoal_sink_config { - enum isoal_mode mode; - /* TODO add SDU and PDU max length etc. */ -}; - struct isoal_sink_session { isoal_sink_sdu_alloc_cb sdu_alloc; isoal_sink_sdu_emit_cb sdu_emit; isoal_sink_sdu_write_cb sdu_write; - struct isoal_sink_config param; isoal_sdu_cnt_t sn; uint16_t handle; + uint16_t iso_interval; uint8_t pdus_per_sdu; uint8_t framed; uint8_t burst_number; uint32_t sdu_interval; - uint32_t latency_unframed; - uint32_t latency_framed; + uint32_t sdu_sync_const; }; struct isoal_sdu_production { @@ -285,6 +278,7 @@ struct isoal_sdu_production { /* Indicates that only padding PDUs have been received for this SDU */ uint64_t only_padding:1; uint64_t sdu_allocated:1; + uint64_t initialized:1; enum { ISOAL_START, ISOAL_CONTINUE, @@ -365,18 +359,12 @@ typedef isoal_status_t (*isoal_source_pdu_emit_cb)( const uint16_t handle ); -struct isoal_source_config { - enum isoal_mode mode; - /* TODO add SDU and PDU max length etc. */ -}; - struct isoal_source_session { isoal_source_pdu_alloc_cb pdu_alloc; isoal_source_pdu_write_cb pdu_write; isoal_source_pdu_emit_cb pdu_emit; isoal_source_pdu_release_cb pdu_release; - struct isoal_source_config param; isoal_sdu_cnt_t sn; uint16_t last_input_sn; uint32_t last_input_time_stamp; @@ -444,8 +432,6 @@ isoal_status_t isoal_sink_create(uint16_t handle, isoal_sink_sdu_write_cb sdu_write, isoal_sink_handle_t *hdl); -struct isoal_sink_config *isoal_get_sink_param_ref(isoal_sink_handle_t hdl); - void isoal_sink_enable(isoal_sink_handle_t hdl); void isoal_sink_disable(isoal_sink_handle_t hdl); @@ -482,8 +468,6 @@ isoal_status_t isoal_source_create(uint16_t handle, isoal_source_pdu_release_cb pdu_release, isoal_source_handle_t *hdl); -struct isoal_source_config *isoal_get_source_param_ref(isoal_source_handle_t hdl); - void isoal_source_enable(isoal_source_handle_t hdl); void isoal_source_disable(isoal_source_handle_t hdl);