From 03942483ecd55fa03612d3f22e35073ad0cdf44d Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 30 May 2017 22:41:20 +0200 Subject: [PATCH] Bluetooth: controller: LE Adv. Ext. non-conn non-scan w/o aux Add implementation to set extended advertising parameters, start advertising Non-Connectable and Non-Scannable Undirected without auxiliary packet. Jira: ZEP-2238 Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hci/hci.c | 15 +- subsys/bluetooth/controller/include/ll.h | 12 +- subsys/bluetooth/controller/ll_sw/ctrl.c | 27 ++- subsys/bluetooth/controller/ll_sw/ctrl.h | 8 +- subsys/bluetooth/controller/ll_sw/ll_adv.c | 194 ++++++++++++++++++++- 5 files changed, 238 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 51ddce131ac..501fa241f13 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -572,17 +572,24 @@ static void le_set_adv_param(struct net_buf *buf, struct net_buf **evt) struct bt_hci_cp_le_set_adv_param *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u16_t min_interval; - u32_t status; + u8_t status; min_interval = sys_le16_to_cpu(cmd->min_interval); - status = ll_adv_params_set(min_interval, cmd->type, cmd->own_addr_type, - cmd->direct_addr.type, +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + status = ll_adv_params_set(0, 0, min_interval, cmd->type, + cmd->own_addr_type, cmd->direct_addr.type, + &cmd->direct_addr.a.val[0], cmd->channel_map, + cmd->filter_policy, 0, 0, 0, 0, 0, 0); +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + status = ll_adv_params_set(min_interval, cmd->type, + cmd->own_addr_type, cmd->direct_addr.type, &cmd->direct_addr.a.val[0], cmd->channel_map, cmd->filter_policy); +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ ccst = cmd_complete(evt, sizeof(*ccst)); - ccst->status = (!status) ? 0x00 : BT_HCI_ERR_CMD_DISALLOWED; + ccst->status = status; } static void le_read_adv_chan_tx_power(struct net_buf *buf, struct net_buf **evt) diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 2b6eb35af69..d6967211fbe 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -12,10 +12,20 @@ int ll_init(struct k_sem *sem_rx); void ll_reset(void); u8_t *ll_addr_get(u8_t addr_type, u8_t *p_bdaddr); void ll_addr_set(u8_t addr_type, u8_t const *const p_bdaddr); + +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) +u32_t ll_adv_params_set(u8_t handle, u16_t evt_prop, u32_t interval, + u8_t adv_type, u8_t own_addr_type, + u8_t direct_addr_type, u8_t const *const direct_addr, + u8_t chl_map, u8_t filter_policy, u8_t *tx_pwr, + u8_t phy_p, u8_t skip, u8_t phy_s, u8_t sid, u8_t sreq); +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ u32_t ll_adv_params_set(u16_t interval, u8_t adv_type, u8_t own_addr_type, u8_t direct_addr_type, - u8_t const *const p_direct_addr, u8_t chl_map, + u8_t const *const direct_addr, u8_t chl_map, u8_t filter_policy); +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + void ll_adv_data_set(u8_t len, u8_t const *const p_data); void ll_scan_data_set(u8_t len, u8_t const *const p_data); u32_t ll_adv_enable(u8_t enable); diff --git a/subsys/bluetooth/controller/ll_sw/ctrl.c b/subsys/bluetooth/controller/ll_sw/ctrl.c index 7dcee8dbd64..784c2c1d871 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl.c +++ b/subsys/bluetooth/controller/ll_sw/ctrl.c @@ -79,8 +79,13 @@ struct advertiser { struct shdr hdr; u8_t is_enabled:1; - u8_t chl_map:3; u8_t chl_map_current:3; + u8_t rfu:4; + +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + u8_t phy_p:3; +#endif /* CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + u8_t chl_map:3; u8_t filter_policy:2; struct radio_adv_data adv_data; @@ -4737,7 +4742,9 @@ static void adv_setup(void) _radio.advertiser.adv_data.data[ _radio.advertiser.adv_data.first]; radio_pkt_tx_set(pdu); - if (pdu->type != PDU_ADV_TYPE_NONCONN_IND) { + if ((pdu->type != PDU_ADV_TYPE_NONCONN_IND) && + (!IS_ENABLED(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) || + (pdu->type != PDU_ADV_TYPE_EXT_IND))) { _radio.state = STATE_TX; radio_tmr_tifs_set(RADIO_TIFS); radio_switch_complete_and_rx(); @@ -4780,7 +4787,12 @@ static void event_adv(u32_t ticks_at_expire, u32_t remainder, _radio.ticker_id_event = RADIO_TICKER_ID_ADV; _radio.ticks_anchor = ticks_at_expire; - adv_scan_configure(0, 0); /* TODO: Advertisement PHY */ +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + /* TODO: if coded we use S8? */ + adv_scan_configure(_radio.advertiser.phy_p, 1); +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + adv_scan_configure(0, 0); +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ _radio.advertiser.chl_map_current = _radio.advertiser.chl_map; adv_setup(); @@ -8001,7 +8013,12 @@ role_disable_cleanup: return ret_cb; } +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) +u32_t radio_adv_enable(u8_t phy_p, u16_t interval, u8_t chl_map, + u8_t filter_policy) +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ u32_t radio_adv_enable(u16_t interval, u8_t chl_map, u8_t filter_policy) +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ { u32_t volatile ret_cb = TICKER_STATUS_BUSY; u32_t ticks_slot_offset; @@ -8117,6 +8134,10 @@ u32_t radio_adv_enable(u16_t interval, u8_t chl_map, u8_t filter_policy) conn = NULL; } +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + _radio.advertiser.phy_p = phy_p; +#endif /* CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + _radio.advertiser.chl_map = chl_map; _radio.advertiser.filter_policy = filter_policy; diff --git a/subsys/bluetooth/controller/ll_sw/ctrl.h b/subsys/bluetooth/controller/ll_sw/ctrl.h index ded4855ece1..83963e56a27 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl.h +++ b/subsys/bluetooth/controller/ll_sw/ctrl.h @@ -315,8 +315,14 @@ void radio_ticks_active_to_start_set(u32_t ticks_active_to_start); /* Downstream - Advertiser */ struct radio_adv_data *radio_adv_data_get(void); struct radio_adv_data *radio_scan_data_get(void); -u32_t radio_adv_enable(u16_t interval, u8_t chl_map, + +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) +u32_t radio_adv_enable(u8_t phy_p, u16_t interval, u8_t chl_map, u8_t filter_policy); +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ +u32_t radio_adv_enable(u16_t interval, u8_t chl_map, u8_t filter_policy); +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + u32_t radio_adv_disable(void); u32_t radio_adv_is_enabled(void); u32_t radio_adv_filter_pol_get(void); diff --git a/subsys/bluetooth/controller/ll_sw/ll_adv.c b/subsys/bluetooth/controller/ll_sw/ll_adv.c index e77ef15d2d8..c6ee635c58d 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ll_adv.c @@ -17,11 +17,31 @@ #include "ll.h" static struct { - u16_t interval; - u8_t filter_policy:2; u8_t chl_map:3; + u8_t filter_policy:2; + +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + u8_t phy_p:3; + u32_t interval; +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + u16_t interval; +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ } ll_adv; +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) +u32_t ll_adv_params_set(u8_t handle, u16_t evt_prop, u32_t interval, + u8_t adv_type, u8_t own_addr_type, + u8_t direct_addr_type, u8_t const *const direct_addr, + u8_t chl_map, u8_t filter_policy, u8_t *tx_pwr, + u8_t phy_p, u8_t skip, u8_t phy_s, u8_t sid, u8_t sreq) +{ + u8_t const pdu_adv_type[] = {PDU_ADV_TYPE_ADV_IND, + PDU_ADV_TYPE_DIRECT_IND, + PDU_ADV_TYPE_SCAN_IND, + PDU_ADV_TYPE_NONCONN_IND, + PDU_ADV_TYPE_DIRECT_IND, + PDU_ADV_TYPE_EXT_IND}; +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ u32_t ll_adv_params_set(u16_t interval, u8_t adv_type, u8_t own_addr_type, u8_t direct_addr_type, u8_t const *const direct_addr, u8_t chl_map, @@ -32,13 +52,50 @@ u32_t ll_adv_params_set(u16_t interval, u8_t adv_type, PDU_ADV_TYPE_SCAN_IND, PDU_ADV_TYPE_NONCONN_IND, PDU_ADV_TYPE_DIRECT_IND}; +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + struct radio_adv_data *radio_adv_data; struct pdu_adv *pdu; if (radio_adv_is_enabled()) { - return 1; + return 0x0C; /* Command Disallowed */ } +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + /* TODO: check and fail (0x12, invalid HCI cmd param) if invalid + * evt_prop bits. + */ + + ll_adv.phy_p = BIT(0); + + /* extended */ + if (adv_type > 0x04) { + /* legacy */ + if (evt_prop & BIT(4)) { + u8_t const leg_adv_type[] = { 0x03, 0x04, 0x02, 0x00}; + + adv_type = leg_adv_type[evt_prop & 0x03]; + + /* high duty cycle directed */ + if (evt_prop & BIT(3)) { + adv_type = 0x01; + } + } else { + /* - Connectable and scannable not allowed; + * - High duty cycle directed connectable not allowed + */ + if (((evt_prop & 0x03) == 0x03) || + ((evt_prop & 0x0C) == 0x0C)) { + return 0x12; /* invalid HCI cmd param */ + } + + adv_type = 0x05; /* PDU_ADV_TYPE_EXT_IND */ + + ll_adv.phy_p = phy_p; + } + } +#endif /* CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + /* remember params so that set adv/scan data and adv enable * interface can correctly update adv/scan data in the * double buffer between caller and controller context. @@ -52,7 +109,7 @@ u32_t ll_adv_params_set(u16_t interval, u8_t adv_type, ll_adv.chl_map = chl_map; ll_adv.filter_policy = filter_policy; - /* update the current adv data */ + /* update the "current" primary adv data */ radio_adv_data = radio_adv_data_get(); pdu = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0]; pdu->type = pdu_adv_type[adv_type]; @@ -60,7 +117,9 @@ u32_t ll_adv_params_set(u16_t interval, u8_t adv_type, if (IS_ENABLED(CONFIG_BLUETOOTH_CONTROLLER_CHAN_SEL_2) && ((pdu->type == PDU_ADV_TYPE_ADV_IND) || - (pdu->type == PDU_ADV_TYPE_DIRECT_IND))) { + (pdu->type == PDU_ADV_TYPE_DIRECT_IND) || + (IS_ENABLED(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) && + (pdu->type == PDU_ADV_TYPE_EXT_IND)))) { pdu->chan_sel = 1; } else { pdu->chan_sel = 0; @@ -73,6 +132,95 @@ u32_t ll_adv_params_set(u16_t interval, u8_t adv_type, memcpy(&pdu->payload.direct_ind.tgt_addr[0], direct_addr, BDADDR_SIZE); pdu->len = sizeof(struct pdu_adv_payload_direct_ind); + +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + } else if (pdu->type == PDU_ADV_TYPE_EXT_IND) { + struct pdu_adv_payload_com_ext_adv *p; + struct ext_adv_hdr *h; + u8_t *ptr; + u8_t len; + + p = (void *)&pdu->payload.adv_ext_ind; + h = (void *)p->ext_hdr_adi_adv_data; + ptr = (u8_t *)h + sizeof(*h); + + /* No ACAD and no AdvData */ + p->ext_hdr_len = 0; + p->adv_mode = evt_prop & 0x03; + + /* Zero-init header flags */ + *(u8_t *)h = 0; + + /* AdvA flag */ + if (!(evt_prop & BIT(5)) && !p->adv_mode && (phy_p != BIT(2))) { + /* TODO: optional on 1M */ + h->adv_addr = 1; + + /* NOTE: AdvA is filled at enable */ + ptr += BDADDR_SIZE; + } + + /* TODO: TargetA flag */ + + /* TODO: ADI flag */ + + /* TODO: AuxPtr flag */ + + /* TODO: SyncInfo flag */ + + /* Tx Power flag */ + if (evt_prop & BIT(6)) { + h->tx_pwr = 1; + ptr++; + } + + /* Calc primary PDU len */ + len = ptr - (u8_t *)p; + if (len > (offsetof(struct pdu_adv_payload_com_ext_adv, + ext_hdr_adi_adv_data) + sizeof(*h))) { + p->ext_hdr_len = len - + offsetof(struct pdu_adv_payload_com_ext_adv, + ext_hdr_adi_adv_data); + pdu->len = len; + } else { + pdu->len = offsetof(struct pdu_adv_payload_com_ext_adv, + ext_hdr_adi_adv_data); + } + + /* Start filling primary PDU payload based on flags */ + + /* TODO: AdvData */ + + /* TODO: ACAD */ + + /* Tx Power */ + if (h->tx_pwr) { + u8_t _tx_pwr; + + _tx_pwr = 0; + if (tx_pwr) { + if (*tx_pwr != 0x7F) { + _tx_pwr = *tx_pwr; + } else { + *tx_pwr = _tx_pwr; + } + } + + ptr--; + *ptr = _tx_pwr; + } + + /* TODO: SyncInfo */ + + /* TODO: AuxPtr */ + + /* TODO: ADI */ + + /* NOTE: TargetA, filled at enable and RPA timeout */ + + /* NOTE: AdvA, filled at enable and RPA timeout */ +#endif /* CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + } else if (pdu->len == 0) { pdu->len = BDADDR_SIZE; } @@ -208,13 +356,41 @@ u32_t ll_adv_enable(u8_t enable) pdu_scan = (struct pdu_adv *)&radio_scan_data->data [radio_scan_data->last][0]; - memcpy(&pdu_adv->payload.adv_ind.addr[0], - ll_addr_get(pdu_adv->tx_addr, NULL), BDADDR_SIZE); - memcpy(&pdu_scan->payload.scan_rsp.addr[0], - ll_addr_get(pdu_adv->tx_addr, NULL), BDADDR_SIZE); + if (0) { +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + } else if (pdu_adv->type == PDU_ADV_TYPE_EXT_IND) { + struct pdu_adv_payload_com_ext_adv *p; + struct ext_adv_hdr *h; + u8_t *ptr; + + p = (void *)&pdu_adv->payload.adv_ext_ind; + h = (void *)p->ext_hdr_adi_adv_data; + ptr = (u8_t *)h + sizeof(*h); + + /* AdvA, fill here at enable */ + if (h->adv_addr) { + memcpy(ptr, ll_addr_get(pdu_adv->tx_addr, NULL), + BDADDR_SIZE); + } + + /* TODO: TargetA, fill here at enable */ +#endif /* CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ + + } else { + memcpy(&pdu_adv->payload.adv_ind.addr[0], + ll_addr_get(pdu_adv->tx_addr, NULL), BDADDR_SIZE); + memcpy(&pdu_scan->payload.scan_rsp.addr[0], + ll_addr_get(pdu_adv->tx_addr, NULL), BDADDR_SIZE); + } + +#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT) + status = radio_adv_enable(ll_adv.phy_p, ll_adv.interval, ll_adv.chl_map, + ll_adv.filter_policy); +#else /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ status = radio_adv_enable(ll_adv.interval, ll_adv.chl_map, ll_adv.filter_policy); +#endif /* !CONFIG_BLUETOOTH_CONTROLLER_ADV_EXT */ return status; }