Bluetooth: controller: Added Periodic Sync Terminate and Sync Lost
Added implementation to perform Periodic Sync Terminate, generation of Sync Lost on terminate and on remote device termination of Periodic Advertising. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
d1f4611ad8
commit
baef416d5d
11 changed files with 221 additions and 57 deletions
|
@ -2088,7 +2088,8 @@ static void le_per_adv_create_sync_cancel(struct net_buf *buf,
|
||||||
ccst->status = status;
|
ccst->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void le_per_adv_terminate_sync(struct net_buf *buf, struct net_buf **evt)
|
static void le_per_adv_terminate_sync(struct net_buf *buf, struct net_buf **evt,
|
||||||
|
void **node_rx)
|
||||||
{
|
{
|
||||||
struct bt_hci_cp_le_per_adv_terminate_sync *cmd = (void *)buf->data;
|
struct bt_hci_cp_le_per_adv_terminate_sync *cmd = (void *)buf->data;
|
||||||
struct bt_hci_evt_cc_status *ccst;
|
struct bt_hci_evt_cc_status *ccst;
|
||||||
|
@ -2097,7 +2098,7 @@ static void le_per_adv_terminate_sync(struct net_buf *buf, struct net_buf **evt)
|
||||||
|
|
||||||
handle = sys_le16_to_cpu(cmd->handle);
|
handle = sys_le16_to_cpu(cmd->handle);
|
||||||
|
|
||||||
status = ll_sync_terminate(handle);
|
status = ll_sync_terminate(handle, node_rx);
|
||||||
|
|
||||||
ccst = hci_cmd_complete(evt, sizeof(*ccst));
|
ccst = hci_cmd_complete(evt, sizeof(*ccst));
|
||||||
ccst->status = status;
|
ccst->status = status;
|
||||||
|
@ -2445,7 +2446,7 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BT_OCF(BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC):
|
case BT_OCF(BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC):
|
||||||
le_per_adv_terminate_sync(cmd, evt);
|
le_per_adv_terminate_sync(cmd, evt, node_rx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* FIXME: Enable when definition is added to hci.h */
|
/* FIXME: Enable when definition is added to hci.h */
|
||||||
|
@ -3841,6 +3842,21 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data,
|
||||||
sep->interval = sys_cpu_to_le16(se->interval);
|
sep->interval = sys_cpu_to_le16(se->interval);
|
||||||
sep->clock_accuracy = se->sca;
|
sep->clock_accuracy = se->sca;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void le_per_adv_sync_lost(struct pdu_data *pdu_data,
|
||||||
|
struct node_rx_pdu *node_rx,
|
||||||
|
struct net_buf *buf)
|
||||||
|
{
|
||||||
|
struct bt_hci_evt_le_per_adv_sync_lost *sep;
|
||||||
|
|
||||||
|
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) ||
|
||||||
|
!(le_event_mask & BT_EVT_MASK_LE_PER_ADV_SYNC_LOST)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sep = meta_evt(buf, BT_HCI_EVT_LE_PER_ADV_SYNC_LOST, sizeof(*sep));
|
||||||
|
sep->handle = sys_cpu_to_le16(node_rx->hdr.handle);
|
||||||
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
||||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||||
#endif /* CONFIG_BT_OBSERVER */
|
#endif /* CONFIG_BT_OBSERVER */
|
||||||
|
@ -3866,8 +3882,8 @@ static void le_adv_ext_terminate(struct pdu_data *pdu_data,
|
||||||
sep->num_completed_ext_adv_evts =
|
sep->num_completed_ext_adv_evts =
|
||||||
node_rx->hdr.rx_ftr.param_adv_term.num_events;
|
node_rx->hdr.rx_ftr.param_adv_term.num_events;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
|
||||||
#endif /* CONFIG_BT_BROADCASTER */
|
#endif /* CONFIG_BT_BROADCASTER */
|
||||||
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
|
#if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
|
||||||
static void le_scan_req_received(struct pdu_data *pdu_data,
|
static void le_scan_req_received(struct pdu_data *pdu_data,
|
||||||
|
@ -4201,6 +4217,9 @@ static void encode_control(struct node_rx_pdu *node_rx,
|
||||||
case NODE_RX_TYPE_SYNC:
|
case NODE_RX_TYPE_SYNC:
|
||||||
le_per_adv_sync_established(pdu_data, node_rx, buf);
|
le_per_adv_sync_established(pdu_data, node_rx, buf);
|
||||||
break;
|
break;
|
||||||
|
case NODE_RX_TYPE_SYNC_LOST:
|
||||||
|
le_per_adv_sync_lost(pdu_data, node_rx, buf);
|
||||||
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
||||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||||
#endif /* CONFIG_BT_OBSERVER */
|
#endif /* CONFIG_BT_OBSERVER */
|
||||||
|
@ -4641,6 +4660,7 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx)
|
||||||
#if defined(CONFIG_BT_CTLR_SCAN_PERIODIC)
|
#if defined(CONFIG_BT_CTLR_SCAN_PERIODIC)
|
||||||
__fallthrough;
|
__fallthrough;
|
||||||
case NODE_RX_TYPE_SYNC:
|
case NODE_RX_TYPE_SYNC:
|
||||||
|
case NODE_RX_TYPE_SYNC_LOST:
|
||||||
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_BROADCASTER)
|
#if defined(CONFIG_BT_BROADCASTER)
|
||||||
|
|
|
@ -102,7 +102,7 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
|
||||||
uint8_t *adv_addr, uint16_t skip,
|
uint8_t *adv_addr, uint16_t skip,
|
||||||
uint16_t sync_timeout, uint8_t sync_cte_type);
|
uint16_t sync_timeout, uint8_t sync_cte_type);
|
||||||
uint8_t ll_sync_create_cancel(void **rx);
|
uint8_t ll_sync_create_cancel(void **rx);
|
||||||
uint8_t ll_sync_terminate(uint16_t handle);
|
uint8_t ll_sync_terminate(uint16_t handle, void **rx);
|
||||||
uint8_t ll_sync_recv_enable(uint16_t handle, uint8_t enable);
|
uint8_t ll_sync_recv_enable(uint16_t handle, uint8_t enable);
|
||||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||||
uint8_t ll_scan_params_set(uint8_t type, uint16_t interval, uint16_t window,
|
uint8_t ll_scan_params_set(uint8_t type, uint16_t interval, uint16_t window,
|
||||||
|
|
|
@ -10,8 +10,8 @@ struct lll_sync {
|
||||||
uint8_t access_addr[4];
|
uint8_t access_addr[4];
|
||||||
uint8_t crc_init[3];
|
uint8_t crc_init[3];
|
||||||
|
|
||||||
uint16_t latency_prepare;
|
uint16_t skip_prepare;
|
||||||
uint16_t latency_event;
|
uint16_t skip_event;
|
||||||
uint16_t event_counter;
|
uint16_t event_counter;
|
||||||
|
|
||||||
uint8_t data_chan_map[5];
|
uint8_t data_chan_map[5];
|
||||||
|
|
|
@ -78,8 +78,8 @@ void lll_sync_prepare(void *param)
|
||||||
/* Instants elapsed */
|
/* Instants elapsed */
|
||||||
elapsed = p->lazy + 1;
|
elapsed = p->lazy + 1;
|
||||||
|
|
||||||
/* Save the (latency + 1) for use in event */
|
/* Save the (skip + 1) for use in event */
|
||||||
lll->latency_prepare += elapsed;
|
lll->skip_prepare += elapsed;
|
||||||
|
|
||||||
/* Accumulate window widening */
|
/* Accumulate window widening */
|
||||||
lll->window_widening_prepare_us += lll->window_widening_periodic_us *
|
lll->window_widening_prepare_us += lll->window_widening_periodic_us *
|
||||||
|
@ -115,17 +115,17 @@ static int prepare_cb(struct lll_prepare_param *p)
|
||||||
|
|
||||||
lll = p->param;
|
lll = p->param;
|
||||||
|
|
||||||
/* Deduce the latency */
|
/* Deduce the skip */
|
||||||
lll->latency_event = lll->latency_prepare - 1;
|
lll->skip_event = lll->skip_prepare - 1;
|
||||||
|
|
||||||
/* Calculate the current event counter value */
|
/* Calculate the current event counter value */
|
||||||
event_counter = lll->event_counter + lll->latency_event;
|
event_counter = lll->event_counter + lll->skip_event;
|
||||||
|
|
||||||
/* Update event counter to next value */
|
/* Update event counter to next value */
|
||||||
lll->event_counter = lll->event_counter + lll->latency_prepare;
|
lll->event_counter = lll->event_counter + lll->skip_prepare;
|
||||||
|
|
||||||
/* Reset accumulated latencies */
|
/* Reset accumulated latencies */
|
||||||
lll->latency_prepare = 0;
|
lll->skip_prepare = 0;
|
||||||
|
|
||||||
/* Current window widening */
|
/* Current window widening */
|
||||||
lll->window_widening_event_us += lll->window_widening_prepare_us;
|
lll->window_widening_event_us += lll->window_widening_prepare_us;
|
||||||
|
@ -242,6 +242,7 @@ static void isr_rx(void *param)
|
||||||
struct event_done_extra *e;
|
struct event_done_extra *e;
|
||||||
uint8_t rssi_ready;
|
uint8_t rssi_ready;
|
||||||
uint8_t trx_done;
|
uint8_t trx_done;
|
||||||
|
uint8_t trx_cnt;
|
||||||
uint8_t crc_ok;
|
uint8_t crc_ok;
|
||||||
|
|
||||||
/* Read radio status and events */
|
/* Read radio status and events */
|
||||||
|
@ -257,25 +258,29 @@ static void isr_rx(void *param)
|
||||||
lll_isr_rx_status_reset();
|
lll_isr_rx_status_reset();
|
||||||
|
|
||||||
/* No Rx */
|
/* No Rx */
|
||||||
|
trx_cnt = 0U;
|
||||||
if (!trx_done) {
|
if (!trx_done) {
|
||||||
/* TODO: Combine the early exit with above if-then-else block
|
/* TODO: Combine the early exit with above if-then-else block
|
||||||
*/
|
*/
|
||||||
goto isr_rx_exit;
|
goto isr_rx_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rx-ed */
|
||||||
|
trx_cnt = 1U;
|
||||||
|
|
||||||
|
/* Check CRC and generate Periodic Advertising Report */
|
||||||
if (crc_ok) {
|
if (crc_ok) {
|
||||||
/* TODO: */
|
/* TODO: */
|
||||||
printk("CRC OK\n");
|
printk("CRC OK\n");
|
||||||
} else {
|
|
||||||
printk("CRC BAD\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isr_rx_done:
|
||||||
/* Calculate and place the drift information in done event */
|
/* Calculate and place the drift information in done event */
|
||||||
e = ull_event_done_extra_get();
|
e = ull_event_done_extra_get();
|
||||||
LL_ASSERT(e);
|
LL_ASSERT(e);
|
||||||
|
|
||||||
e->type = EVENT_DONE_EXTRA_TYPE_SYNC;
|
e->type = EVENT_DONE_EXTRA_TYPE_SYNC;
|
||||||
e->trx_cnt = 1U;
|
e->trx_cnt = trx_cnt;
|
||||||
e->crc_valid = crc_ok;
|
e->crc_valid = crc_ok;
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_PHY)
|
#if defined(CONFIG_BT_CTLR_PHY)
|
||||||
|
@ -292,6 +297,5 @@ static void isr_rx(void *param)
|
||||||
lll->window_widening_event_us = 0U;
|
lll->window_widening_event_us = 0U;
|
||||||
lll->window_size_event_us = 0U;
|
lll->window_size_event_us = 0U;
|
||||||
|
|
||||||
isr_rx_exit:
|
|
||||||
lll_isr_cleanup(param);
|
lll_isr_cleanup(param);
|
||||||
}
|
}
|
||||||
|
|
|
@ -739,6 +739,7 @@ void ll_rx_dequeue(void)
|
||||||
#if defined(CONFIG_BT_CTLR_SCAN_PERIODIC)
|
#if defined(CONFIG_BT_CTLR_SCAN_PERIODIC)
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case NODE_RX_TYPE_SYNC:
|
case NODE_RX_TYPE_SYNC:
|
||||||
|
case NODE_RX_TYPE_SYNC_LOST:
|
||||||
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
||||||
#endif /* CONFIG_BT_OBSERVER */
|
#endif /* CONFIG_BT_OBSERVER */
|
||||||
|
|
||||||
|
@ -967,14 +968,17 @@ void ll_rx_mem_release(void **node_rx)
|
||||||
struct node_rx_sync *se =
|
struct node_rx_sync *se =
|
||||||
(void *)((struct node_rx_pdu *)rx_free)->pdu;
|
(void *)((struct node_rx_pdu *)rx_free)->pdu;
|
||||||
|
|
||||||
if (se->status) {
|
if (!se->status) {
|
||||||
ull_sync_release(rx_free->rx_ftr.param);
|
mem_release(rx_free, &mem_pdu_rx.free);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* Pass through */
|
||||||
|
|
||||||
ll_rx_link_inc_quota(1);
|
case NODE_RX_TYPE_SYNC_LOST:
|
||||||
mem_release(rx_free, &mem_pdu_rx.free);
|
{
|
||||||
|
ull_sync_release(rx_free->rx_ftr.param);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
#endif /* CONFIG_BT_CTLR_SCAN_PERIODIC */
|
||||||
|
|
|
@ -1156,7 +1156,7 @@ void ull_conn_done(struct node_rx_event_done *done)
|
||||||
conn->supervision_expire -= elapsed_event;
|
conn->supervision_expire -= elapsed_event;
|
||||||
|
|
||||||
/* break latency */
|
/* break latency */
|
||||||
lll->latency_event = 0;
|
lll->latency_event = 0U;
|
||||||
|
|
||||||
/* Force both master and slave when close to
|
/* Force both master and slave when close to
|
||||||
* supervision timeout.
|
* supervision timeout.
|
||||||
|
@ -1175,7 +1175,7 @@ void ull_conn_done(struct node_rx_event_done *done)
|
||||||
force = conn->slave.force & 0x01;
|
force = conn->slave.force & 0x01;
|
||||||
|
|
||||||
/* rotate force bits */
|
/* rotate force bits */
|
||||||
conn->slave.force >>= 1;
|
conn->slave.force >>= 1U;
|
||||||
if (force) {
|
if (force) {
|
||||||
conn->slave.force |= BIT(31);
|
conn->slave.force |= BIT(31);
|
||||||
}
|
}
|
||||||
|
@ -1242,7 +1242,7 @@ void ull_conn_done(struct node_rx_event_done *done)
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_CONN_RSSI_EVENT)
|
#if defined(CONFIG_BT_CTLR_CONN_RSSI_EVENT)
|
||||||
/* generate RSSI event */
|
/* generate RSSI event */
|
||||||
if (lll->rssi_sample_count == 0) {
|
if (lll->rssi_sample_count == 0U) {
|
||||||
struct node_rx_pdu *rx;
|
struct node_rx_pdu *rx;
|
||||||
struct pdu_data *pdu_data_rx;
|
struct pdu_data *pdu_data_rx;
|
||||||
|
|
||||||
|
@ -1271,13 +1271,13 @@ void ull_conn_done(struct node_rx_event_done *done)
|
||||||
((conn->llcp_type == LLCP_CONN_UPD) ||
|
((conn->llcp_type == LLCP_CONN_UPD) ||
|
||||||
(conn->llcp_type == LLCP_CHAN_MAP))) ||
|
(conn->llcp_type == LLCP_CHAN_MAP))) ||
|
||||||
(conn->llcp_cu.req != conn->llcp_cu.ack)) {
|
(conn->llcp_cu.req != conn->llcp_cu.ack)) {
|
||||||
lll->latency_event = 0;
|
lll->latency_event = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if latency needs update */
|
/* check if latency needs update */
|
||||||
lazy = 0U;
|
lazy = 0U;
|
||||||
if ((force) || (latency_event != lll->latency_event)) {
|
if ((force) || (latency_event != lll->latency_event)) {
|
||||||
lazy = lll->latency_event + 1;
|
lazy = lll->latency_event + 1U;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update conn ticker */
|
/* update conn ticker */
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Macro to convert time in us to connection interval units */
|
|
||||||
#define RADIO_CONN_EVENTS(x, y) ((uint16_t)(((x) + (y) - 1) / (y)))
|
|
||||||
|
|
||||||
struct ll_conn *ll_conn_acquire(void);
|
struct ll_conn *ll_conn_acquire(void);
|
||||||
void ll_conn_release(struct ll_conn *conn);
|
void ll_conn_release(struct ll_conn *conn);
|
||||||
uint16_t ll_conn_handle_get(struct ll_conn *conn);
|
uint16_t ll_conn_handle_get(struct ll_conn *conn);
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Macro to convert time in us to connection interval units */
|
||||||
|
#define RADIO_CONN_EVENTS(x, y) ((uint16_t)(((x) + (y) - 1) / (y)))
|
||||||
|
|
||||||
|
/* Macro to convert time in us to periodic advertising interval units */
|
||||||
|
#define RADIO_SYNC_EVENTS(x, y) ((uint16_t)(((x) + (y) - 1) / (y)))
|
||||||
|
|
||||||
static inline uint8_t ull_ref_get(struct ull_hdr *hdr)
|
static inline uint8_t ull_ref_get(struct ull_hdr *hdr)
|
||||||
{
|
{
|
||||||
return hdr->ref;
|
return hdr->ref;
|
||||||
|
|
|
@ -23,10 +23,6 @@ struct ll_scan_set {
|
||||||
uint8_t adv_addr[BDADDR_SIZE];
|
uint8_t adv_addr[BDADDR_SIZE];
|
||||||
|
|
||||||
struct node_rx_hdr *node_rx_estab;
|
struct node_rx_hdr *node_rx_estab;
|
||||||
struct {
|
|
||||||
struct node_rx_hdr node_rx_lost;
|
|
||||||
uint8_t status;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ll_sync_set *sync;
|
struct ll_sync_set *sync;
|
||||||
} per_scan;
|
} per_scan;
|
||||||
|
|
|
@ -43,10 +43,13 @@
|
||||||
static int init_reset(void);
|
static int init_reset(void);
|
||||||
static inline struct ll_sync_set *sync_acquire(void);
|
static inline struct ll_sync_set *sync_acquire(void);
|
||||||
static struct ll_sync_set *is_enabled_get(uint16_t handle);
|
static struct ll_sync_set *is_enabled_get(uint16_t handle);
|
||||||
|
static void timeout_cleanup(struct ll_sync_set *sync);
|
||||||
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
|
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
|
||||||
uint16_t lazy, void *param);
|
uint16_t lazy, void *param);
|
||||||
static void ticker_op_cb(uint32_t status, void *param);
|
static void ticker_op_cb(uint32_t status, void *param);
|
||||||
static void ticker_update_sync_op_cb(uint32_t status, void *param);
|
static void ticker_update_sync_op_cb(uint32_t status, void *param);
|
||||||
|
static void ticker_stop_op_cb(uint32_t status, void *param);
|
||||||
|
static void sync_lost(void *param);
|
||||||
|
|
||||||
static struct ll_sync_set ll_sync_pool[CONFIG_BT_CTLR_SCAN_SYNC_SET];
|
static struct ll_sync_set ll_sync_pool[CONFIG_BT_CTLR_SCAN_SYNC_SET];
|
||||||
static void *sync_free;
|
static void *sync_free;
|
||||||
|
@ -104,8 +107,6 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
|
||||||
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync->is_enabled = 0U;
|
|
||||||
|
|
||||||
scan->per_scan.filter_policy = options & BIT(0);
|
scan->per_scan.filter_policy = options & BIT(0);
|
||||||
if (!scan->per_scan.filter_policy) {
|
if (!scan->per_scan.filter_policy) {
|
||||||
scan->per_scan.sid = sid;
|
scan->per_scan.sid = sid;
|
||||||
|
@ -113,16 +114,17 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
|
||||||
memcpy(scan->per_scan.adv_addr, adv_addr, BDADDR_SIZE);
|
memcpy(scan->per_scan.adv_addr, adv_addr, BDADDR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Support for skip */
|
sync->skip = skip;
|
||||||
|
sync->timeout = sync_timeout;
|
||||||
/* TODO: Support for timeout */
|
|
||||||
|
|
||||||
/* TODO: Support for CTE type */
|
/* TODO: Support for CTE type */
|
||||||
|
|
||||||
/* Initialize sync context */
|
/* Initialize sync context */
|
||||||
|
sync->timeout_reload = 0U;
|
||||||
|
sync->timeout_expire = 0U;
|
||||||
lll_sync = &sync->lll;
|
lll_sync = &sync->lll;
|
||||||
lll_sync->latency_prepare = 0U;
|
lll_sync->skip_prepare = 0U;
|
||||||
lll_sync->latency_event = 0U;
|
lll_sync->skip_event = 0U;
|
||||||
lll_sync->data_chan_id = 0U;
|
lll_sync->data_chan_id = 0U;
|
||||||
lll_sync->window_widening_prepare_us = 0U;
|
lll_sync->window_widening_prepare_us = 0U;
|
||||||
lll_sync->window_widening_event_us = 0U;
|
lll_sync->window_widening_event_us = 0U;
|
||||||
|
@ -136,7 +138,7 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
|
||||||
/* established and sync_lost node_rx */
|
/* established and sync_lost node_rx */
|
||||||
node_rx->link = link_sync_estab;
|
node_rx->link = link_sync_estab;
|
||||||
scan->per_scan.node_rx_estab = node_rx;
|
scan->per_scan.node_rx_estab = node_rx;
|
||||||
scan->per_scan.node_rx_lost.link = link_sync_lost;
|
sync->node_rx_lost.link = link_sync_lost;
|
||||||
|
|
||||||
/* Initialise ULL and LLL headers */
|
/* Initialise ULL and LLL headers */
|
||||||
ull_hdr_init(&sync->ull);
|
ull_hdr_init(&sync->ull);
|
||||||
|
@ -182,19 +184,19 @@ uint8_t ll_sync_create_cancel(void **rx)
|
||||||
/* Check for race condition where in sync is established when sync
|
/* Check for race condition where in sync is established when sync
|
||||||
* context was set to NULL.
|
* context was set to NULL.
|
||||||
*/
|
*/
|
||||||
if (sync->is_enabled) {
|
if (sync->timeout_reload) {
|
||||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_rx = (void *)scan->per_scan.node_rx_estab;
|
node_rx = (void *)scan->per_scan.node_rx_estab;
|
||||||
link_sync_estab = node_rx->hdr.link;
|
link_sync_estab = node_rx->hdr.link;
|
||||||
link_sync_lost = scan->per_scan.node_rx_lost.link;
|
link_sync_lost = sync->node_rx_lost.link;
|
||||||
|
|
||||||
ll_rx_link_release(link_sync_lost);
|
ll_rx_link_release(link_sync_lost);
|
||||||
ll_rx_link_release(link_sync_estab);
|
ll_rx_link_release(link_sync_estab);
|
||||||
ll_rx_release(node_rx);
|
ll_rx_release(node_rx);
|
||||||
|
|
||||||
node_rx = (void *)&scan->per_scan.node_rx_lost;
|
node_rx = (void *)&sync->node_rx_lost;
|
||||||
node_rx->hdr.type = NODE_RX_TYPE_SYNC;
|
node_rx->hdr.type = NODE_RX_TYPE_SYNC;
|
||||||
node_rx->hdr.handle = 0xffff;
|
node_rx->hdr.handle = 0xffff;
|
||||||
node_rx->hdr.rx_ftr.param = sync;
|
node_rx->hdr.rx_ftr.param = sync;
|
||||||
|
@ -206,16 +208,47 @@ uint8_t ll_sync_create_cancel(void **rx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ll_sync_terminate(uint16_t handle)
|
uint8_t ll_sync_terminate(uint16_t handle, void **rx)
|
||||||
{
|
{
|
||||||
|
struct node_rx_pdu *node_rx;
|
||||||
|
memq_link_t *link_sync_lost;
|
||||||
struct ll_sync_set *sync;
|
struct ll_sync_set *sync;
|
||||||
|
uint32_t volatile ret_cb;
|
||||||
|
uint32_t ret;
|
||||||
|
void *mark;
|
||||||
|
|
||||||
sync = is_enabled_get(handle);
|
sync = is_enabled_get(handle);
|
||||||
if (!sync) {
|
if (!sync) {
|
||||||
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark = ull_disable_mark(sync);
|
||||||
|
LL_ASSERT(mark == sync);
|
||||||
|
|
||||||
|
ret_cb = TICKER_STATUS_BUSY;
|
||||||
|
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
|
||||||
|
TICKER_ID_SCAN_SYNC_BASE + handle,
|
||||||
|
ull_ticker_status_give, (void *)&ret_cb);
|
||||||
|
ret = ull_ticker_status_take(ret, &ret_cb);
|
||||||
|
if (ret) {
|
||||||
|
mark = ull_disable_mark(sync);
|
||||||
|
LL_ASSERT(mark == sync);
|
||||||
|
|
||||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Stop periodic sync events */
|
mark = ull_disable_unmark(sync);
|
||||||
|
LL_ASSERT(mark == sync);
|
||||||
|
|
||||||
|
link_sync_lost = sync->node_rx_lost.link;
|
||||||
|
ll_rx_link_release(link_sync_lost);
|
||||||
|
|
||||||
|
node_rx = (void *)&sync->node_rx_lost;
|
||||||
|
node_rx->hdr.type = NODE_RX_TYPE_SYNC_LOST;
|
||||||
|
node_rx->hdr.handle = handle;
|
||||||
|
node_rx->hdr.rx_ftr.param = sync;
|
||||||
|
|
||||||
|
*rx = node_rx;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -296,8 +329,6 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
|
||||||
sync = scan->per_scan.sync;
|
sync = scan->per_scan.sync;
|
||||||
scan->per_scan.sync = NULL;
|
scan->per_scan.sync = NULL;
|
||||||
|
|
||||||
sync->is_enabled = 1U;
|
|
||||||
|
|
||||||
lll = &sync->lll;
|
lll = &sync->lll;
|
||||||
memcpy(lll->data_chan_map, si->sca_chm, sizeof(lll->data_chan_map));
|
memcpy(lll->data_chan_map, si->sca_chm, sizeof(lll->data_chan_map));
|
||||||
lll->data_chan_map[4] &= ~0xE0;
|
lll->data_chan_map[4] &= ~0xE0;
|
||||||
|
@ -316,6 +347,9 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
|
||||||
interval = sys_le16_to_cpu(si->interval);
|
interval = sys_le16_to_cpu(si->interval);
|
||||||
interval_us = interval * 1250U;
|
interval_us = interval * 1250U;
|
||||||
|
|
||||||
|
sync->timeout_reload = RADIO_SYNC_EVENTS((sync->timeout * 10U * 1000U),
|
||||||
|
interval_us);
|
||||||
|
|
||||||
lll->window_widening_periodic_us =
|
lll->window_widening_periodic_us =
|
||||||
(((lll_clock_ppm_local_get() + lll_clock_ppm_get(sca)) *
|
(((lll_clock_ppm_local_get() + lll_clock_ppm_get(sca)) *
|
||||||
interval_us) + (1000000 - 1)) / 1000000U;
|
interval_us) + (1000000 - 1)) / 1000000U;
|
||||||
|
@ -393,17 +427,72 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
|
||||||
void ull_sync_done(struct node_rx_event_done *done)
|
void ull_sync_done(struct node_rx_event_done *done)
|
||||||
{
|
{
|
||||||
struct lll_sync *lll = (void *)HDR_ULL2LLL(done->param);
|
struct lll_sync *lll = (void *)HDR_ULL2LLL(done->param);
|
||||||
|
struct ll_sync_set *sync = (void *)HDR_LLL2EVT(lll);
|
||||||
uint32_t ticks_drift_minus;
|
uint32_t ticks_drift_minus;
|
||||||
uint32_t ticks_drift_plus;
|
uint32_t ticks_drift_plus;
|
||||||
uint16_t lazy = 0U;
|
uint16_t elapsed_event;
|
||||||
uint8_t force = 0U;
|
uint16_t skip_event;
|
||||||
|
uint16_t lazy;
|
||||||
|
uint8_t force;
|
||||||
|
|
||||||
/* TODO: use skip value and decide on the laziness using latency_event.
|
/* Events elapsed used in timeout checks below */
|
||||||
|
skip_event = lll->skip_event;
|
||||||
|
elapsed_event = skip_event + 1;
|
||||||
|
|
||||||
|
/* Sync drift compensation and new skip calculation
|
||||||
*/
|
*/
|
||||||
|
ticks_drift_plus = 0U;
|
||||||
|
ticks_drift_minus = 0U;
|
||||||
|
if (done->extra.trx_cnt) {
|
||||||
|
/* Calculate drift in ticks unit */
|
||||||
|
ull_drift_ticks_get(done, &ticks_drift_plus,
|
||||||
|
&ticks_drift_minus);
|
||||||
|
|
||||||
ull_drift_ticks_get(done, &ticks_drift_plus, &ticks_drift_minus);
|
/* Enforce skip */
|
||||||
|
lll->skip_event = sync->skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset supervision countdown */
|
||||||
|
if (done->extra.crc_valid) {
|
||||||
|
sync->timeout_expire = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if anchor point not sync-ed, start timeout countdown, and break
|
||||||
|
* skip if any.
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
if (!sync->timeout_expire) {
|
||||||
|
sync->timeout_expire = sync->timeout_reload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check timeout */
|
||||||
|
force = 0U;
|
||||||
|
if (sync->timeout_expire) {
|
||||||
|
if (sync->timeout_expire > elapsed_event) {
|
||||||
|
sync->timeout_expire -= elapsed_event;
|
||||||
|
|
||||||
|
/* break skip */
|
||||||
|
lll->skip_event = 0U;
|
||||||
|
|
||||||
|
if (skip_event) {
|
||||||
|
force = 1U;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeout_cleanup(sync);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if skip needs update */
|
||||||
|
lazy = 0U;
|
||||||
|
if ((force) || (skip_event != lll->skip_event)) {
|
||||||
|
lazy = lll->skip_event + 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update Sync ticker instance */
|
||||||
if (ticks_drift_plus || ticks_drift_minus || lazy || force) {
|
if (ticks_drift_plus || ticks_drift_minus || lazy || force) {
|
||||||
struct ll_sync_set *sync = (void *)HDR_LLL2EVT(lll);
|
|
||||||
uint16_t sync_handle = ull_sync_handle_get(sync);
|
uint16_t sync_handle = ull_sync_handle_get(sync);
|
||||||
uint32_t ticker_status;
|
uint32_t ticker_status;
|
||||||
|
|
||||||
|
@ -447,13 +536,26 @@ static struct ll_sync_set *is_enabled_get(uint16_t handle)
|
||||||
struct ll_sync_set *sync;
|
struct ll_sync_set *sync;
|
||||||
|
|
||||||
sync = ull_sync_set_get(handle);
|
sync = ull_sync_set_get(handle);
|
||||||
if (!sync || !sync->is_enabled) {
|
if (!sync || !sync->timeout_reload) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sync;
|
return sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void timeout_cleanup(struct ll_sync_set *sync)
|
||||||
|
{
|
||||||
|
uint16_t sync_handle = ull_sync_handle_get(sync);
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
|
/* Stop Periodic Sync Ticker */
|
||||||
|
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH,
|
||||||
|
TICKER_ID_SCAN_SYNC_BASE + sync_handle,
|
||||||
|
ticker_stop_op_cb, (void *)sync);
|
||||||
|
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
|
||||||
|
(ret == TICKER_STATUS_BUSY));
|
||||||
|
}
|
||||||
|
|
||||||
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
|
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
|
||||||
uint16_t lazy, void *param)
|
uint16_t lazy, void *param)
|
||||||
{
|
{
|
||||||
|
@ -501,3 +603,33 @@ static void ticker_update_sync_op_cb(uint32_t status, void *param)
|
||||||
param == ull_update_mark_get() ||
|
param == ull_update_mark_get() ||
|
||||||
param == ull_disable_mark_get());
|
param == ull_disable_mark_get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ticker_stop_op_cb(uint32_t status, void *param)
|
||||||
|
{
|
||||||
|
uint32_t retval;
|
||||||
|
static memq_link_t link;
|
||||||
|
static struct mayfly mfy = {0, 0, &link, NULL, sync_lost};
|
||||||
|
|
||||||
|
LL_ASSERT(status == TICKER_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
mfy.param = param;
|
||||||
|
|
||||||
|
retval = mayfly_enqueue(TICKER_USER_ID_ULL_LOW, TICKER_USER_ID_ULL_HIGH,
|
||||||
|
0, &mfy);
|
||||||
|
LL_ASSERT(!retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sync_lost(void *param)
|
||||||
|
{
|
||||||
|
struct ll_sync_set *sync = param;
|
||||||
|
struct node_rx_pdu *rx;
|
||||||
|
|
||||||
|
/* Generate Periodic advertising sync lost */
|
||||||
|
rx = (void *)&sync->node_rx_lost;
|
||||||
|
rx->hdr.handle = ull_sync_handle_get(sync);
|
||||||
|
rx->hdr.type = NODE_RX_TYPE_SYNC_LOST;
|
||||||
|
|
||||||
|
/* Enqueue the sync lost towards ULL context */
|
||||||
|
ll_rx_put(rx->hdr.link, rx);
|
||||||
|
ll_rx_sched();
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,12 @@ struct ll_sync_set {
|
||||||
struct ull_hdr ull;
|
struct ull_hdr ull;
|
||||||
struct lll_sync lll;
|
struct lll_sync lll;
|
||||||
|
|
||||||
uint8_t is_enabled:1;
|
uint16_t skip;
|
||||||
|
uint16_t timeout;
|
||||||
|
uint16_t timeout_reload;
|
||||||
|
uint16_t timeout_expire;
|
||||||
|
|
||||||
|
struct node_rx_hdr node_rx_lost;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct node_rx_sync {
|
struct node_rx_sync {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue