Bluetooth: controller: Add non-connectable scannable
This enables processing of AUX_SCAN_REQ and sending back AUX_SCAN_RSP on non-connectabe scannable advertising instances. Similar path will be used for AUX_CONNECT_REQ so there are few references for connectable as well, but this is not supported as for now. Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
This commit is contained in:
parent
b47df3cc21
commit
09115429a1
1 changed files with 251 additions and 3 deletions
|
@ -9,6 +9,7 @@
|
|||
#include <zephyr.h>
|
||||
#include <soc.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#include "hal/cpu.h"
|
||||
#include "hal/ccm.h"
|
||||
|
@ -26,9 +27,12 @@
|
|||
#include "lll_chan.h"
|
||||
#include "lll_adv.h"
|
||||
#include "lll_adv_aux.h"
|
||||
#include "lll_filter.h"
|
||||
|
||||
#include "lll_internal.h"
|
||||
#include "lll_tim_internal.h"
|
||||
#include "lll_adv_internal.h"
|
||||
#include "lll_prof_internal.h"
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#define LOG_MODULE_NAME bt_ctlr_lll_adv_aux
|
||||
|
@ -38,6 +42,12 @@
|
|||
static int init_reset(void);
|
||||
static int prepare_cb(struct lll_prepare_param *prepare_param);
|
||||
static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
|
||||
static void isr_tx(void *param);
|
||||
static void isr_rx(void *param);
|
||||
static inline int isr_rx_pdu(struct lll_adv_aux *lll_aux,
|
||||
uint8_t devmatch_ok, uint8_t devmatch_id,
|
||||
uint8_t irkmatch_ok, uint8_t irkmatch_id,
|
||||
uint8_t rssi_ready);
|
||||
|
||||
int lll_adv_aux_init(void)
|
||||
{
|
||||
|
@ -164,9 +174,35 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
|
|||
/* Set the Radio Tx Packet */
|
||||
radio_pkt_tx_set(sec_pdu);
|
||||
|
||||
/* TODO: Based on adv_mode switch to Rx, if needed */
|
||||
radio_isr_set(lll_isr_done, lll);
|
||||
radio_switch_complete_and_disable();
|
||||
/* Switch to Rx if connectable or scannable */
|
||||
if (pri_com_hdr->adv_mode & (BT_HCI_LE_ADV_PROP_CONN |
|
||||
BT_HCI_LE_ADV_PROP_SCAN)) {
|
||||
|
||||
struct pdu_adv *scan_pdu;
|
||||
|
||||
scan_pdu = lll_adv_scan_rsp_latest_get(lll_adv, &upd);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
if (upd) {
|
||||
/* Copy the address from the adv packet we will send
|
||||
* into the scan response.
|
||||
*/
|
||||
memcpy(&scan_pdu->adv_ext_ind.ext_hdr_adi_adv_data[1],
|
||||
&sec_pdu->adv_ext_ind.ext_hdr_adi_adv_data[1],
|
||||
BDADDR_SIZE);
|
||||
}
|
||||
#else
|
||||
ARG_UNUSED(scan_pdu);
|
||||
ARG_UNUSED(upd);
|
||||
#endif /* !CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
radio_isr_set(isr_tx, lll);
|
||||
radio_tmr_tifs_set(EVENT_IFS_US);
|
||||
radio_switch_complete_and_rx(phy_s);
|
||||
} else {
|
||||
radio_isr_set(lll_isr_done, lll);
|
||||
radio_switch_complete_and_disable();
|
||||
}
|
||||
|
||||
#if defined(BT_CTLR_ADV_EXT_PBACK)
|
||||
start_us = 1000;
|
||||
|
@ -240,3 +276,215 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
|
|||
|
||||
lll_done(param);
|
||||
}
|
||||
|
||||
static void isr_tx(void *param)
|
||||
{
|
||||
struct lll_adv_aux *lll_aux = param;
|
||||
struct lll_adv *lll = lll_aux->adv;
|
||||
uint32_t hcto;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
lll_prof_latency_capture();
|
||||
}
|
||||
|
||||
/* Clear radio tx status and events */
|
||||
lll_isr_tx_status_reset();
|
||||
|
||||
/* setup tIFS switching */
|
||||
radio_tmr_tifs_set(EVENT_IFS_US);
|
||||
radio_switch_complete_and_tx(lll->phy_s, 0, lll->phy_s, 0);
|
||||
|
||||
radio_pkt_rx_set(radio_pkt_scratch_get());
|
||||
/* assert if radio packet ptr is not set and radio started rx */
|
||||
LL_ASSERT(!radio_is_ready());
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
lll_prof_cputime_capture();
|
||||
}
|
||||
|
||||
radio_isr_set(isr_rx, param);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
if (ull_filter_lll_rl_enabled()) {
|
||||
uint8_t count, *irks = ull_filter_lll_irks_get(&count);
|
||||
|
||||
radio_ar_configure(count, irks);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
/* +/- 2us active clock jitter, +1 us hcto compensation */
|
||||
hcto = radio_tmr_tifs_base_get() + EVENT_IFS_US + 4 + 1;
|
||||
hcto += radio_rx_chain_delay_get(lll->phy_s, 1);
|
||||
hcto += addr_us_get(0);
|
||||
hcto -= radio_tx_chain_delay_get(lll->phy_s, 0);
|
||||
radio_tmr_hcto_configure(hcto);
|
||||
|
||||
/* capture end of CONNECT_IND PDU, used for calculating first
|
||||
* slave event.
|
||||
*/
|
||||
radio_tmr_end_capture();
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_SCAN_REQ_RSSI) ||
|
||||
IS_ENABLED(CONFIG_BT_CTLR_CONN_RSSI)) {
|
||||
radio_rssi_measure();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
/* PA/LNA enable is overwriting packet end used in ISR
|
||||
* profiling, hence back it up for later use.
|
||||
*/
|
||||
lll_prof_radio_end_backup();
|
||||
}
|
||||
|
||||
radio_gpio_lna_setup();
|
||||
radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + EVENT_IFS_US - 4 -
|
||||
radio_tx_chain_delay_get(0, 0) -
|
||||
CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
|
||||
#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
/* NOTE: as scratch packet is used to receive, it is safe to
|
||||
* generate profile event using rx nodes.
|
||||
*/
|
||||
lll_prof_send();
|
||||
}
|
||||
}
|
||||
|
||||
static void isr_rx(void *param)
|
||||
{
|
||||
uint8_t trx_done;
|
||||
uint8_t crc_ok;
|
||||
uint8_t devmatch_ok;
|
||||
uint8_t devmatch_id;
|
||||
uint8_t irkmatch_ok;
|
||||
uint8_t irkmatch_id;
|
||||
uint8_t rssi_ready;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
lll_prof_latency_capture();
|
||||
}
|
||||
|
||||
/* Read radio status and events */
|
||||
trx_done = radio_is_done();
|
||||
if (trx_done) {
|
||||
crc_ok = radio_crc_is_valid();
|
||||
devmatch_ok = radio_filter_has_match();
|
||||
devmatch_id = radio_filter_match_get();
|
||||
irkmatch_ok = radio_ar_has_match();
|
||||
irkmatch_id = radio_ar_match_get();
|
||||
rssi_ready = radio_rssi_is_ready();
|
||||
} else {
|
||||
crc_ok = devmatch_ok = irkmatch_ok = rssi_ready = 0U;
|
||||
devmatch_id = irkmatch_id = 0xFF;
|
||||
}
|
||||
|
||||
/* Clear radio status and events */
|
||||
lll_isr_status_reset();
|
||||
|
||||
/* No Rx */
|
||||
if (!trx_done) {
|
||||
goto isr_rx_do_close;
|
||||
}
|
||||
|
||||
if (crc_ok) {
|
||||
int err;
|
||||
|
||||
err = isr_rx_pdu(param, devmatch_ok, devmatch_id,
|
||||
irkmatch_ok, irkmatch_id, rssi_ready);
|
||||
if (!err) {
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
lll_prof_send();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
isr_rx_do_close:
|
||||
radio_isr_set(lll_isr_done, param);
|
||||
radio_disable();
|
||||
}
|
||||
|
||||
static inline int isr_rx_pdu(struct lll_adv_aux *lll_aux,
|
||||
uint8_t devmatch_ok, uint8_t devmatch_id,
|
||||
uint8_t irkmatch_ok, uint8_t irkmatch_id,
|
||||
uint8_t rssi_ready)
|
||||
{
|
||||
struct pdu_adv *pdu_rx, *pdu_adv, *pdu_aux;
|
||||
struct lll_adv *lll = lll_aux->adv;
|
||||
uint8_t tx_addr;
|
||||
uint8_t *addr;
|
||||
uint8_t upd;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
/* An IRK match implies address resolution enabled */
|
||||
uint8_t rl_idx = irkmatch_ok ? ull_filter_lll_rl_irk_idx(irkmatch_id) :
|
||||
FILTER_IDX_NONE;
|
||||
#else
|
||||
uint8_t rl_idx = FILTER_IDX_NONE;
|
||||
#endif /* CONFIG_BT_CTLR_PRIVACY */
|
||||
|
||||
pdu_rx = (void *)radio_pkt_scratch_get();
|
||||
pdu_adv = lll_adv_data_curr_get(lll);
|
||||
pdu_aux = lll_adv_aux_data_latest_get(lll_aux, &upd);
|
||||
|
||||
if (pdu_adv->type == PDU_ADV_TYPE_EXT_IND) {
|
||||
/* AdvA is placed at 2nd byte of ext hdr data */
|
||||
addr = &pdu_aux->adv_ext_ind.ext_hdr_adi_adv_data[1];
|
||||
tx_addr = pdu_aux->tx_addr;
|
||||
} else {
|
||||
addr = pdu_adv->adv_ind.addr;
|
||||
tx_addr = pdu_adv->tx_addr;
|
||||
}
|
||||
|
||||
if ((pdu_rx->type == PDU_ADV_TYPE_AUX_SCAN_REQ) &&
|
||||
(pdu_rx->len == sizeof(struct pdu_adv_scan_req)) &&
|
||||
lll_adv_scan_req_check(lll, pdu_rx, tx_addr, addr, devmatch_ok,
|
||||
&rl_idx)) {
|
||||
radio_isr_set(lll_isr_done, lll);
|
||||
radio_switch_complete_and_disable();
|
||||
radio_pkt_tx_set(lll_adv_scan_rsp_curr_get(lll));
|
||||
|
||||
/* assert if radio packet ptr is not set and radio started tx */
|
||||
LL_ASSERT(!radio_is_ready());
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
lll_prof_cputime_capture();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
|
||||
if (lll->scan_req_notify) {
|
||||
uint32_t err;
|
||||
|
||||
/* Generate the scan request event */
|
||||
err = lll_adv_scan_req_report(lll, pdu_rx, rl_idx,
|
||||
rssi_ready);
|
||||
if (err) {
|
||||
/* Scan Response will not be transmitted */
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||
/* PA/LNA enable is overwriting packet end used in ISR
|
||||
* profiling, hence back it up for later use.
|
||||
*/
|
||||
lll_prof_radio_end_backup();
|
||||
}
|
||||
|
||||
radio_gpio_pa_setup();
|
||||
radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
|
||||
EVENT_IFS_US -
|
||||
radio_rx_chain_delay_get(0, 0) -
|
||||
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
|
||||
#endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: add handling for AUX_CONNECT_REQ */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue