Skip to content

Commit 6c855b4

Browse files
niag-Oticoncarlescufi
authored andcommitted
Bluetooth: Controller: implemented HCI_LE_Read_ISO_TX_Sync in ISO-AL
Implemented: -- Storing information required to service HCI_LE_Read_ISO_TX_Sync request -- Implemented interface to retrieve information -- Cleared ISO-AL source and sink state on deallocation -- Renamed cig_ref_point to grp_ref_point as it serves a common purpose in both CIS and BIS Signed-off-by: Nirosharn Amarasinghe <[email protected]>
1 parent 68b7b36 commit 6c855b4

File tree

4 files changed

+149
-23
lines changed

4 files changed

+149
-23
lines changed

subsys/bluetooth/controller/hci/hci.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5676,7 +5676,7 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt)
56765676
sdu_frag_tx.target_event = cis->lll.event_count +
56775677
(cis->lll.tx.flush_timeout > 1 ? 0 : 1);
56785678

5679-
sdu_frag_tx.cig_ref_point = cig->cig_ref_point;
5679+
sdu_frag_tx.grp_ref_point = cig->cig_ref_point;
56805680

56815681
/* Get controller's input data path for CIS */
56825682
dp_in = hdr->datapath_in;

subsys/bluetooth/controller/ll_sw/isoal.c

Lines changed: 109 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ struct
4646
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
4747
} isoal_global;
4848

49-
5049
/**
5150
* @brief Internal reset
5251
* Zero-init entire ISO-AL state
@@ -110,6 +109,7 @@ static isoal_status_t isoal_sink_allocate(isoal_sink_handle_t *hdl)
110109
static void isoal_sink_deallocate(isoal_sink_handle_t hdl)
111110
{
112111
isoal_global.sink_allocated[hdl] = ISOAL_ALLOC_STATE_FREE;
112+
(void)memset(&isoal_global.sink_state[hdl], 0, sizeof(struct isoal_sink));
113113
}
114114

115115
/**
@@ -122,8 +122,8 @@ static void isoal_sink_deallocate(isoal_sink_handle_t hdl)
122122
* @param flush_timeout[in] Flush timeout
123123
* @param sdu_interval[in] SDU interval
124124
* @param iso_interval[in] ISO interval
125-
* @param stream_sync_delay[in] CIS sync delay
126-
* @param group_sync_delay[in] CIG sync delay
125+
* @param stream_sync_delay[in] CIS / BIS sync delay
126+
* @param group_sync_delay[in] CIG / BIG sync delay
127127
* @param sdu_alloc[in] Callback of SDU allocator
128128
* @param sdu_emit[in] Callback of SDU emitter
129129
* @param sdu_write[in] Callback of SDU byte writer
@@ -987,6 +987,24 @@ static isoal_status_t isoal_source_allocate(isoal_source_handle_t *hdl)
987987
static void isoal_source_deallocate(isoal_source_handle_t hdl)
988988
{
989989
isoal_global.source_allocated[hdl] = ISOAL_ALLOC_STATE_FREE;
990+
(void)memset(&isoal_global.source_state[hdl], 0, sizeof(struct isoal_source));
991+
}
992+
993+
/**
994+
* @brief Check if a provided handle is valid
995+
* @param[in] hdl Input handle for validation
996+
* @return Handle valid / not valid
997+
*/
998+
static isoal_status_t isoal_check_source_hdl_valid(isoal_source_handle_t hdl)
999+
{
1000+
if (hdl < CONFIG_BT_CTLR_ISOAL_SOURCES &&
1001+
isoal_global.source_allocated[hdl] == ISOAL_ALLOC_STATE_TAKEN) {
1002+
return ISOAL_STATUS_OK;
1003+
}
1004+
1005+
BT_ERR("Invalid source handle (0x%02x)", hdl);
1006+
1007+
return ISOAL_STATUS_ERR_UNSPECIFIED;
9901008
}
9911009

9921010
/**
@@ -1000,8 +1018,8 @@ static void isoal_source_deallocate(isoal_source_handle_t hdl)
10001018
* @param max_octets[in] Maximum PDU size (Max_PDU_C_To_P / Max_PDU_P_To_C)
10011019
* @param sdu_interval[in] SDU interval
10021020
* @param iso_interval[in] ISO interval
1003-
* @param stream_sync_delay[in] CIS sync delay
1004-
* @param group_sync_delay[in] CIG sync delay
1021+
* @param stream_sync_delay[in] CIS / BIS sync delay
1022+
* @param group_sync_delay[in] CIG / BIG sync delay
10051023
* @param pdu_alloc[in] Callback of PDU allocator
10061024
* @param pdu_write[in] Callback of PDU byte writer
10071025
* @param pdu_emit[in] Callback of PDU emitter
@@ -1293,6 +1311,10 @@ static isoal_status_t isoal_tx_unframed_produce(struct isoal_source *source,
12931311

12941312
if (tx_sdu->sdu_state == BT_ISO_START ||
12951313
tx_sdu->sdu_state == BT_ISO_SINGLE) {
1314+
/* Initialize to info provided in SDU */
1315+
uint32_t actual_grp_ref_point = tx_sdu->grp_ref_point;
1316+
uint64_t actual_event = tx_sdu->target_event;
1317+
12961318
/* Start of a new SDU */
12971319

12981320
/* Update sequence number for received SDU
@@ -1320,6 +1342,33 @@ static isoal_status_t isoal_tx_unframed_produce(struct isoal_source *source,
13201342
pp->payload_number = MAX(pp->payload_number,
13211343
(tx_sdu->target_event * session->burst_number));
13221344

1345+
/* Get actual event for this payload number */
1346+
actual_event = pp->payload_number / session->burst_number;
1347+
1348+
/* Get group reference point for this PDU based on the actual
1349+
* event being set. This might introduce some errors as the
1350+
* group refernce point for future events could drift. However
1351+
* as the time offset calculation requires an absolute value,
1352+
* this seems to be the best candidate. As the actual group
1353+
* refereence point is 32-bits, it is expected that advancing
1354+
* the reference point will cause it to wrap around.
1355+
*/
1356+
if (actual_event > tx_sdu->target_event) {
1357+
actual_grp_ref_point = (uint32_t)(tx_sdu->grp_ref_point +
1358+
((actual_event - tx_sdu->target_event) * session->iso_interval *
1359+
ISO_INT_UNIT_US));
1360+
}
1361+
1362+
/* Store timing info for TX Sync command */
1363+
session->tx_time_stamp = actual_grp_ref_point;
1364+
/* BT Core V5.3 : Vol 4 HCI : Part E HCI Functional Spec:
1365+
* 7.8.96 LE Read ISO TX Sync Command:
1366+
* When the Connection_Handle identifies a CIS or BIS that is
1367+
* transmitting unframed PDUs the value of Time_Offset returned
1368+
* shall be zero
1369+
* Relies on initialization value being 0.
1370+
*/
1371+
13231372
/* Reset PDU fragmentation count for this SDU */
13241373
pp->pdu_cnt = 0;
13251374

@@ -1564,7 +1613,7 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
15641613
/* Start of a new SDU */
15651614

15661615
/* Initialize to info provided in SDU */
1567-
uint32_t actual_cig_ref_point = tx_sdu->cig_ref_point;
1616+
uint32_t actual_grp_ref_point = tx_sdu->grp_ref_point;
15681617
uint64_t actual_event = tx_sdu->target_event;
15691618

15701619
/* Update sequence number for received SDU
@@ -1598,38 +1647,43 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
15981647
/* Get actual event for this payload number */
15991648
actual_event = pp->payload_number / session->burst_number;
16001649

1601-
/* Get cig reference point for this PDU based on the actual
1602-
* event being set. This might introduce some errors as the cig
1603-
* refernce point for future events could drift. However as the
1604-
* time offset calculation requires an absolute value, this
1605-
* seems to be the best candidate.
1650+
/* Get group reference point for this PDU based on the actual
1651+
* event being set. This might introduce some errors as the
1652+
* group refernce point for future events could drift. However
1653+
* as the time offset calculation requires an absolute value,
1654+
* this seems to be the best candidate.
16061655
*/
16071656
if (actual_event > tx_sdu->target_event) {
1608-
actual_cig_ref_point = tx_sdu->cig_ref_point +
1657+
actual_grp_ref_point = tx_sdu->grp_ref_point +
16091658
((actual_event - tx_sdu->target_event) * session->iso_interval *
16101659
ISO_INT_UNIT_US);
16111660
}
16121661

1613-
/* Check if time stamp on packet is later than the CIG reference
1614-
* point and adjust targets. This could happen if the SDU has
1615-
* been time-stampped at the controller when received via HCI.
1662+
/* Check if time stamp on packet is later than the group
1663+
* reference point and adjust targets. This could happen if the
1664+
* SDU has been time-stampped at the controller when received
1665+
* via HCI.
16161666
*
16171667
* BT Core V5.3 : Vol 6 Low Energy Controller : Part G IS0-AL:
16181668
* 3.1 Time_Offset in framed PDUs :
16191669
* The Time_Offset shall be a positive value.
16201670
*/
1621-
if (actual_cig_ref_point <= tx_sdu->time_stamp) {
1671+
if (actual_grp_ref_point <= tx_sdu->time_stamp) {
16221672
/* Advance target to next event */
16231673
actual_event++;
1624-
actual_cig_ref_point += session->iso_interval * ISO_INT_UNIT_US;
1674+
actual_grp_ref_point += session->iso_interval * ISO_INT_UNIT_US;
16251675

16261676
/* Set payload number */
16271677
pp->payload_number = actual_event * session->burst_number;
16281678
}
16291679

16301680
/* Calculate the time offset */
1631-
LL_ASSERT(actual_cig_ref_point > tx_sdu->time_stamp);
1632-
time_offset = actual_cig_ref_point - tx_sdu->time_stamp;
1681+
LL_ASSERT(actual_grp_ref_point > tx_sdu->time_stamp);
1682+
time_offset = actual_grp_ref_point - tx_sdu->time_stamp;
1683+
1684+
/* Store timing info for TX Sync command */
1685+
session->tx_time_stamp = actual_grp_ref_point;
1686+
session->tx_time_offset = time_offset;
16331687

16341688
/* Reset PDU fragmentation count for this SDU */
16351689
pp->pdu_cnt = 0;
@@ -1793,4 +1847,40 @@ void isoal_tx_pdu_release(isoal_source_handle_t source_hdl,
17931847
ISOAL_STATUS_OK);
17941848
}
17951849
}
1850+
1851+
/**
1852+
* @brief Get information required for HCI_LE_Read_ISO_TX_Sync
1853+
* @param source_hdl Source handle linked to handle provided in HCI message
1854+
* @param seq Packet Sequence number of last SDU
1855+
* @param timestamp CIG / BIG reference point of last SDU
1856+
* @param offset Time-offset (Framed) / 0 (Unframed) of last SDU
1857+
* @return Operation status
1858+
*/
1859+
isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
1860+
uint16_t *seq,
1861+
uint32_t *timestamp,
1862+
uint32_t *offset)
1863+
{
1864+
if (isoal_check_source_hdl_valid(source_hdl) == ISOAL_STATUS_OK) {
1865+
struct isoal_source_session *session;
1866+
1867+
session = &isoal_global.source_state[source_hdl].session;
1868+
1869+
/* BT Core V5.3 : Vol 4 HCI : Part E HCI Functional Spec:
1870+
* 7.8.96 LE Read ISO TX Sync Command:
1871+
* If the Host issues this command before an SDU had been transmitted by
1872+
* the Controller, then Controller shall return the error code Command
1873+
* Disallowed.
1874+
*/
1875+
if (session->seqn > 0) {
1876+
*seq = session->seqn;
1877+
*timestamp = session->tx_time_stamp;
1878+
*offset = session->tx_time_offset;
1879+
return ISOAL_STATUS_OK;
1880+
}
1881+
}
1882+
1883+
return ISOAL_STATUS_ERR_UNSPECIFIED;
1884+
}
1885+
17961886
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */

