Bluetooth: controller: Move CIS peripheral functionality to ull_conn_iso
Move ull_peripheral_iso_start ull_peripheral_iso_ticker_cb to ull_conn_iso, to share code between CIS peripheral and central. Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
parent
38a4e58d1f
commit
64ade9e01d
6 changed files with 211 additions and 201 deletions
|
@ -6429,7 +6429,7 @@ void event_peripheral_iso_prep(struct ll_conn *conn, uint16_t event_counter,
|
||||||
/* Start ISO peripheral one event before the requested instant */
|
/* Start ISO peripheral one event before the requested instant */
|
||||||
if (event_counter == start_event_count) {
|
if (event_counter == start_event_count) {
|
||||||
/* Start CIS peripheral */
|
/* Start CIS peripheral */
|
||||||
ull_peripheral_iso_start(conn, ticks_at_expire, conn->llcp_cis.cis_handle);
|
ull_conn_iso_start(conn, ticks_at_expire, conn->llcp_cis.cis_handle);
|
||||||
|
|
||||||
conn->llcp_cis.state = LLCP_CIS_STATE_REQ;
|
conn->llcp_cis.state = LLCP_CIS_STATE_REQ;
|
||||||
conn->llcp_cis.ack = conn->llcp_cis.req;
|
conn->llcp_cis.ack = conn->llcp_cis.req;
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "pdu.h"
|
#include "pdu.h"
|
||||||
#include "lll.h"
|
#include "lll.h"
|
||||||
#include "lll_conn.h"
|
#include "lll_conn.h"
|
||||||
|
#include "lll_clock.h"
|
||||||
|
#include "lll_peripheral_iso.h"
|
||||||
|
#include "lll_central_iso.h"
|
||||||
|
|
||||||
#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
||||||
#include "ull_tx_queue.h"
|
#include "ull_tx_queue.h"
|
||||||
|
@ -31,6 +34,7 @@
|
||||||
#include "ull_conn_iso_types.h"
|
#include "ull_conn_iso_types.h"
|
||||||
#include "ull_conn_internal.h"
|
#include "ull_conn_internal.h"
|
||||||
#include "ull_conn_iso_internal.h"
|
#include "ull_conn_iso_internal.h"
|
||||||
|
#include "ull_peripheral_iso_internal.h"
|
||||||
#include "ull_internal.h"
|
#include "ull_internal.h"
|
||||||
#include "lll/lll_vendor.h"
|
#include "lll/lll_vendor.h"
|
||||||
|
|
||||||
|
@ -480,6 +484,196 @@ static int init_reset(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
|
||||||
|
uint32_t remainder, uint16_t lazy, uint8_t force,
|
||||||
|
void *param)
|
||||||
|
{
|
||||||
|
static memq_link_t link;
|
||||||
|
static struct mayfly mfy = { 0, 0, &link, NULL, lll_peripheral_iso_prepare };
|
||||||
|
static struct lll_prepare_param p;
|
||||||
|
struct ll_conn_iso_group *cig;
|
||||||
|
struct ll_conn_iso_stream *cis;
|
||||||
|
uint64_t leading_event_count;
|
||||||
|
uint16_t handle_iter;
|
||||||
|
uint32_t err;
|
||||||
|
uint8_t ref;
|
||||||
|
|
||||||
|
cig = param;
|
||||||
|
leading_event_count = 0;
|
||||||
|
|
||||||
|
/* Check if stopping ticker (on disconnection, race with ticker expiry)
|
||||||
|
*/
|
||||||
|
if (unlikely(cig->lll.handle == 0xFFFF)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_iter = UINT16_MAX;
|
||||||
|
|
||||||
|
/* Increment CIS event counters */
|
||||||
|
for (int i = 0; i < cig->lll.num_cis; i++) {
|
||||||
|
cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter);
|
||||||
|
LL_ASSERT(cis);
|
||||||
|
|
||||||
|
/* New CIS may become available by creation prior to the CIG
|
||||||
|
* event in which it has event_count == 0. Don't increment
|
||||||
|
* event count until its handle is validated in
|
||||||
|
* ull_peripheral_iso_start, which means that its ACL instant
|
||||||
|
* has been reached, and offset calculated.
|
||||||
|
*/
|
||||||
|
if (cis->lll.handle != 0xFFFF) {
|
||||||
|
cis->lll.event_count++;
|
||||||
|
|
||||||
|
leading_event_count = MAX(leading_event_count,
|
||||||
|
cis->lll.event_count);
|
||||||
|
|
||||||
|
ull_iso_lll_event_prepare(cis->lll.handle, cis->lll.event_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Latch datapath validity entering event */
|
||||||
|
cis->lll.datapath_ready_rx = cis->hdr.datapath_out != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the CIG reference point for this event. Event 0 for the
|
||||||
|
* leading CIS in the CIG would have had it's reference point set in
|
||||||
|
* ull_peripheral_iso_start(). The reference point should only be
|
||||||
|
* updated from event 1 onwards. Although the cig reference point set
|
||||||
|
* this way is not accurate, it is the best possible until the anchor
|
||||||
|
* point for the leading CIS is available for this event.
|
||||||
|
*/
|
||||||
|
if (leading_event_count > 0) {
|
||||||
|
cig->cig_ref_point += (cig->iso_interval * CONN_INT_UNIT_US);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment prepare reference count */
|
||||||
|
ref = ull_ref_inc(&cig->ull);
|
||||||
|
LL_ASSERT(ref);
|
||||||
|
|
||||||
|
/* Append timing parameters */
|
||||||
|
p.ticks_at_expire = ticks_at_expire;
|
||||||
|
p.remainder = remainder;
|
||||||
|
p.lazy = lazy;
|
||||||
|
p.param = &cig->lll;
|
||||||
|
mfy.param = &p;
|
||||||
|
|
||||||
|
if (cig->sca_update) {
|
||||||
|
/* CIG/ACL affilaition established */
|
||||||
|
uint32_t iso_interval_us_frac =
|
||||||
|
EVENT_US_TO_US_FRAC(cig->iso_interval * CONN_INT_UNIT_US);
|
||||||
|
cig->lll.window_widening_periodic_us_frac =
|
||||||
|
ceiling_fraction(((lll_clock_ppm_local_get() +
|
||||||
|
lll_clock_ppm_get(cig->sca_update - 1)) *
|
||||||
|
iso_interval_us_frac),
|
||||||
|
1000000U);
|
||||||
|
iso_interval_us_frac -= cig->lll.window_widening_periodic_us_frac;
|
||||||
|
|
||||||
|
ull_peripheral_iso_update_ticker(cig, ticks_at_expire, iso_interval_us_frac);
|
||||||
|
cig->sca_update = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kick LLL prepare */
|
||||||
|
err = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, &mfy);
|
||||||
|
LL_ASSERT(!err);
|
||||||
|
|
||||||
|
/* Handle ISO Transmit Test for this CIG */
|
||||||
|
ull_conn_iso_transmit_test_cig_interval(cig->lll.handle, ticks_at_expire);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ticker_op_cb(uint32_t status, void *param)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(param);
|
||||||
|
|
||||||
|
LL_ASSERT(status == TICKER_STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ull_conn_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, uint16_t cis_handle)
|
||||||
|
{
|
||||||
|
struct ll_conn_iso_group *cig;
|
||||||
|
struct ll_conn_iso_stream *cis;
|
||||||
|
uint32_t acl_to_cig_ref_point;
|
||||||
|
uint32_t cis_offs_to_cig_ref;
|
||||||
|
uint32_t iso_interval_us_frac;
|
||||||
|
uint32_t ready_delay_us;
|
||||||
|
uint32_t ticker_status;
|
||||||
|
int32_t cig_offset_us;
|
||||||
|
uint8_t ticker_id;
|
||||||
|
|
||||||
|
cis = ll_conn_iso_stream_get(cis_handle);
|
||||||
|
cig = cis->group;
|
||||||
|
|
||||||
|
cis_offs_to_cig_ref = cig->sync_delay - cis->sync_delay;
|
||||||
|
|
||||||
|
cis->lll.offset = cis_offs_to_cig_ref;
|
||||||
|
cis->lll.handle = cis_handle;
|
||||||
|
|
||||||
|
/* Check if another CIS was already started and CIG ticker is
|
||||||
|
* running. If so, we just return with updated offset and
|
||||||
|
* validated handle.
|
||||||
|
*/
|
||||||
|
if (cig->started) {
|
||||||
|
/* We're done */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig);
|
||||||
|
|
||||||
|
/* Calculate interval in fractional microseconds for highest precision when
|
||||||
|
* accumulating the window widening window size. Ticker interval is set lopsided,
|
||||||
|
* with natural drift towards earlier timeout.
|
||||||
|
*/
|
||||||
|
iso_interval_us_frac = EVENT_US_TO_US_FRAC(cig->iso_interval * CONN_INT_UNIT_US) -
|
||||||
|
cig->lll.window_widening_periodic_us_frac;
|
||||||
|
|
||||||
|
/* Establish the CIG reference point by adjusting ACL-to-CIS offset
|
||||||
|
* (cis->offset) by the difference between CIG- and CIS sync delays.
|
||||||
|
*/
|
||||||
|
acl_to_cig_ref_point = cis->offset - cis_offs_to_cig_ref;
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_PHY)
|
||||||
|
ready_delay_us = lll_radio_rx_ready_delay_get(acl->lll.phy_rx, 1);
|
||||||
|
#else
|
||||||
|
ready_delay_us = lll_radio_rx_ready_delay_get(0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Calculate initial ticker offset - we're one ACL interval early */
|
||||||
|
cig_offset_us = acl_to_cig_ref_point;
|
||||||
|
cig_offset_us += (acl->lll.interval * CONN_INT_UNIT_US);
|
||||||
|
cig_offset_us -= EVENT_TICKER_RES_MARGIN_US;
|
||||||
|
cig_offset_us -= EVENT_JITTER_US;
|
||||||
|
cig_offset_us -= ready_delay_us;
|
||||||
|
|
||||||
|
/* Make sure we have time to service first subevent. TODO: Improve
|
||||||
|
* by skipping <n> interval(s) and incrementing event_count.
|
||||||
|
*/
|
||||||
|
LL_ASSERT(cig_offset_us > 0);
|
||||||
|
|
||||||
|
/* Calculate the CIG reference point of first CIG event. This
|
||||||
|
* calculation is inaccurate. However it is the best estimate available
|
||||||
|
* until the first anchor point for the leading CIS is available.
|
||||||
|
*/
|
||||||
|
cig->cig_ref_point = HAL_TICKER_TICKS_TO_US(ticks_at_expire);
|
||||||
|
cig->cig_ref_point += (acl->lll.interval * CONN_INT_UNIT_US);
|
||||||
|
cig->cig_ref_point += EVENT_OVERHEAD_START_US;
|
||||||
|
cig->cig_ref_point += acl_to_cig_ref_point;
|
||||||
|
|
||||||
|
/* Start CIS peripheral CIG ticker */
|
||||||
|
ticker_status = ticker_start(TICKER_INSTANCE_ID_CTLR,
|
||||||
|
TICKER_USER_ID_ULL_HIGH,
|
||||||
|
ticker_id,
|
||||||
|
ticks_at_expire,
|
||||||
|
HAL_TICKER_US_TO_TICKS(cig_offset_us),
|
||||||
|
EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac),
|
||||||
|
EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac),
|
||||||
|
TICKER_NULL_LAZY,
|
||||||
|
0,
|
||||||
|
ull_conn_iso_ticker_cb, cig,
|
||||||
|
ticker_op_cb, NULL);
|
||||||
|
|
||||||
|
LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
|
||||||
|
(ticker_status == TICKER_STATUS_BUSY));
|
||||||
|
|
||||||
|
cig->started = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void ticker_update_cig_op_cb(uint32_t status, void *param)
|
static void ticker_update_cig_op_cb(uint32_t status, void *param)
|
||||||
{
|
{
|
||||||
/* CIG drift compensation succeeds, or it fails in a race condition
|
/* CIG drift compensation succeeds, or it fails in a race condition
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_acl(struct ll_conn *conn,
|
||||||
struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_group(struct ll_conn_iso_group *cig,
|
struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_group(struct ll_conn_iso_group *cig,
|
||||||
uint16_t *handle_iter);
|
uint16_t *handle_iter);
|
||||||
|
|
||||||
|
void ull_conn_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, uint16_t cis_handle);
|
||||||
void ull_conn_iso_done(struct node_rx_event_done *done);
|
void ull_conn_iso_done(struct node_rx_event_done *done);
|
||||||
void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis);
|
void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis);
|
||||||
void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
||||||
|
@ -36,3 +37,7 @@ void ull_conn_iso_resume_ticker_start(struct lll_event *resume_event,
|
||||||
uint32_t resume_timeout);
|
uint32_t resume_timeout);
|
||||||
void ull_conn_iso_transmit_test_cig_interval(uint16_t handle,
|
void ull_conn_iso_transmit_test_cig_interval(uint16_t handle,
|
||||||
uint32_t ticks_at_expire);
|
uint32_t ticks_at_expire);
|
||||||
|
|
||||||
|
void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
|
||||||
|
uint32_t remainder, uint16_t lazy, uint8_t force,
|
||||||
|
void *param);
|
||||||
|
|
|
@ -437,8 +437,8 @@ static void rp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
|
||||||
if (is_instant_reached_or_passed(start_event_count,
|
if (is_instant_reached_or_passed(start_event_count,
|
||||||
cc_event_counter(conn))) {
|
cc_event_counter(conn))) {
|
||||||
/* Start CIS */
|
/* Start CIS */
|
||||||
ull_peripheral_iso_start(conn, conn->llcp.prep.ticks_at_expire,
|
ull_conn_iso_start(conn, conn->llcp.prep.ticks_at_expire,
|
||||||
ctx->data.cis_create.cis_handle);
|
ctx->data.cis_create.cis_handle);
|
||||||
|
|
||||||
/* Now we can wait for CIS to become established */
|
/* Now we can wait for CIS to become established */
|
||||||
ctx->state = RP_CC_STATE_WAIT_CIS_ESTABLISHED;
|
ctx->state = RP_CC_STATE_WAIT_CIS_ESTABLISHED;
|
||||||
|
@ -816,8 +816,8 @@ static void lp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
|
||||||
|
|
||||||
if (is_instant_reached_or_passed(ctx->data.cis_create.conn_event_count, event_counter)) {
|
if (is_instant_reached_or_passed(ctx->data.cis_create.conn_event_count, event_counter)) {
|
||||||
/* Start CIS */
|
/* Start CIS */
|
||||||
ull_central_iso_start(conn, conn->llcp.prep.ticks_at_expire,
|
ull_conn_iso_start(conn, conn->llcp.prep.ticks_at_expire,
|
||||||
ctx->data.cis_create.cis_handle);
|
ctx->data.cis_create.cis_handle);
|
||||||
|
|
||||||
/* Now we can wait for CIS to become established */
|
/* Now we can wait for CIS to become established */
|
||||||
ctx->state = LP_CC_STATE_WAIT_ESTABLISHED;
|
ctx->state = LP_CC_STATE_WAIT_ESTABLISHED;
|
||||||
|
|
|
@ -314,107 +314,6 @@ uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
|
|
||||||
uint32_t ticks_at_expire,
|
|
||||||
uint32_t iso_interval_us_frac);
|
|
||||||
|
|
||||||
static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
|
|
||||||
uint32_t remainder, uint16_t lazy, uint8_t force,
|
|
||||||
void *param)
|
|
||||||
{
|
|
||||||
static memq_link_t link;
|
|
||||||
static struct mayfly mfy = { 0, 0, &link, NULL,
|
|
||||||
lll_peripheral_iso_prepare };
|
|
||||||
static struct lll_prepare_param p;
|
|
||||||
struct ll_conn_iso_group *cig;
|
|
||||||
struct ll_conn_iso_stream *cis;
|
|
||||||
uint64_t leading_event_count;
|
|
||||||
uint16_t handle_iter;
|
|
||||||
uint32_t err;
|
|
||||||
uint8_t ref;
|
|
||||||
|
|
||||||
cig = param;
|
|
||||||
leading_event_count = 0;
|
|
||||||
|
|
||||||
/* Check if stopping ticker (on disconnection, race with ticker expiry)
|
|
||||||
*/
|
|
||||||
if (unlikely(cig->lll.handle == 0xFFFF)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_iter = UINT16_MAX;
|
|
||||||
|
|
||||||
/* Increment CIS event counters */
|
|
||||||
for (int i = 0; i < cig->lll.num_cis; i++) {
|
|
||||||
cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter);
|
|
||||||
LL_ASSERT(cis);
|
|
||||||
|
|
||||||
/* New CIS may become available by creation prior to the CIG
|
|
||||||
* event in which it has event_count == 0. Don't increment
|
|
||||||
* event count until its handle is validated in
|
|
||||||
* ull_peripheral_iso_start, which means that its ACL instant
|
|
||||||
* has been reached, and offset calculated.
|
|
||||||
*/
|
|
||||||
if (cis->lll.handle != 0xFFFF) {
|
|
||||||
cis->lll.event_count++;
|
|
||||||
|
|
||||||
|
|
||||||
leading_event_count = MAX(leading_event_count,
|
|
||||||
cis->lll.event_count);
|
|
||||||
|
|
||||||
ull_iso_lll_event_prepare(cis->lll.handle, cis->lll.event_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Latch datapath validity entering event */
|
|
||||||
cis->lll.datapath_ready_rx = cis->hdr.datapath_out != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the CIG reference point for this event. Event 0 for the
|
|
||||||
* leading CIS in the CIG would have had it's reference point set in
|
|
||||||
* ull_peripheral_iso_start(). The reference point should only be
|
|
||||||
* updated from event 1 onwards. Although the cig reference point set
|
|
||||||
* this way is not accurate, it is the best possible until the anchor
|
|
||||||
* point for the leading CIS is available for this event.
|
|
||||||
*/
|
|
||||||
if (leading_event_count > 0) {
|
|
||||||
cig->cig_ref_point += (cig->iso_interval * CONN_INT_UNIT_US);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment prepare reference count */
|
|
||||||
ref = ull_ref_inc(&cig->ull);
|
|
||||||
LL_ASSERT(ref);
|
|
||||||
|
|
||||||
/* Append timing parameters */
|
|
||||||
p.ticks_at_expire = ticks_at_expire;
|
|
||||||
p.remainder = remainder;
|
|
||||||
p.lazy = lazy;
|
|
||||||
p.param = &cig->lll;
|
|
||||||
mfy.param = &p;
|
|
||||||
|
|
||||||
if (cig->sca_update) {
|
|
||||||
/* CIG/ACL affilaition established */
|
|
||||||
uint32_t iso_interval_us_frac =
|
|
||||||
EVENT_US_TO_US_FRAC(cig->iso_interval * CONN_INT_UNIT_US);
|
|
||||||
|
|
||||||
cig->lll.window_widening_periodic_us_frac =
|
|
||||||
ceiling_fraction(((lll_clock_ppm_local_get() +
|
|
||||||
lll_clock_ppm_get(cig->sca_update - 1)) *
|
|
||||||
iso_interval_us_frac),
|
|
||||||
1000000U);
|
|
||||||
iso_interval_us_frac -= cig->lll.window_widening_periodic_us_frac;
|
|
||||||
|
|
||||||
ull_peripheral_iso_update_ticker(cig, ticks_at_expire, iso_interval_us_frac);
|
|
||||||
cig->sca_update = 0;
|
|
||||||
}
|
|
||||||
/* Kick LLL prepare */
|
|
||||||
err = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL,
|
|
||||||
0, &mfy);
|
|
||||||
LL_ASSERT(!err);
|
|
||||||
|
|
||||||
/* Handle ISO Transmit Test for this CIG */
|
|
||||||
ull_conn_iso_transmit_test_cig_interval(cig->lll.handle, ticks_at_expire);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ticker_op_cb(uint32_t status, void *param)
|
static void ticker_op_cb(uint32_t status, void *param)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(param);
|
ARG_UNUSED(param);
|
||||||
|
@ -422,9 +321,9 @@ static void ticker_op_cb(uint32_t status, void *param)
|
||||||
LL_ASSERT(status == TICKER_STATUS_SUCCESS);
|
LL_ASSERT(status == TICKER_STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
|
void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
|
||||||
uint32_t ticks_at_expire,
|
uint32_t ticks_at_expire,
|
||||||
uint32_t iso_interval_us_frac)
|
uint32_t iso_interval_us_frac)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* stop/start with new updated timings */
|
/* stop/start with new updated timings */
|
||||||
|
@ -443,7 +342,7 @@ static void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
|
||||||
EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac),
|
EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac),
|
||||||
TICKER_NULL_LAZY,
|
TICKER_NULL_LAZY,
|
||||||
0,
|
0,
|
||||||
ticker_cb, cig,
|
ull_conn_iso_ticker_cb, cig,
|
||||||
ticker_op_cb, NULL);
|
ticker_op_cb, NULL);
|
||||||
|
|
||||||
LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
|
LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
|
||||||
|
@ -451,95 +350,6 @@ static void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ull_peripheral_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire,
|
|
||||||
uint16_t cis_handle)
|
|
||||||
{
|
|
||||||
struct ll_conn_iso_group *cig;
|
|
||||||
struct ll_conn_iso_stream *cis;
|
|
||||||
uint32_t acl_to_cig_ref_point;
|
|
||||||
uint32_t cis_offs_to_cig_ref;
|
|
||||||
uint32_t iso_interval_us_frac;
|
|
||||||
uint32_t ready_delay_us;
|
|
||||||
uint32_t ticker_status;
|
|
||||||
int32_t cig_offset_us;
|
|
||||||
uint8_t ticker_id;
|
|
||||||
|
|
||||||
cis = ll_conn_iso_stream_get(cis_handle);
|
|
||||||
cig = cis->group;
|
|
||||||
|
|
||||||
cis_offs_to_cig_ref = cig->sync_delay - cis->sync_delay;
|
|
||||||
|
|
||||||
cis->lll.offset = cis_offs_to_cig_ref;
|
|
||||||
cis->lll.handle = cis_handle;
|
|
||||||
|
|
||||||
/* Check if another CIS was already started and CIG ticker is
|
|
||||||
* running. If so, we just return with updated offset and
|
|
||||||
* validated handle.
|
|
||||||
*/
|
|
||||||
if (cig->started) {
|
|
||||||
/* We're done */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig);
|
|
||||||
|
|
||||||
/* Calculate interval in fractional microseconds for highest precision when
|
|
||||||
* accumulating the window widening window size. Ticker interval is set lopsided,
|
|
||||||
* with natural drift towards earlier timeout.
|
|
||||||
*/
|
|
||||||
iso_interval_us_frac = EVENT_US_TO_US_FRAC(cig->iso_interval * CONN_INT_UNIT_US) -
|
|
||||||
cig->lll.window_widening_periodic_us_frac;
|
|
||||||
|
|
||||||
/* Establish the CIG reference point by adjusting ACL-to-CIS offset
|
|
||||||
* (cis->offset) by the difference between CIG- and CIS sync delays.
|
|
||||||
*/
|
|
||||||
acl_to_cig_ref_point = cis->offset - cis_offs_to_cig_ref;
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_PHY)
|
|
||||||
ready_delay_us = lll_radio_rx_ready_delay_get(acl->lll.phy_rx, 1);
|
|
||||||
#else
|
|
||||||
ready_delay_us = lll_radio_rx_ready_delay_get(0, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Calculate initial ticker offset - we're one ACL interval early */
|
|
||||||
cig_offset_us = acl_to_cig_ref_point;
|
|
||||||
cig_offset_us += (acl->lll.interval * CONN_INT_UNIT_US);
|
|
||||||
cig_offset_us -= EVENT_TICKER_RES_MARGIN_US;
|
|
||||||
cig_offset_us -= EVENT_JITTER_US;
|
|
||||||
cig_offset_us -= ready_delay_us;
|
|
||||||
|
|
||||||
/* Make sure we have time to service first subevent. TODO: Improve
|
|
||||||
* by skipping <n> interval(s) and incrementing event_count.
|
|
||||||
*/
|
|
||||||
LL_ASSERT(cig_offset_us > 0);
|
|
||||||
|
|
||||||
/* Calculate the CIG reference point of first CIG event. This
|
|
||||||
* calculation is inaccurate. However it is the best estimate available
|
|
||||||
* until the first anchor point for the leading CIS is available.
|
|
||||||
*/
|
|
||||||
cig->cig_ref_point = HAL_TICKER_TICKS_TO_US(ticks_at_expire);
|
|
||||||
cig->cig_ref_point += acl_to_cig_ref_point;
|
|
||||||
cig->cig_ref_point += (acl->lll.interval * CONN_INT_UNIT_US);
|
|
||||||
|
|
||||||
/* Start CIS peripheral CIG ticker */
|
|
||||||
ticker_status = ticker_start(TICKER_INSTANCE_ID_CTLR,
|
|
||||||
TICKER_USER_ID_ULL_HIGH,
|
|
||||||
ticker_id,
|
|
||||||
ticks_at_expire,
|
|
||||||
HAL_TICKER_US_TO_TICKS(cig_offset_us),
|
|
||||||
EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac),
|
|
||||||
EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac),
|
|
||||||
TICKER_NULL_LAZY,
|
|
||||||
0,
|
|
||||||
ticker_cb, cig,
|
|
||||||
ticker_op_cb, NULL);
|
|
||||||
|
|
||||||
LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
|
|
||||||
(ticker_status == TICKER_STATUS_BUSY));
|
|
||||||
|
|
||||||
cig->started = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl)
|
void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl)
|
||||||
{
|
{
|
||||||
uint8_t cig_handle;
|
uint8_t cig_handle;
|
||||||
|
|
|
@ -15,6 +15,7 @@ uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
|
||||||
uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind,
|
uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind,
|
||||||
uint8_t cig_id,
|
uint8_t cig_id,
|
||||||
uint16_t cis_handle);
|
uint16_t cis_handle);
|
||||||
void ull_peripheral_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire,
|
|
||||||
uint16_t cis_handle);
|
|
||||||
void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl);
|
void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl);
|
||||||
|
void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
|
||||||
|
uint32_t ticks_at_expire,
|
||||||
|
uint32_t iso_interval_us_frac);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue