nimble/ll: Refactor periodic sync synchronization

This is a preparation for adding transfer sync support which is
independent of synchronization procesure. This also fixes
HCI/CCO/BV-17-C qualification test case.

This includes:
 - adding separate periodic device list
 - SM struct is only used for synchronized syncs
This commit is contained in:
Szymon Janc
2019-12-03 23:37:08 +01:00
parent 3a2f0dab95
commit 914e044327
4 changed files with 284 additions and 264 deletions
@@ -56,6 +56,7 @@ uint32_t ble_ll_sync_get_event_end_time(void);
bool ble_ll_sync_enabled(void);
void ble_ll_sync_reset(void);
void ble_ll_sync_init(void);
#ifdef __cplusplus
}
+1
View File
@@ -1651,6 +1651,7 @@ ble_ll_init(void)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
features |= BLE_LL_FEAT_PERIODIC_ADV;
ble_ll_sync_init();
#endif
/* Initialize random number generation */
+277 -264
View File
@@ -45,15 +45,15 @@
#define BLE_LL_SYNC_ESTABLISH_CNT 6
#define BLE_LL_SYNC_CNT MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT)
#define BLE_LL_SYNC_LIST_CNT MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT)
#define BLE_LL_SYNC_SM_FLAG_ON_LIST 0x01
#define BLE_LL_SYNC_SM_FLAG_PENDING 0x02
#define BLE_LL_SYNC_SM_FLAG_ESTABLISHING 0x04
#define BLE_LL_SYNC_SM_FLAG_ESTABLISHED 0x08
#define BLE_LL_SYNC_SM_FLAG_SET_ANCHOR 0x10
#define BLE_LL_SYNC_SM_FLAG_OFFSET_300 0x20
#define BLE_LL_SYNC_SM_FLAG_SYNC_INFO 0x40
#define BLE_LL_SYNC_SM_FLAG_DISABLED 0x80
#define BLE_LL_SYNC_SM_FLAG_RESERVED 0x01
#define BLE_LL_SYNC_SM_FLAG_ESTABLISHING 0x02
#define BLE_LL_SYNC_SM_FLAG_ESTABLISHED 0x04
#define BLE_LL_SYNC_SM_FLAG_SET_ANCHOR 0x08
#define BLE_LL_SYNC_SM_FLAG_OFFSET_300 0x10
#define BLE_LL_SYNC_SM_FLAG_SYNC_INFO 0x20
#define BLE_LL_SYNC_SM_FLAG_DISABLED 0x40
#define BLE_LL_SYNC_CHMAP_LEN 5
#define BLE_LL_SYNC_ITVL_USECS 1250
@@ -74,6 +74,8 @@ struct ble_ll_sync_sm {
uint8_t phy_mode;
uint8_t sync_pending_cnt;
uint32_t timeout;
uint16_t skip;
@@ -100,11 +102,65 @@ struct ble_ll_sync_sm {
static struct ble_ll_sync_sm g_ble_ll_sync_sm[BLE_LL_SYNC_CNT];
static unsigned int g_ble_ll_sync_pending;
static struct {
uint8_t adv_sid;
uint8_t adv_addr[BLE_DEV_ADDR_LEN];
uint8_t adv_addr_type;
} g_ble_ll_sync_adv_list[BLE_LL_SYNC_LIST_CNT];
static struct {
uint32_t timeout;
uint16_t max_skip;
uint16_t options;
} g_ble_ll_sync_create_params;
/* if this is set HCI LE Sync Create is pending */
static uint8_t *g_ble_ll_sync_create_comp_ev;
static struct ble_ll_sync_sm *g_ble_ll_sync_sm_establishing;
static struct ble_ll_sync_sm *g_ble_ll_sync_sm_current;
static uint8_t *g_ble_ll_sync_comp_ev;
static int
ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
{
int i;
for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
if ((g_ble_ll_sync_adv_list[i].adv_sid == sid) &&
(g_ble_ll_sync_adv_list[i].adv_addr_type == addr_type) &&
!memcmp(g_ble_ll_sync_adv_list[i].adv_addr, addr, BLE_DEV_ADDR_LEN)) {
return i;
}
}
return -1;
}
static int
ble_ll_sync_list_get_free(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
if (g_ble_ll_sync_adv_list[i].adv_sid == 0xff) {
return i;
}
}
return -1;
}
static bool
ble_ll_sync_list_empty(void) {
int i;
for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
if (g_ble_ll_sync_adv_list[i].adv_sid != 0xff) {
return false;
}
}
return true;
}
static uint8_t
ble_ll_sync_get_handle(struct ble_ll_sync_sm *sm)
@@ -126,6 +182,20 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm)
ble_hci_trans_buf_free(sm->next_report);
}
if (g_ble_ll_sync_sm_current == sm) {
ble_phy_disable();
ble_ll_wfr_disable();
ble_ll_state_set(BLE_LL_STATE_STANDBY);
g_ble_ll_sync_sm_current = NULL;
ble_ll_scan_chk_resume();
}
#ifdef BLE_XCVR_RFCLK
ble_ll_sched_rfclk_chk_restart();
#endif
BLE_LL_ASSERT(sm->sync_ev_end.ev.ev_queued == 0);
BLE_LL_ASSERT(sm->sch.enqueued == 0);
memset(sm, 0, sizeof(*sm));
}
@@ -160,10 +230,10 @@ ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm)
struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev;
struct ble_hci_ev *hci_ev;
BLE_LL_ASSERT(g_ble_ll_sync_comp_ev);
BLE_LL_ASSERT(g_ble_ll_sync_create_comp_ev);
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB)) {
hci_ev = (void *) g_ble_ll_sync_comp_ev;
hci_ev = (void *) g_ble_ll_sync_create_comp_ev;
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
@@ -181,10 +251,10 @@ ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm)
ble_ll_hci_event_send(hci_ev);
} else {
ble_hci_trans_buf_free(g_ble_ll_sync_comp_ev);
ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
}
g_ble_ll_sync_comp_ev = NULL;
g_ble_ll_sync_create_comp_ev = NULL;
}
static void
@@ -193,10 +263,10 @@ ble_ll_sync_est_event_failed(uint8_t status)
struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev;
struct ble_hci_ev *hci_ev;
BLE_LL_ASSERT(g_ble_ll_sync_comp_ev);
BLE_LL_ASSERT(g_ble_ll_sync_create_comp_ev);
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB)) {
hci_ev = (void *) g_ble_ll_sync_comp_ev;
hci_ev = (void *) g_ble_ll_sync_create_comp_ev;
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
@@ -209,10 +279,10 @@ ble_ll_sync_est_event_failed(uint8_t status)
ble_ll_hci_event_send(hci_ev);
} else {
ble_hci_trans_buf_free(g_ble_ll_sync_comp_ev);
ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
}
g_ble_ll_sync_comp_ev = NULL;
g_ble_ll_sync_create_comp_ev = NULL;
}
static void
@@ -234,8 +304,6 @@ ble_ll_sync_lost_event(struct ble_ll_sync_sm *sm)
ble_ll_hci_event_send(hci_ev);
}
}
ble_ll_sync_sm_clear(sm);
}
static struct ble_ll_sync_sm *
@@ -259,31 +327,6 @@ ble_ll_sync_find(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
return NULL;
}
static struct ble_ll_sync_sm *
ble_ll_sync_get(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
{
struct ble_ll_sync_sm *sm;
int i;
sm = ble_ll_sync_find(addr, addr_type, sid);
if (sm) {
return sm;
}
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
sm = &g_ble_ll_sync_sm[i];
if (!sm->flags) {
sm->adv_sid = sid;
sm->adv_addr_type = addr_type;
memcpy(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN);
return sm;
}
}
return NULL;
}
static void
ble_ll_sync_current_sm_over(void)
{
@@ -310,9 +353,10 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch)
/* Set current connection state machine */
sm = sch->cb_arg;
g_ble_ll_sync_sm_current = sm;
BLE_LL_ASSERT(sm);
g_ble_ll_sync_sm_current = sm;
/* Disable whitelisting */
ble_ll_whitelist_disable();
@@ -378,30 +422,16 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch)
int
ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr)
{
struct ble_ll_sync_sm *sm = g_ble_ll_sync_sm_current;
BLE_LL_ASSERT(g_ble_ll_sync_sm_current);
/* this also handles chains as those have same PDU type */
if (pdu_type != BLE_ADV_PDU_TYPE_AUX_SYNC_IND) {
ble_ll_event_send(&sm->sync_ev_end);
ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end);
ble_ll_sync_current_sm_over();
STATS_INC(ble_ll_stats, sched_invalid_pdu);
return -1;
}
/* Set anchor point (and last) if 1st rxd frame in sync event.
* According to spec this should be done even if CRC is not valid so we
* can store it here
*/
if (sm->flags & BLE_LL_SYNC_SM_FLAG_SET_ANCHOR) {
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR;
sm->anchor_point = rxhdr->beg_cputime;
sm->anchor_point_usecs = rxhdr->rem_usecs;
sm->last_anchor_point = sm->anchor_point;
}
STATS_INC(ble_ll_stats, sync_received);
return 0;
}
@@ -631,13 +661,10 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu,
int
ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
{
struct ble_ll_sync_sm *sm = g_ble_ll_sync_sm_current;
struct ble_mbuf_hdr *ble_hdr;
struct os_mbuf *rxpdu;
BLE_LL_ASSERT(sm);
ble_ll_sync_current_sm_over();
BLE_LL_ASSERT(g_ble_ll_sync_sm_current);
/* type was verified in isr_start */
@@ -646,14 +673,16 @@ ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
ble_phy_rxpdu_copy(rxbuf, rxpdu);
ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
ble_hdr->rxinfo.user_data = sm;
ble_hdr->rxinfo.user_data = g_ble_ll_sync_sm_current;
ble_ll_rx_pdu_in(rxpdu);
} else {
STATS_INC(ble_ll_stats, sync_rx_buf_err);
ble_ll_event_send(&sm->sync_ev_end);
ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end);
}
ble_ll_sync_current_sm_over();
return -1;
}
@@ -843,49 +872,29 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr,
static void
ble_ll_sync_established(struct ble_ll_sync_sm *sm)
{
int i;
BLE_LL_ASSERT(sm == g_ble_ll_sync_sm_establishing);
BLE_LL_ASSERT(g_ble_ll_sync_pending);
BLE_LL_ASSERT(sm->sync_pending_cnt);
/* mark as established */
ble_ll_sync_est_event_success(sm);
sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHED;
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
/* clear as we are not longer pending sync here */
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
g_ble_ll_sync_sm[i].flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
}
g_ble_ll_sync_sm_establishing = NULL;
g_ble_ll_sync_pending = 0;
sm->sync_pending_cnt = 0;
}
static void
ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm)
{
int i;
BLE_LL_ASSERT(sm == g_ble_ll_sync_sm_establishing);
BLE_LL_ASSERT(g_ble_ll_sync_pending);
BLE_LL_ASSERT(sm->sync_pending_cnt);
/* if we can retry on next event */
if (--g_ble_ll_sync_pending) {
if (--sm->sync_pending_cnt) {
return;
}
ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT);
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
/* clear as we are not longer pending sync here */
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
g_ble_ll_sync_sm[i].flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
}
g_ble_ll_sync_sm_establishing = NULL;
g_ble_ll_sync_pending = 0;
}
void
@@ -896,14 +905,26 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
BLE_LL_ASSERT(sm);
/* this could happen if sync was terminated while pkt_in was already
* in LL queue, just drop in that case
/* this could happen if sync was cancelled or terminated while pkt_in was
* already in LL queue, just drop in that case
*/
if (!sm->flags) {
ble_ll_scan_chk_resume();
return;
}
/* Set anchor point (and last) if 1st rxd frame in sync event.
* According to spec this should be done even if CRC is not valid so we
* can store it here
*/
if (sm->flags & BLE_LL_SYNC_SM_FLAG_SET_ANCHOR) {
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR;
sm->anchor_point = hdr->beg_cputime;
sm->anchor_point_usecs = hdr->rem_usecs;
sm->last_anchor_point = sm->anchor_point;
}
/* CRC error, end event */
if (!BLE_MBUF_HDR_CRC_OK(hdr)) {
STATS_INC(ble_ll_stats, sync_crc_err);
@@ -1045,9 +1066,12 @@ ble_ll_sync_event_end(struct ble_npl_event *ev)
/* Remove any end events that might be enqueued */
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end);
/* don't schedule next event if sync is not established nor establishing */
/* don't schedule next event if sync is not established nor establishing
* at this point SM is no longer valid
*/
if (!(sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHED |
BLE_LL_SYNC_SM_FLAG_ESTABLISHING))) {
ble_ll_sync_sm_clear(sm);
return;
}
@@ -1067,11 +1091,14 @@ ble_ll_sync_event_end(struct ble_npl_event *ev)
if (ble_ll_sync_next_event(sm) < 0) {
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
/* don't allow any retry if this failed */
g_ble_ll_sync_pending = 1;
sm->sync_pending_cnt = 1;
ble_ll_sync_check_failed(sm);
} else {
ble_ll_sync_lost_event(sm);
}
/* at this point SM is no longer valid */
ble_ll_sync_sm_clear(sm);
return;
}
} while (ble_ll_sched_sync_reschedule(&sm->sch, sm->anchor_point,
@@ -1096,29 +1123,46 @@ void
ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
struct ble_mbuf_hdr *rxhdr, const uint8_t *syncinfo)
{
struct ble_ll_sync_sm *sm;
struct ble_ll_sync_sm *sm = NULL;
uint16_t max_skip;
uint32_t offset;
uint32_t usecs;
uint16_t itvl;
int i;
if (!g_ble_ll_sync_pending || g_ble_ll_sync_sm_establishing) {
/* ignore if not synchronizing */
if (!g_ble_ll_sync_create_comp_ev) {
return;
}
sm = ble_ll_sync_find(addr, addr_type, sid);
/* get reserved SM */
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
if (g_ble_ll_sync_sm[i].flags & BLE_LL_SYNC_SM_FLAG_RESERVED) {
sm = &g_ble_ll_sync_sm[i];
break;
}
}
/* this means we already got sync info event and pending sync */
if (!sm) {
return;
}
/* don't attempt to synchronize again if already synchronized */
if (sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING |
BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) {
/* check peer */
if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) {
if (ble_ll_sync_on_list(addr, addr_type, sid) < 0) {
return;
}
}
/* check if this SM is allowed to establish new sync */
if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_PENDING)) {
/* set addr and sid in sm */
sm->adv_sid = sid;
sm->adv_addr_type = addr_type;
memcpy(sm->adv_addr, addr, BLE_DEV_ADDR_LEN);
} else {
if ((sm->adv_sid != sid) || (sm->adv_addr_type != addr_type) ||
memcmp(sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) {
return;
}
}
/* Sync Packet Offset (13 bits), Offset Units (1 bit), RFU (2 bits) */
@@ -1130,6 +1174,17 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
return;
}
/* Interval (2 bytes), ignore if invalid */
itvl = get_le16(&syncinfo[2]);
if (itvl < 6) {
return;
}
/* set params from HCI LE Create Periodic Sync */
sm->timeout = g_ble_ll_sync_create_params.timeout;
sm->skip = g_ble_ll_sync_create_params.max_skip;
sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT;
if (syncinfo[1] & 0x20) {
offset *= 300;
sm->flags |= BLE_LL_SYNC_SM_FLAG_OFFSET_300;
@@ -1141,13 +1196,7 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
/* sync end event */
ble_npl_event_init(&sm->sync_ev_end, ble_ll_sync_event_end, sm);
/* Interval (2 bytes) */
sm->itvl = get_le16(&syncinfo[2]);
/* ignore if interval is invalid */
if (sm->itvl < 6) {
return;
}
sm->itvl = itvl;
/* precalculate interval ticks and usecs */
usecs = sm->itvl * BLE_LL_SYNC_ITVL_USECS;
@@ -1224,10 +1273,33 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
sm->last_anchor_point = sm->anchor_point;
/* keep sm for which we want to establish new sync */
#if MYNEWT_VAL(BLE_VERSION) >= 51
if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) {
sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
}
#endif
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_RESERVED;
sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
sm->flags |= BLE_LL_SYNC_SM_FLAG_SYNC_INFO;
g_ble_ll_sync_sm_establishing = sm;
}
static struct ble_ll_sync_sm *
ble_ll_sync_reserve(void)
{
struct ble_ll_sync_sm *sm;
int i;
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
sm = &g_ble_ll_sync_sm[i];
if (!sm->flags) {
sm->flags |= BLE_LL_SYNC_SM_FLAG_RESERVED;
return sm;
}
}
return NULL;
}
int
@@ -1237,10 +1309,8 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
struct ble_ll_sync_sm *sm;
uint16_t timeout;
os_sr_t sr;
int cnt;
int i;
if (g_ble_ll_sync_pending) {
if (g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_CMD_DISALLOWED;
}
@@ -1261,7 +1331,7 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
}
timeout = le16toh(cmd->sync_timeout);
if (timeout < 0x000a && timeout > 0x4000) {
if (timeout < 0x000a || timeout > 0x4000) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
@@ -1276,44 +1346,8 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
}
#endif
/* check if list is sane */
if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) {
cnt = 0;
OS_ENTER_CRITICAL(sr);
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
sm = &g_ble_ll_sync_sm[i];
if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ON_LIST)) {
continue;
}
/* skip if already synchronized
* TODO should we return 0x0B if list is to be used?
*/
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
continue;
}
/* mark as pending */
sm->flags |= BLE_LL_SYNC_SM_FLAG_PENDING;
#if MYNEWT_VAL(BLE_VERSION) >= 51
if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) {
sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
}
#endif
sm->timeout = timeout * 10000; /* 10ms units, store in us */
sm->skip = cmd->skip;
cnt++;
}
OS_EXIT_CRITICAL(sr);
/* if nothing on list return error
* TODO is this valid behavior?
*/
if (!cnt) {
if (ble_ll_sync_list_empty()) {
return BLE_ERR_CMD_DISALLOWED;
}
} else {
@@ -1325,49 +1359,44 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
return BLE_ERR_INV_HCI_CMD_PARMS;
}
sm = ble_ll_sync_get(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
if (!sm) {
return BLE_ERR_MEM_CAPACITY;
}
OS_ENTER_CRITICAL(sr);
sm = ble_ll_sync_find(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
OS_EXIT_CRITICAL(sr);
/* if we already have link established return error as per spec */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
OS_EXIT_CRITICAL(sr);
if (sm) {
return BLE_ERR_ACL_CONN_EXISTS;
}
/* mark as pending */
sm->flags |= BLE_LL_SYNC_SM_FLAG_PENDING;
#if MYNEWT_VAL(BLE_VERSION) >= 51
if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) {
sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
}
#endif
sm->timeout = timeout * 10000; /* 10ms units, store in us */
sm->skip = cmd->skip;
OS_EXIT_CRITICAL(sr);
}
g_ble_ll_sync_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (!g_ble_ll_sync_comp_ev) {
OS_ENTER_CRITICAL(sr);
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
g_ble_ll_sync_sm[i].flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
sm->timeout = 0;
sm->skip = 0;
}
OS_EXIT_CRITICAL(sr);
/* reserve buffer for sync complete event */
g_ble_ll_sync_create_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (!g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_MEM_CAPACITY;
}
g_ble_ll_sync_pending = BLE_LL_SYNC_ESTABLISH_CNT;
OS_ENTER_CRITICAL(sr);
/* reserve 1 SM for created sync */
sm = ble_ll_sync_reserve();
if (!sm) {
ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
g_ble_ll_sync_create_comp_ev = NULL;
OS_EXIT_CRITICAL(sr);
return BLE_ERR_MEM_CAPACITY;
}
/* if we don't use list, store expected address in reserved SM */
if (!(cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER)) {
sm->adv_sid = cmd->sid;
sm->adv_addr_type = cmd->peer_addr_type;
memcpy(&sm->adv_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN);
}
g_ble_ll_sync_create_params.timeout = timeout * 10000; /* 10ms units, store in us */;
g_ble_ll_sync_create_params.max_skip = cmd->skip;
g_ble_ll_sync_create_params.options = cmd->options;
OS_EXIT_CRITICAL(sr);
return BLE_ERR_SUCCESS;
}
@@ -1384,7 +1413,7 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb)
os_sr_t sr;
int i;
if (!g_ble_ll_sync_pending) {
if (!g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_CMD_DISALLOWED;
}
@@ -1393,20 +1422,22 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb)
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
sm = &g_ble_ll_sync_sm[i];
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
/* cancelled before fist sync info packet */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_RESERVED) {
memset(sm, 0, sizeof(*sm));
break;
}
/* cancelled while pending sync */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
ble_ll_sched_rmv_elem(&sm->sch);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end);
ble_ll_sync_sm_clear(sm);
break;
}
}
OS_EXIT_CRITICAL(sr);
g_ble_ll_sync_pending = 0;
g_ble_ll_sync_sm_establishing = NULL;
/* g_ble_ll_sync_create_comp_ev will be cleared by this callback */
*post_cmd_cb = ble_ll_sync_cancel_complete_event;
return BLE_ERR_SUCCESS;
@@ -1420,7 +1451,7 @@ ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len)
uint16_t handle;
os_sr_t sr;
if (g_ble_ll_sync_pending) {
if (g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_CMD_DISALLOWED;
}
@@ -1457,10 +1488,9 @@ int
ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_add_dev_to_periodic_adv_list_cp *cmd = (const void *)cmdbuf;
struct ble_ll_sync_sm *sm;
os_sr_t sr;
int i;
if (g_ble_ll_sync_pending) {
if (g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_CMD_DISALLOWED;
}
@@ -1475,17 +1505,19 @@ ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len)
return BLE_ERR_INV_HCI_CMD_PARMS;
}
OS_ENTER_CRITICAL(sr);
i = ble_ll_sync_on_list(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
if (i >= 0) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
sm = ble_ll_sync_get(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
if (!sm) {
OS_EXIT_CRITICAL(sr);
i = ble_ll_sync_list_get_free();
if (i < 0) {
return BLE_ERR_MEM_CAPACITY;
}
sm->flags |= BLE_LL_SYNC_SM_FLAG_ON_LIST;
OS_EXIT_CRITICAL(sr);
g_ble_ll_sync_adv_list[i].adv_sid = cmd->sid;
g_ble_ll_sync_adv_list[i].adv_addr_type = cmd->peer_addr_type;
memcpy(&g_ble_ll_sync_adv_list[i].adv_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN);
return BLE_ERR_SUCCESS;
}
@@ -1494,14 +1526,13 @@ int
ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rem_dev_from_periodic_adv_list_cp *cmd = (const void *)cmdbuf;
struct ble_ll_sync_sm *sm;
os_sr_t sr;
int i;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (g_ble_ll_sync_pending) {
if (g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_CMD_DISALLOWED;
}
@@ -1513,22 +1544,13 @@ ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len)
return BLE_ERR_INV_HCI_CMD_PARMS;
}
OS_ENTER_CRITICAL(sr);
sm = ble_ll_sync_find(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
if (!sm) {
OS_EXIT_CRITICAL(sr);
i = ble_ll_sync_on_list(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
if (i < 0) {
return BLE_ERR_UNK_ADV_INDENT;
}
/* if sync is established only mark entry as removed from list */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ON_LIST;
} else {
ble_ll_sync_sm_clear(sm);
}
OS_EXIT_CRITICAL(sr);
memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i]));
g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
return BLE_ERR_SUCCESS;
}
@@ -1536,30 +1558,17 @@ ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len)
int
ble_ll_sync_list_clear(void)
{
struct ble_ll_sync_sm *sm;
os_sr_t sr;
int i;
if (g_ble_ll_sync_pending) {
if (g_ble_ll_sync_create_comp_ev) {
return BLE_ERR_CMD_DISALLOWED;
}
OS_ENTER_CRITICAL(sr);
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
sm = &g_ble_ll_sync_sm[i];
/* if sync is establish only mark entry as removed from list */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ON_LIST;
continue;
}
ble_ll_sync_sm_clear(sm);
for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i]));
g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
}
OS_EXIT_CRITICAL(sr);
return BLE_ERR_SUCCESS;
}
@@ -1567,24 +1576,8 @@ int
ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_le_rd_periodic_adv_list_size_rp *rsp = (void *) rspbuf;
os_sr_t sr;
int i;
rsp->list_size = 0;
OS_ENTER_CRITICAL(sr);
for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
/* only established syncs 'consume' state machine entry */
if (g_ble_ll_sync_sm[i].flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING |
BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) {
continue;
}
rsp->list_size++;
}
OS_EXIT_CRITICAL(sr);
rsp->list_size = ARRAY_SIZE(g_ble_ll_sync_adv_list);
*rsplen = sizeof(*rsp);
return BLE_ERR_SUCCESS;
@@ -1632,7 +1625,6 @@ ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len)
}
OS_EXIT_CRITICAL(sr);
return BLE_ERR_SUCCESS;
}
#endif
@@ -1650,9 +1642,14 @@ ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm)
bool
ble_ll_sync_enabled(void)
{
return g_ble_ll_sync_pending > 0;
return g_ble_ll_sync_create_comp_ev != NULL;
}
/**
* Called to reset the sync module. When this function is called the
* scheduler has been stopped and the phy has been disabled. The LL should
* be in the standby state.
*/
void
ble_ll_sync_reset(void)
{
@@ -1662,14 +1659,30 @@ ble_ll_sync_reset(void)
ble_ll_sync_sm_clear(&g_ble_ll_sync_sm[i]);
}
g_ble_ll_sync_pending = 0;
for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i]));
g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
}
g_ble_ll_sync_create_params.timeout = 0;
g_ble_ll_sync_create_params.max_skip = 0;
g_ble_ll_sync_create_params.options = 0;
g_ble_ll_sync_sm_establishing = NULL;
g_ble_ll_sync_sm_current = NULL;
if (g_ble_ll_sync_comp_ev) {
ble_hci_trans_buf_free(g_ble_ll_sync_comp_ev);
g_ble_ll_sync_comp_ev = NULL;
if (g_ble_ll_sync_create_comp_ev) {
ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
g_ble_ll_sync_create_comp_ev = NULL;
}
}
void
ble_ll_sync_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
}
}
#endif
+5
View File
@@ -276,6 +276,11 @@ syscfg.defs:
This option is used to configure number of supported periodic syncs.
value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT:
description: >
Size of Periodic Advertiser sync list.
value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
BLE_LL_EXT_ADV_AUX_PTR_CNT:
description: >
This option configure a max number of scheduled outstanding auxiliary