mirror of
https://github.com/Dasharo/zephyr.git
synced 2026-03-06 14:57:20 -08:00
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 <niag@demant.com>
This commit is contained in:
committed by
Carles Cufí
parent
68b7b36adf
commit
6c855b43be
@@ -5676,7 +5676,7 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt)
|
||||
sdu_frag_tx.target_event = cis->lll.event_count +
|
||||
(cis->lll.tx.flush_timeout > 1 ? 0 : 1);
|
||||
|
||||
sdu_frag_tx.cig_ref_point = cig->cig_ref_point;
|
||||
sdu_frag_tx.grp_ref_point = cig->cig_ref_point;
|
||||
|
||||
/* Get controller's input data path for CIS */
|
||||
dp_in = hdr->datapath_in;
|
||||
|
||||
@@ -46,7 +46,6 @@ struct
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
|
||||
} isoal_global;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Internal reset
|
||||
* Zero-init entire ISO-AL state
|
||||
@@ -110,6 +109,7 @@ static isoal_status_t isoal_sink_allocate(isoal_sink_handle_t *hdl)
|
||||
static void isoal_sink_deallocate(isoal_sink_handle_t hdl)
|
||||
{
|
||||
isoal_global.sink_allocated[hdl] = ISOAL_ALLOC_STATE_FREE;
|
||||
(void)memset(&isoal_global.sink_state[hdl], 0, sizeof(struct isoal_sink));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,8 +122,8 @@ static void isoal_sink_deallocate(isoal_sink_handle_t hdl)
|
||||
* @param flush_timeout[in] Flush timeout
|
||||
* @param sdu_interval[in] SDU interval
|
||||
* @param iso_interval[in] ISO interval
|
||||
* @param stream_sync_delay[in] CIS sync delay
|
||||
* @param group_sync_delay[in] CIG sync delay
|
||||
* @param stream_sync_delay[in] CIS / BIS sync delay
|
||||
* @param group_sync_delay[in] CIG / BIG sync delay
|
||||
* @param sdu_alloc[in] Callback of SDU allocator
|
||||
* @param sdu_emit[in] Callback of SDU emitter
|
||||
* @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)
|
||||
static void isoal_source_deallocate(isoal_source_handle_t hdl)
|
||||
{
|
||||
isoal_global.source_allocated[hdl] = ISOAL_ALLOC_STATE_FREE;
|
||||
(void)memset(&isoal_global.source_state[hdl], 0, sizeof(struct isoal_source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a provided handle is valid
|
||||
* @param[in] hdl Input handle for validation
|
||||
* @return Handle valid / not valid
|
||||
*/
|
||||
static isoal_status_t isoal_check_source_hdl_valid(isoal_source_handle_t hdl)
|
||||
{
|
||||
if (hdl < CONFIG_BT_CTLR_ISOAL_SOURCES &&
|
||||
isoal_global.source_allocated[hdl] == ISOAL_ALLOC_STATE_TAKEN) {
|
||||
return ISOAL_STATUS_OK;
|
||||
}
|
||||
|
||||
BT_ERR("Invalid source handle (0x%02x)", hdl);
|
||||
|
||||
return ISOAL_STATUS_ERR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1000,8 +1018,8 @@ static void isoal_source_deallocate(isoal_source_handle_t hdl)
|
||||
* @param max_octets[in] Maximum PDU size (Max_PDU_C_To_P / Max_PDU_P_To_C)
|
||||
* @param sdu_interval[in] SDU interval
|
||||
* @param iso_interval[in] ISO interval
|
||||
* @param stream_sync_delay[in] CIS sync delay
|
||||
* @param group_sync_delay[in] CIG sync delay
|
||||
* @param stream_sync_delay[in] CIS / BIS sync delay
|
||||
* @param group_sync_delay[in] CIG / BIG sync delay
|
||||
* @param pdu_alloc[in] Callback of PDU allocator
|
||||
* @param pdu_write[in] Callback of PDU byte writer
|
||||
* @param pdu_emit[in] Callback of PDU emitter
|
||||
@@ -1293,6 +1311,10 @@ static isoal_status_t isoal_tx_unframed_produce(struct isoal_source *source,
|
||||
|
||||
if (tx_sdu->sdu_state == BT_ISO_START ||
|
||||
tx_sdu->sdu_state == BT_ISO_SINGLE) {
|
||||
/* Initialize to info provided in SDU */
|
||||
uint32_t actual_grp_ref_point = tx_sdu->grp_ref_point;
|
||||
uint64_t actual_event = tx_sdu->target_event;
|
||||
|
||||
/* Start of a new SDU */
|
||||
|
||||
/* Update sequence number for received SDU
|
||||
@@ -1320,6 +1342,33 @@ static isoal_status_t isoal_tx_unframed_produce(struct isoal_source *source,
|
||||
pp->payload_number = MAX(pp->payload_number,
|
||||
(tx_sdu->target_event * session->burst_number));
|
||||
|
||||
/* Get actual event for this payload number */
|
||||
actual_event = pp->payload_number / session->burst_number;
|
||||
|
||||
/* Get group reference point for this PDU based on the actual
|
||||
* event being set. This might introduce some errors as the
|
||||
* group refernce point for future events could drift. However
|
||||
* as the time offset calculation requires an absolute value,
|
||||
* this seems to be the best candidate. As the actual group
|
||||
* refereence point is 32-bits, it is expected that advancing
|
||||
* the reference point will cause it to wrap around.
|
||||
*/
|
||||
if (actual_event > tx_sdu->target_event) {
|
||||
actual_grp_ref_point = (uint32_t)(tx_sdu->grp_ref_point +
|
||||
((actual_event - tx_sdu->target_event) * session->iso_interval *
|
||||
ISO_INT_UNIT_US));
|
||||
}
|
||||
|
||||
/* Store timing info for TX Sync command */
|
||||
session->tx_time_stamp = actual_grp_ref_point;
|
||||
/* BT Core V5.3 : Vol 4 HCI : Part E HCI Functional Spec:
|
||||
* 7.8.96 LE Read ISO TX Sync Command:
|
||||
* When the Connection_Handle identifies a CIS or BIS that is
|
||||
* transmitting unframed PDUs the value of Time_Offset returned
|
||||
* shall be zero
|
||||
* Relies on initialization value being 0.
|
||||
*/
|
||||
|
||||
/* Reset PDU fragmentation count for this SDU */
|
||||
pp->pdu_cnt = 0;
|
||||
|
||||
@@ -1564,7 +1613,7 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
|
||||
/* Start of a new SDU */
|
||||
|
||||
/* Initialize to info provided in SDU */
|
||||
uint32_t actual_cig_ref_point = tx_sdu->cig_ref_point;
|
||||
uint32_t actual_grp_ref_point = tx_sdu->grp_ref_point;
|
||||
uint64_t actual_event = tx_sdu->target_event;
|
||||
|
||||
/* Update sequence number for received SDU
|
||||
@@ -1598,38 +1647,43 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
|
||||
/* Get actual event for this payload number */
|
||||
actual_event = pp->payload_number / session->burst_number;
|
||||
|
||||
/* Get cig reference point for this PDU based on the actual
|
||||
* event being set. This might introduce some errors as the cig
|
||||
* refernce point for future events could drift. However as the
|
||||
* time offset calculation requires an absolute value, this
|
||||
* seems to be the best candidate.
|
||||
/* Get group reference point for this PDU based on the actual
|
||||
* event being set. This might introduce some errors as the
|
||||
* group refernce point for future events could drift. However
|
||||
* as the time offset calculation requires an absolute value,
|
||||
* this seems to be the best candidate.
|
||||
*/
|
||||
if (actual_event > tx_sdu->target_event) {
|
||||
actual_cig_ref_point = tx_sdu->cig_ref_point +
|
||||
actual_grp_ref_point = tx_sdu->grp_ref_point +
|
||||
((actual_event - tx_sdu->target_event) * session->iso_interval *
|
||||
ISO_INT_UNIT_US);
|
||||
}
|
||||
|
||||
/* Check if time stamp on packet is later than the CIG reference
|
||||
* point and adjust targets. This could happen if the SDU has
|
||||
* been time-stampped at the controller when received via HCI.
|
||||
/* Check if time stamp on packet is later than the group
|
||||
* reference point and adjust targets. This could happen if the
|
||||
* SDU has been time-stampped at the controller when received
|
||||
* via HCI.
|
||||
*
|
||||
* BT Core V5.3 : Vol 6 Low Energy Controller : Part G IS0-AL:
|
||||
* 3.1 Time_Offset in framed PDUs :
|
||||
* The Time_Offset shall be a positive value.
|
||||
*/
|
||||
if (actual_cig_ref_point <= tx_sdu->time_stamp) {
|
||||
if (actual_grp_ref_point <= tx_sdu->time_stamp) {
|
||||
/* Advance target to next event */
|
||||
actual_event++;
|
||||
actual_cig_ref_point += session->iso_interval * ISO_INT_UNIT_US;
|
||||
actual_grp_ref_point += session->iso_interval * ISO_INT_UNIT_US;
|
||||
|
||||
/* Set payload number */
|
||||
pp->payload_number = actual_event * session->burst_number;
|
||||
}
|
||||
|
||||
/* Calculate the time offset */
|
||||
LL_ASSERT(actual_cig_ref_point > tx_sdu->time_stamp);
|
||||
time_offset = actual_cig_ref_point - tx_sdu->time_stamp;
|
||||
LL_ASSERT(actual_grp_ref_point > tx_sdu->time_stamp);
|
||||
time_offset = actual_grp_ref_point - tx_sdu->time_stamp;
|
||||
|
||||
/* Store timing info for TX Sync command */
|
||||
session->tx_time_stamp = actual_grp_ref_point;
|
||||
session->tx_time_offset = time_offset;
|
||||
|
||||
/* Reset PDU fragmentation count for this SDU */
|
||||
pp->pdu_cnt = 0;
|
||||
@@ -1793,4 +1847,40 @@ void isoal_tx_pdu_release(isoal_source_handle_t source_hdl,
|
||||
ISOAL_STATUS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get information required for HCI_LE_Read_ISO_TX_Sync
|
||||
* @param source_hdl Source handle linked to handle provided in HCI message
|
||||
* @param seq Packet Sequence number of last SDU
|
||||
* @param timestamp CIG / BIG reference point of last SDU
|
||||
* @param offset Time-offset (Framed) / 0 (Unframed) of last SDU
|
||||
* @return Operation status
|
||||
*/
|
||||
isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
|
||||
uint16_t *seq,
|
||||
uint32_t *timestamp,
|
||||
uint32_t *offset)
|
||||
{
|
||||
if (isoal_check_source_hdl_valid(source_hdl) == ISOAL_STATUS_OK) {
|
||||
struct isoal_source_session *session;
|
||||
|
||||
session = &isoal_global.source_state[source_hdl].session;
|
||||
|
||||
/* BT Core V5.3 : Vol 4 HCI : Part E HCI Functional Spec:
|
||||
* 7.8.96 LE Read ISO TX Sync Command:
|
||||
* If the Host issues this command before an SDU had been transmitted by
|
||||
* the Controller, then Controller shall return the error code Command
|
||||
* Disallowed.
|
||||
*/
|
||||
if (session->seqn > 0) {
|
||||
*seq = session->seqn;
|
||||
*timestamp = session->tx_time_stamp;
|
||||
*offset = session->tx_time_offset;
|
||||
return ISOAL_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ISOAL_STATUS_ERR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
|
||||
|
||||
@@ -157,7 +157,7 @@ struct isoal_sdu_tx {
|
||||
/** Time stamp from HCI or vendor specific path (us) */
|
||||
uint32_t time_stamp;
|
||||
/** CIG Reference of target event (us, compensated for drift) */
|
||||
uint32_t cig_ref_point;
|
||||
uint32_t grp_ref_point;
|
||||
/** Target Event of SDU */
|
||||
uint64_t target_event:39;
|
||||
};
|
||||
@@ -335,6 +335,8 @@ struct isoal_source_session {
|
||||
|
||||
struct isoal_source_config param;
|
||||
isoal_sdu_cnt_t seqn;
|
||||
uint32_t tx_time_stamp;
|
||||
uint32_t tx_time_offset;
|
||||
uint16_t handle;
|
||||
uint16_t iso_interval;
|
||||
uint8_t framed;
|
||||
@@ -441,3 +443,8 @@ isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl,
|
||||
|
||||
void isoal_tx_pdu_release(isoal_source_handle_t source_hdl,
|
||||
struct node_tx_iso *node_tx);
|
||||
|
||||
isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
|
||||
uint16_t *seq,
|
||||
uint32_t *timestamp,
|
||||
uint32_t *offset);
|
||||
|
||||
@@ -154,12 +154,41 @@ __weak bool ll_data_path_configured(uint8_t data_path_dir,
|
||||
uint8_t ll_read_iso_tx_sync(uint16_t handle, uint16_t *seq,
|
||||
uint32_t *timestamp, uint32_t *offset)
|
||||
{
|
||||
#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
|
||||
|
||||
if (IS_CIS_HANDLE(handle)) {
|
||||
struct ll_iso_datapath *dp = NULL;
|
||||
struct ll_conn_iso_stream *cis;
|
||||
|
||||
cis = ll_conn_iso_stream_get(handle);
|
||||
|
||||
if (cis) {
|
||||
dp = cis->hdr.datapath_in;
|
||||
}
|
||||
|
||||
if (dp &&
|
||||
isoal_tx_get_sync_info(dp->source_hdl, seq,
|
||||
timestamp, offset) == ISOAL_STATUS_OK) {
|
||||
return BT_HCI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
|
||||
} else if (IS_ADV_ISO_HANDLE(handle)) {
|
||||
/* FIXME: Do something similar to connected */
|
||||
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
#else
|
||||
ARG_UNUSED(handle);
|
||||
ARG_UNUSED(seq);
|
||||
ARG_UNUSED(timestamp);
|
||||
ARG_UNUSED(offset);
|
||||
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
|
||||
}
|
||||
|
||||
/* Must be implemented by vendor */
|
||||
@@ -951,9 +980,9 @@ void ll_iso_transmit_test_send_sdu(uint16_t handle, uint32_t ticks_at_expire)
|
||||
|
||||
/* Configure SDU similarly to one delivered via HCI */
|
||||
sdu.dbuf = tx_buffer;
|
||||
sdu.cig_ref_point = cig->cig_ref_point;
|
||||
sdu.grp_ref_point = cig->cig_ref_point;
|
||||
sdu.target_event = cis->lll.event_count +
|
||||
(cis->lll.tx.flush_timeout > 1U ? 0U : 1U);
|
||||
(cis->lll.tx.flush_timeout > 1U ? 0U : 1U);
|
||||
sdu.iso_sdu_length = remaining_tx;
|
||||
|
||||
/* Send all SDU fragments */
|
||||
|
||||
Reference in New Issue
Block a user