subsys/bluetooth/controller/ll_sw/isoal.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ struct isoal_sdu_tx {
157157
/** Time stamp from HCI or vendor specific path (us) */
158158
uint32_t time_stamp;
159159
/** CIG Reference of target event (us, compensated for drift) */
160-
uint32_t cig_ref_point;
160+
uint32_t grp_ref_point;
161161
/** Target Event of SDU */
162162
uint64_t target_event:39;
163163
};
@@ -335,6 +335,8 @@ struct isoal_source_session {
335335

336336
struct isoal_source_config param;
337337
isoal_sdu_cnt_t seqn;
338+
uint32_t tx_time_stamp;
339+
uint32_t tx_time_offset;
338340
uint16_t handle;
339341
uint16_t iso_interval;
340342
uint8_t framed;
@@ -441,3 +443,8 @@ isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl,
441443

442444
void isoal_tx_pdu_release(isoal_source_handle_t source_hdl,
443445
struct node_tx_iso *node_tx);
446+
447+
isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
448+
uint16_t *seq,
449+
uint32_t *timestamp,
450+
uint32_t *offset);

subsys/bluetooth/controller/ll_sw/ull_iso.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,41 @@ __weak bool ll_data_path_configured(uint8_t data_path_dir,
154154
uint8_t ll_read_iso_tx_sync(uint16_t handle, uint16_t *seq,
155155
uint32_t *timestamp, uint32_t *offset)
156156
{
157+
#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
158+
159+
if (IS_CIS_HANDLE(handle)) {
160+
struct ll_iso_datapath *dp = NULL;
161+
struct ll_conn_iso_stream *cis;
162+
163+
cis = ll_conn_iso_stream_get(handle);
164+
165+
if (cis) {
166+
dp = cis->hdr.datapath_in;
167+
}
168+
169+
if (dp &&
170+
isoal_tx_get_sync_info(dp->source_hdl, seq,
171+
timestamp, offset) == ISOAL_STATUS_OK) {
172+
return BT_HCI_ERR_SUCCESS;
173+
}
174+
175+
return BT_HCI_ERR_CMD_DISALLOWED;
176+
177+
} else if (IS_ADV_ISO_HANDLE(handle)) {
178+
/* FIXME: Do something similar to connected */
179+
180+
return BT_HCI_ERR_CMD_DISALLOWED;
181+
}
182+
183+
return BT_HCI_ERR_UNKNOWN_CONN_ID;
184+
#else
157185
ARG_UNUSED(handle);
158186
ARG_UNUSED(seq);
159187
ARG_UNUSED(timestamp);
160188
ARG_UNUSED(offset);
161189

162190
return BT_HCI_ERR_CMD_DISALLOWED;
191+
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
163192
}
164193

165194
/* Must be implemented by vendor */
@@ -951,9 +980,9 @@ void ll_iso_transmit_test_send_sdu(uint16_t handle, uint32_t ticks_at_expire)
951980

952981
/* Configure SDU similarly to one delivered via HCI */
953982
sdu.dbuf = tx_buffer;
954-
sdu.cig_ref_point = cig->cig_ref_point;
983+
sdu.grp_ref_point = cig->cig_ref_point;
955984
sdu.target_event = cis->lll.event_count +
956-
(cis->lll.tx.flush_timeout > 1U ? 0U : 1U);
985+
(cis->lll.tx.flush_timeout > 1U ? 0U : 1U);
957986
sdu.iso_sdu_length = remaining_tx;
958987

959988
/* Send all SDU fragments */

0 commit comments

Comments
 (0)