2828#include "common/log.h"
2929#include "hal/debug.h"
3030
31+ #if defined(CONFIG_BT_CTLR_ADV_ISO ) || defined(CONFIG_BT_CTLR_CONN_ISO )
32+ /* Given the minimum payload, this defines the minimum number of bytes that
33+ * should be remaining in a TX PDU such that it would make inserting a new
34+ * segment worthwhile during the segmentation process.
35+ * [Payload (min) + Segmentation Header + Time Offset]
36+ */
37+ #define ISOAL_TX_SEGMENT_MIN_SIZE (CONFIG_BT_CTLR_ISO_TX_SEG_PLAYLOAD_MIN + \
38+ PDU_ISO_SEG_HDR_SIZE + \
39+ PDU_ISO_SEG_TIMEOFFSET_SIZE)
40+ #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
41+
3142/** Allocation state */
3243typedef uint8_t isoal_alloc_state_t ;
3344#define ISOAL_ALLOC_STATE_FREE ((isoal_alloc_state_t) 0x00)
@@ -1106,6 +1117,21 @@ static isoal_status_t isoal_source_allocate(isoal_source_handle_t *hdl)
11061117 */
11071118static void isoal_source_deallocate (isoal_source_handle_t hdl )
11081119{
1120+ struct isoal_pdu_production * pp ;
1121+ struct isoal_source * source ;
1122+
1123+ source = & isoal_global .source_state [hdl ];
1124+ pp = & source -> pdu_production ;
1125+
1126+ if (pp -> pdu_available > 0 ) {
1127+ /* There is a pending PDU that should be released */
1128+ if (source && source -> session .pdu_release ) {
1129+ source -> session .pdu_release (pp -> pdu .contents .handle ,
1130+ source -> session .handle ,
1131+ ISOAL_STATUS_ERR_PDU_EMIT );
1132+ }
1133+ }
1134+
11091135 isoal_global .source_allocated [hdl ] = ISOAL_ALLOC_STATE_FREE ;
11101136 (void )memset (& isoal_global .source_state [hdl ], 0 , sizeof (struct isoal_source ));
11111137}
@@ -1884,18 +1910,11 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
18841910 /* LLID is fixed for framed PDUs */
18851911 ll_id = PDU_BIS_LLID_FRAMED ;
18861912
1887- /* NOTE: Ideally even if the end of the SDU is reached, the PDU
1888- * should not be emitted as long as there is space left. If the
1889- * PDU is not released, it might require a flush timeout to
1890- * trigger the release as receiving an SDU per SDU interval is
1891- * not guaranteed. As there is no trigger for this in the
1892- * ISO-AL, the PDU is released. This does mean that the
1893- * bandwidth of this implementation will be less that the ideal
1894- * supported by framed PDUs. Ideally ISOAL_SEGMENT_MIN_SIZE
1895- * should be used to assess if there is sufficient usable space
1896- * left in the PDU.
1913+ /* If there isn't sufficient usable space then release the
1914+ * PDU when the end of the SDU is reached, instead of waiting
1915+ * for the next SDU.
18971916 */
1898- bool release_pdu = end_of_sdu ;
1917+ bool release_pdu = end_of_sdu && ( pp -> pdu_available <= ISOAL_TX_SEGMENT_MIN_SIZE ) ;
18991918 const isoal_status_t err_emit = isoal_tx_try_emit_pdu (source , release_pdu , ll_id );
19001919
19011920 err |= err_emit ;
@@ -1918,6 +1937,41 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
19181937 return err ;
19191938}
19201939
1940+ /**
1941+ * @brief Handle preparation of the given source before commencing TX on the
1942+ * specified event (only for framed sources)
1943+ * @param source_hdl Handle of source to prepare
1944+ * @param event_count Event number source should be prepared for
1945+ * @return Status of operation
1946+ */
1947+ static isoal_status_t isoal_tx_framed_event_prepare_handle (isoal_source_handle_t source_hdl ,
1948+ uint64_t event_count )
1949+ {
1950+ struct isoal_source_session * session ;
1951+ struct isoal_pdu_production * pp ;
1952+ struct isoal_source * source ;
1953+ uint64_t last_event_payload ;
1954+ isoal_status_t err ;
1955+
1956+ err = ISOAL_STATUS_OK ;
1957+
1958+ source = & isoal_global .source_state [source_hdl ];
1959+ session = & source -> session ;
1960+ pp = & source -> pdu_production ;
1961+ last_event_payload = (session -> burst_number * (event_count + 1 )) - 1 ;
1962+
1963+ if (pp -> pdu_available > 0 &&
1964+ pp -> payload_number <= last_event_payload ) {
1965+ /* Pending PDU that should be released for framed TX */
1966+ err = isoal_tx_try_emit_pdu (source , true, PDU_BIS_LLID_FRAMED );
1967+ }
1968+
1969+ if (pp -> payload_number < last_event_payload + 1 ) {
1970+ pp -> payload_number = last_event_payload + 1 ;
1971+ }
1972+
1973+ return err ;
1974+ }
19211975
19221976/**
19231977 * @brief Deep copy a SDU, fragment into PDU(s)
@@ -1930,12 +1984,19 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
19301984isoal_status_t isoal_tx_sdu_fragment (isoal_source_handle_t source_hdl ,
19311985 struct isoal_sdu_tx * tx_sdu )
19321986{
1987+ struct isoal_source_session * session ;
19331988 struct isoal_source * source ;
19341989 isoal_status_t err ;
19351990
19361991 source = & isoal_global .source_state [source_hdl ];
1992+ session = & source -> session ;
19371993 err = ISOAL_STATUS_ERR_PDU_ALLOC ;
19381994
1995+ /* Set source context active to mutually exclude ISO Event prepare
1996+ * kick.
1997+ */
1998+ source -> context_active = true;
1999+
19392000 if (source -> pdu_production .mode != ISOAL_PRODUCTION_MODE_DISABLED ) {
19402001 /* BT Core V5.3 : Vol 6 Low Energy Controller : Part G IS0-AL:
19412002 * 2 ISOAL Features :
@@ -1954,6 +2015,16 @@ isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl,
19542015 }
19552016 }
19562017
2018+ source -> context_active = false;
2019+
2020+ if (source -> timeout_trigger ) {
2021+ source -> timeout_trigger = false;
2022+ if (session -> framed ) {
2023+ isoal_tx_framed_event_prepare_handle (source_hdl ,
2024+ source -> timeout_event_count );
2025+ }
2026+ }
2027+
19572028 return err ;
19582029}
19592030
@@ -2003,4 +2074,35 @@ isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
20032074 return ISOAL_STATUS_ERR_UNSPECIFIED ;
20042075}
20052076
2077+ /**
2078+ * @brief Incoming prepare request before commencing TX for the specified
2079+ * event
2080+ * @param source_hdl Handle of source to prepare
2081+ * @param event_count Event number source should be prepared for
2082+ * @return Status of operation
2083+ */
2084+ void isoal_tx_event_prepare (isoal_source_handle_t source_hdl ,
2085+ uint64_t event_count )
2086+ {
2087+ struct isoal_source_session * session ;
2088+ struct isoal_source * source ;
2089+
2090+ source = & isoal_global .source_state [source_hdl ];
2091+ session = & source -> session ;
2092+
2093+ /* Store prepare timeout information and check if fragmentation context
2094+ * is active.
2095+ */
2096+ source -> timeout_event_count = event_count ;
2097+ source -> timeout_trigger = true;
2098+ if (source -> context_active ) {
2099+ return ;
2100+ }
2101+ source -> timeout_trigger = false;
2102+
2103+ if (session -> framed ) {
2104+ isoal_tx_framed_event_prepare_handle (source_hdl , event_count );
2105+ }
2106+ }
2107+
20062108#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
0 commit comments