1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-29 00:11:16 +01:00

Merge pull request #16843 from haukepetersen/add_nimble_scannerext

nimble_scanner: rework to enable scanning BLE5 PHYs and extended advertisements
This commit is contained in:
Francisco 2021-12-03 12:00:10 +01:00 committed by GitHub
commit 5ba215f9c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 428 additions and 112 deletions

View File

@ -12,6 +12,8 @@ config CPU_FAM_NRF52
# So far, NimBLE netif does not support nrf51 platforms, so we use a dedicated
# feature to mark this
select HAS_BLE_NIMBLE_NETIF
# All nrf52s support the 2Mbit PHY mode
select HAS_BLE_PHY_2MBIT
select HAS_CORTEXM_MPU
select HAS_CPU_NRF52
select HAS_PERIPH_I2C_RECONFIGURE
@ -33,6 +35,7 @@ config CPU_MODEL_NRF52811XXAA
bool
select CPU_CORE_CORTEX_M4
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
@ -40,6 +43,7 @@ config CPU_MODEL_NRF52820XXAA
bool
select CPU_CORE_CORTEX_M4
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
@ -52,6 +56,7 @@ config CPU_MODEL_NRF52833XXAA
bool
select CPU_CORE_CORTEX_M4F
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
@ -59,6 +64,7 @@ config CPU_MODEL_NRF52840XXAA
bool
select CPU_CORE_CORTEX_M4F
select CPU_FAM_NRF52
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING

View File

@ -25,4 +25,11 @@ FEATURES_PROVIDED += cortexm_mpu
FEATURES_PROVIDED += periph_i2c_reconfigure
# On top of the default 1Mbit PHY mode, all nrf52 support the 2MBit PHY mode,
# and the 52840 does further support the coded PHYs
FEATURES_PROVIDED += ble_phy_2mbit
ifneq (,$(filter nrf52811% nrf52820% nrf52833% nrf52840%,$(CPU_MODEL)))
FEATURES_PROVIDED += ble_phy_coded
endif
include $(RIOTCPU)/nrf5x_common/Makefile.features

View File

@ -33,6 +33,16 @@ config HAS_BLE_NIMBLE_NETIF
help
Indicates that NimBLE netif is supported on the current platform.
config HAS_BLE_PHY_2MBIT
bool
help
Indicates that the BLE radio supports the 2Mbit PHY mode
config HAS_BLE_PHY_CODED
bool
help
Indicates that the BLE radio supports the CODED PHY mode
config HAS_RADIO_NRFBLE
bool
select HAVE_NRF5X_RADIO

View File

@ -30,6 +30,9 @@
#include "nimble_scanner.h"
#include "nimble_scanlist.h"
/* default scan interval */
#define DEFAULT_SCAN_INTERVAL_MS 30
/* default scan duration (1s) */
#define DEFAULT_DURATION_MS (1 * MS_PER_SEC)
@ -39,6 +42,7 @@ int _cmd_scan(int argc, char **argv)
if ((argc == 2) && (memcmp(argv[1], "help", 4) == 0)) {
printf("usage: %s [timeout in ms]\n", argv[0]);
return 0;
}
if (argc >= 2) {
@ -46,11 +50,11 @@ int _cmd_scan(int argc, char **argv)
}
nimble_scanlist_clear();
printf("Scanning for %"PRIu32" ms now ...", timeout);
nimble_scanner_set_scan_duration(timeout);
printf("Scanning for %"PRIu32" ms now ...\n", timeout);
nimble_scanner_start();
ztimer_sleep(ZTIMER_MSEC, timeout);
puts(" done\n\nResults:");
nimble_scanner_stop();
puts("Done, results:");
nimble_scanlist_print();
puts("");
@ -69,18 +73,19 @@ int main(void)
/* in this example, we want Nimble to scan 'full time', so we set the
* window equal the interval */
struct ble_gap_disc_params scan_params = {
.itvl = BLE_GAP_LIM_DISC_SCAN_INT,
.window = BLE_GAP_LIM_DISC_SCAN_WINDOW,
.filter_policy = 0, /* don't use */
.limited = 0, /* no limited discovery */
.passive = 0, /* no passive scanning */
. filter_duplicates = 0, /* no duplicate filtering */
nimble_scanner_cfg_t params = {
.itvl_ms = DEFAULT_SCAN_INTERVAL_MS,
.win_ms = DEFAULT_SCAN_INTERVAL_MS,
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
.flags = NIMBLE_SCANNER_PHY_1M | NIMBLE_SCANNER_PHY_CODED,
#else
.flags = NIMBLE_SCANNER_PHY_1M,
#endif
};
/* initialize the nimble scanner */
nimble_scanlist_init();
nimble_scanner_init(&scan_params, nimble_scanlist_update);
nimble_scanner_init(&params, nimble_scanlist_update);
/* start shell */
char line_buf[SHELL_DEFAULT_BUFSIZE];

View File

@ -105,7 +105,10 @@ PSEUDOMODULES += netstats_neighbor_tx_time
PSEUDOMODULES += netstats_ipv6
PSEUDOMODULES += netstats_rpl
PSEUDOMODULES += nimble
PSEUDOMODULES += nimble_adv_ext
PSEUDOMODULES += nimble_autoconn_%
PSEUDOMODULES += nimble_phy_coded
PSEUDOMODULES += nimble_phy_2mbit
PSEUDOMODULES += newlib
PSEUDOMODULES += newlib_gnu_source
PSEUDOMODULES += newlib_nano

View File

@ -1,6 +1,6 @@
PKG_NAME = nimble
PKG_URL = https://github.com/apache/mynewt-nimble.git
PKG_VERSION = 6c9f70972e8c68efe1fd38d413778c9487c5d997
PKG_VERSION = bc142016bdef082ba7997aea09aec1c1e4db0104
PKG_LICENSE = Apache-2.0
include $(RIOTBASE)/pkg/pkg.mk
@ -23,7 +23,7 @@ else
CFLAGS += -Wno-unused-but-set-variable
endif
IGNORE := nimble_autoconn_%
IGNORE := nimble_autoconn_% nimble_phy_% nimble_adv_ext
SUBMODS := $(filter-out $(IGNORE),$(filter nimble_%,$(USEMODULE)))
.PHONY: all

View File

@ -67,6 +67,18 @@ ifneq (,$(filter nimble_autoconn,$(USEMODULE)))
USEMODULE += bluetil_ad
endif
ifneq (,$(filter nimble_phy_%,$(USEMODULE)))
USEMODULE += nimble_adv_ext
endif
ifneq (,$(filter nimble_phy_2mbit,$(USEMODULE)))
FEATURES_REQUIRED += ble_phy_2mbit
endif
ifneq (,$(filter nimble_phy_coded,$(USEMODULE)))
FEATURES_REQUIRED += ble_phy_coded
endif
ifneq (,$(filter nimble_rpble,$(USEMODULE)))
USEMODULE += gnrc_rpl
USEMODULE += nimble_netif

View File

@ -77,12 +77,35 @@ endif
ifneq (,$(filter nimble_addr,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/addr/include
endif
ifneq (,$(filter nimble_autoadv,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/autoadv/include
endif
ifneq (,$(filter nimble_autoconn,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/autoconn/include
endif
ifneq (,$(filter nimble_adv_ext,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_EXT_ADV=1
CFLAGS += -DMYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT=2
ifneq (,$(filter nimble_controller,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV=1
endif
endif
ifneq (,$(filter nimble_phy_2mbit,$(USEMODULE)))
ifneq (,$(filter nimble_controller,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY=1
endif
endif
ifneq (,$(filter nimble_phy_coded,$(USEMODULE)))
ifneq (,$(filter nimble_controller,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY=1
endif
endif
ifneq (,$(filter nimble_netif,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/netif/include
@ -113,15 +136,19 @@ ifneq (,$(filter nimble_netif,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT=1
endif
endif
ifneq (,$(filter nimble_rpble,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/rpble/include
endif
ifneq (,$(filter nimble_scanlist,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/scanlist/include
endif
ifneq (,$(filter nimble_scanner,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/scanner/include
endif
ifneq (,$(filter nimble_statconn,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/statconn/include
endif

View File

@ -131,10 +131,11 @@ static int _filter_uuid(const bluetil_ad_t *ad)
return 0;
}
static void _on_scan_evt(uint8_t type, const ble_addr_t *addr, int8_t rssi,
static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
const uint8_t *ad_buf, size_t ad_len)
{
(void)rssi;
(void)info;
/* we are only interested in ADV_IND packets, the rest can be dropped right
* away */
@ -296,13 +297,10 @@ int nimble_autoconn_update(const nimble_autoconn_params_t *params,
conn_update_params.max_ce_len = 0;
/* calculate the used scan parameters */
struct ble_gap_disc_params scan_params;
scan_params.itvl = BLE_GAP_SCAN_ITVL_MS(params->scan_itvl);
scan_params.window = BLE_GAP_SCAN_WIN_MS(params->scan_win);
scan_params.filter_policy = 0;
scan_params.limited = 0;
scan_params.passive = 0;
scan_params.filter_duplicates = 1;
nimble_scanner_cfg_t scan_params;
scan_params.itvl_ms = params->scan_itvl;
scan_params.win_ms = params->scan_win;
scan_params.flags = NIMBLE_SCANNER_FILTER_DUPS;
/* set the advertising parameters used */
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;

View File

@ -288,24 +288,6 @@ int nimble_netif_update(int handle,
*/
int nimble_netif_used_chanmap(int handle, uint8_t map[5]);
/**
* @brief Trigger a L2CAP ping procedure for the specified connection
*
* This is a convenience wrapper around the NimBLE ble_l2cap_ping() function.
*
* @param[in] handle connection handle
* @param[in] cb callback triggered when the PING_RSP is received,
* executed in the NimBLE host thread context
* @param[in] data payload included in the PING_REQ and PING_RSP
* messages
* @param[in] data_len length of @p data in bytes
*
* @return 0 on success
* @return <0 on error
*/
int nimble_netif_l2cap_ping(int handle, ble_l2cap_ping_fn cb,
const void *data, uint16_t data_len);
#ifdef __cplusplus
}
#endif

View File

@ -740,13 +740,3 @@ int nimble_netif_used_chanmap(int handle, uint8_t map[5])
return 0;
}
int nimble_netif_l2cap_ping(int handle, ble_l2cap_ping_fn cb,
const void *data, uint16_t data_len)
{
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
if (conn == NULL) {
return -1;
}
return ble_l2cap_ping(conn->gaphandle, cb, data, data_len);
}

View File

@ -25,6 +25,10 @@
#include "os/os.h"
#include "mcu/mcu.h"
#if defined(CPU_FAM_NRF51) || defined(CPU_FAM_NRF52)
#include "nrf_clock.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -564,6 +568,22 @@ static inline void ble_npl_hw_set_isr(int irqn, void (*addr)(void))
nrf5x_hw_set_isr(irqn, addr);
}
/* XXX: these functions are required to build hal_timer.c, however with the
* default configuration they are never used... */
#if defined(CPU_FAM_NRF51) || defined(CPU_FAM_NRF52)
static inline void
nrf52_clock_hfxo_request(void)
{
clock_hfxo_request();
}
static inline void
nrf52_clock_hfxo_release(void)
{
clock_hfxo_release();
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -111,11 +111,12 @@ static void _children_accept(void)
assert(res == 0);
}
static void _on_scan_evt(uint8_t type,
const ble_addr_t *addr, int8_t rssi,
static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
const uint8_t *ad, size_t ad_len)
{
int res;
(void)info;
/* filter out all non-connectible advertisements */
if (type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND) {
@ -300,11 +301,10 @@ int nimble_rpble_param_update(const nimble_rpble_cfg_t *cfg)
nimble_netif_eventcb(_on_netif_evt);
/* configure scanner */
struct ble_gap_disc_params scan_params = { 0 };
scan_params.itvl = BLE_GAP_SCAN_ITVL_MS(cfg->scan_itvl_ms);
scan_params.window = BLE_GAP_SCAN_WIN_MS(cfg->scan_win_ms);
scan_params.passive = 1;
scan_params.filter_duplicates = 1;
nimble_scanner_cfg_t scan_params = { 0 };
scan_params.itvl_ms = cfg->scan_itvl_ms;
scan_params.win_ms = cfg->scan_win_ms;
scan_params.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_FILTER_DUPS);
nimble_scanner_init(&scan_params, _on_scan_evt);
/* start to look for parents */

View File

@ -28,6 +28,7 @@
#include "clist.h"
#include "net/ble.h"
#include "nimble/ble.h"
#include "nimble_scanner.h"
#ifdef __cplusplus
extern "C" {
@ -53,6 +54,8 @@ typedef struct {
uint32_t first_update; /**< first packet timestamp */
uint32_t last_update; /**< last packet timestamp */
uint8_t type; /**< advertising packet type */
uint8_t phy_pri; /**< primary PHY used */
uint8_t phy_sec; /**< secondary PHY advertised */
} nimble_scanlist_entry_t;
/**
@ -67,11 +70,12 @@ void nimble_scanlist_init(void);
*
* @param[in] type type of the advertising packet received
* @param[in] addr BLE address of the scanned node
* @param[in] rssi RSSI of the received advertising packet
* @param[in] info Additional information on received advertising event
* @param[in] ad the payload of the advertising packet
* @param[in] len length of @p ad
*/
void nimble_scanlist_update(uint8_t type, const ble_addr_t *addr, int8_t rssi,
void nimble_scanlist_update(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
const uint8_t *ad, size_t len);
/**

View File

@ -66,7 +66,8 @@ nimble_scanlist_entry_t *nimble_scanlist_get_by_pos(unsigned pos)
return e;
}
void nimble_scanlist_update(uint8_t type, const ble_addr_t *addr, int8_t rssi,
void nimble_scanlist_update(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
const uint8_t *ad, size_t len)
{
assert(addr);
@ -86,10 +87,12 @@ void nimble_scanlist_update(uint8_t type, const ble_addr_t *addr, int8_t rssi,
memcpy(e->ad, ad, len);
}
e->ad_len = len;
e->last_rssi = rssi;
e->last_rssi = info->rssi;
e->first_update = now;
e->adv_msg_cnt = 1;
e->type = type;
e->phy_pri = info->phy_pri;
e->phy_sec = info->phy_sec;
clist_rpush(&_list, (clist_node_t *)e);
}
else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
* Copyright (C) 2019-2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -27,8 +27,30 @@
#include "nimble_scanlist.h"
#include "nimble/hci_common.h"
static const char *_phys[] = { "N/A", "1M", "2M", "CODED" };
static void _print_type(uint8_t type)
{
#if MYNEWT_VAL_BLE_EXT_ADV
if (type & NIMBLE_SCANNER_EXT_ADV) {
printf(" [EXT");
if (type & BLE_HCI_ADV_CONN_MASK) {
printf("-CONN");
}
if (type & BLE_HCI_ADV_SCAN_MASK) {
printf("-SCAN");
}
if (type & BLE_HCI_ADV_DIRECT_MASK) {
printf("-DIR");
}
if (type & BLE_HCI_ADV_SCAN_RSP_MASK) {
printf("-SCANRSP");
}
printf("]");
return;
}
#endif
switch (type) {
case BLE_HCI_ADV_RPT_EVTYPE_ADV_IND:
printf(" [IND]");
@ -80,6 +102,7 @@ void nimble_scanlist_print_entry(nimble_scanlist_entry_t *e)
nimble_addr_print(&e->addr);
_print_type(e->type);
printf(" phy:%s-%s", _phys[e->phy_pri], _phys[e->phy_sec]);
unsigned adv_int = ((e->last_update - e->first_update) / e->adv_msg_cnt);
printf(" \"%s\", adv_msg_cnt: %u, adv_int: %uus, last_rssi: %i\n",
name, (unsigned)e->adv_msg_cnt, adv_int, (int)e->last_rssi);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
* Copyright (C) 2019-2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -31,31 +31,100 @@
extern "C" {
#endif
/**
* @brief Flag to mark type for extended advertisements
*/
#define NIMBLE_SCANNER_EXT_ADV 0x80
/**
* @brief Scan procedure configuration flags
*/
enum {
NIMBLE_SCANNER_PASSIVE = 0x01, /**< do a passive scan */
NIMBLE_SCANNER_LIMITED = 0x02, /**< do limited discovery */
NIMBLE_SCANNER_FILTER_DUPS = 0x04, /**< filter duplicates */
NIMBLE_SCANNER_PHY_1M = 0x10, /**< scan on 1Mbit PHY */
NIMBLE_SCANNER_PHY_CODED = 0x20, /**< scan on CODED PHY */
};
/**
* @brief Status flags for received advertising packets
*/
enum {
/**
* All fragments of a advertising message were received
*/
NIMBLE_SCANNER_COMPLETE = BLE_HCI_ADV_DATA_STATUS_COMPLETE,
/**
* The advertising message is incomplete
*/
NIMBLE_SCANNER_INCOMPLETE = BLE_HCI_ADV_DATA_STATUS_INCOMPLETE,
/**
* Advertising message is truncated
*/
NIMBLE_SCANNER_TRUNCATED = BLE_HCI_ADV_DATA_STATUS_TRUNCATED,
};
/**
* @brief Scanner configuration parameters
*/
typedef struct {
uint16_t itvl_ms; /**< scan interval [ms] */
uint16_t win_ms; /**< scan window [ms] */
uint8_t flags; /**< scan configuration flags */
} nimble_scanner_cfg_t;
/**
* @brief Additional information about received advertising packets
*/
typedef struct {
/**
* Status of received packet. Possible values:
* - NIMBLE_SCANNER_COMPLETE
* - NIMBLE_SCANNER_INCOMPLETE
* - NIMBLE_SCANNER_TRUNCATED
*/
uint8_t status;
uint8_t phy_pri; /**< PHY used on primary advertisement channels */
uint8_t phy_sec; /**< PHY used on secondary advertisement channels */
int8_t rssi; /**< RSSI value of received advertisement */
} nimble_scanner_info_t;
/**
* @brief Callback signature triggered by this module for each discovered
* advertising packet
*
* @param[in] type type of advertising packet, e.g
* BLE_HCI_ADV_RPT_EVTYPE_ADV_IND
* @param[in] type type of advertising packet.
* For legacy advertisements on of the following:
* - BLE_HCI_ADV_RPT_EVTYPE_ADV_IND
* - BLE_HCI_ADV_RPT_EVTYPE_DIR_IND
* - BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND
* - BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND
* - BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP
* For extended advertisements NIMBLE_SCANNER_EXT_ADV ORed
* with any set out of the following:
* - BLE_HCI_ADV_CONN_MASK
* - BLE_HCI_ADV_SCAN_MASK
* - BLE_HCI_ADV_DIRECT_MASK
* - BLE_HCI_ADV_SCAN_RSP_MASK
* @param[in] addr advertising address of the source node
* @param[in] rssi RSSI value for the received packet
* @param[in] info additional information about the advertiser
* @param[in] ad advertising data
* @param[in] ad_len length of @p ad in bytes
*/
typedef void(*nimble_scanner_cb)(uint8_t type,
const ble_addr_t *addr, int8_t rssi,
typedef void(*nimble_scanner_cb)(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
const uint8_t *ad, size_t ad_len);
/**
* @brief Initialize the scanner module
*
* @param[in] params scan parameters to use, pass NULL to use NimBLE's
* default parameters
* @param[in] params scan parameters to use
* @param[in] disc_cb callback triggered of each received advertising packet
*
* @return 0 on success
*/
int nimble_scanner_init(const struct ble_gap_disc_params *params,
int nimble_scanner_init(const nimble_scanner_cfg_t *params,
nimble_scanner_cb disc_cb);
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
* Copyright (C) 2019-2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -30,22 +30,60 @@
#include "debug.h"
static nimble_scanner_cb _disc_cb = NULL;
#if MYNEWT_VAL_BLE_EXT_ADV
static struct ble_gap_ext_disc_params _scan_params = { 0 };
static uint8_t _scan_flags = 0;
#else
static struct ble_gap_disc_params _scan_params = { 0 };
#endif
/* duration of the scanning procedure */
static int32_t _scan_duration = BLE_HS_FOREVER;
static int _on_scan_evt(struct ble_gap_event *event, void *arg)
{
/* only interested in the DISC event */
if (event->type == BLE_GAP_EVENT_DISC) {
_disc_cb(event->disc.event_type, &event->disc.addr, event->disc.rssi,
switch (event->type) {
#if MYNEWT_VAL_BLE_EXT_ADV
case BLE_GAP_EVENT_EXT_DISC: {
uint8_t type;
nimble_scanner_info_t info;
info.rssi = event->ext_disc.rssi;
if (event->ext_disc.props & BLE_HCI_ADV_LEGACY_MASK) {
type = event->ext_disc.legacy_event_type;
info.status = NIMBLE_SCANNER_COMPLETE;
info.phy_pri = BLE_HCI_LE_PHY_1M;
info.phy_sec = BLE_HCI_LE_PHY_1M;
}
else {
type = (event->ext_disc.props | NIMBLE_SCANNER_EXT_ADV);
info.status = event->ext_disc.data_status;
info.phy_pri = event->ext_disc.prim_phy;
info.phy_sec = event->ext_disc.sec_phy;
}
_disc_cb(type, &event->ext_disc.addr, &info,
event->ext_disc.data, event->ext_disc.length_data);
break;
}
#else
case BLE_GAP_EVENT_DISC: {
nimble_scanner_info_t info = {
.status = NIMBLE_SCANNER_COMPLETE,
.phy_pri = BLE_HCI_LE_PHY_1M,
.phy_sec = BLE_HCI_LE_PHY_1M,
.rssi = event->disc.rssi,
};
_disc_cb(event->disc.event_type, &event->disc.addr, &info,
event->disc.data, (size_t)event->disc.length_data);
break;
}
else if (event->type == BLE_GAP_EVENT_DISC_COMPLETE) {
#endif
case BLE_GAP_EVENT_DISC_COMPLETE:
DEBUG("[scanner] scan cycle completed\n");
}
else {
break;
default:
/* this should never happen */
DEBUG("[scanner] unknown event triggered (%i)\n", (int)event->type);
assert(0);
@ -57,8 +95,23 @@ static int _on_scan_evt(struct ble_gap_event *event, void *arg)
int nimble_scanner_start(void)
{
if (ble_gap_disc_active() == 0) {
int res = ble_gap_disc(nimble_riot_own_addr_type, _scan_duration,
#if MYNEWT_VAL_BLE_EXT_ADV
uint8_t dups = (_scan_flags & NIMBLE_SCANNER_FILTER_DUPS) ? 1 : 0;
uint8_t limited = (_scan_flags & NIMBLE_SCANNER_LIMITED) ? 1 : 0;
const struct ble_gap_ext_disc_params *uncoded =
(_scan_flags & NIMBLE_SCANNER_PHY_1M) ? &_scan_params : NULL;
const struct ble_gap_ext_disc_params *coded =
(_scan_flags & NIMBLE_SCANNER_PHY_CODED) ? &_scan_params : NULL;
int res = ble_gap_ext_disc(nimble_riot_own_addr_type,
_scan_duration / 10, 0, dups,
BLE_HCI_SCAN_FILT_NO_WL, limited,
uncoded, coded,
_on_scan_evt, NULL);
#else
int res = ble_gap_disc(nimble_riot_own_addr_type, 0,
&_scan_params, _on_scan_evt, NULL);
#endif
if (res != 0) {
DEBUG("[scanner] err: start failed (%i)\n", res);
return -ECANCELED;
@ -87,17 +140,23 @@ void nimble_scanner_set_scan_duration(int32_t duration_ms)
}
}
int nimble_scanner_init(const struct ble_gap_disc_params *params,
int nimble_scanner_init(const nimble_scanner_cfg_t *params,
nimble_scanner_cb disc_cb)
{
assert(params);
assert(disc_cb);
if (params) {
memcpy(&_scan_params, params, sizeof(_scan_params));
}
else {
memset(&_scan_params, 0, sizeof(_scan_params));
}
_scan_params.itvl = BLE_GAP_SCAN_ITVL_MS(params->itvl_ms);
_scan_params.window = BLE_GAP_SCAN_WIN_MS(params->win_ms);
_scan_params.passive = (params->flags & NIMBLE_SCANNER_PASSIVE) ? 1 : 0;
#if MYNEWT_VAL_BLE_EXT_ADV
_scan_flags = params->flags;
#else
_scan_params.limited = (params->flags & NIMBLE_SCANNER_LIMITED) ? 1 : 0;
_scan_params.filter_duplicates =
(params->flags & NIMBLE_SCANNER_FILTER_DUPS) ? 1 : 0;
#endif
_disc_cb = disc_cb;
return 0;

View File

@ -42,11 +42,12 @@
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
static const char *_name_to_connect = NULL;
static void _scan_for_name(uint8_t type, const ble_addr_t *addr, int8_t rssi,
static void _scan_for_name(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
const uint8_t *ad, size_t ad_len)
{
(void)type;
(void)rssi;
(void)info;
int res;
bluetil_ad_t adstruct;
@ -398,13 +399,6 @@ static void _cmd_update(int handle, int itvl, int timeout)
}
}
static void _on_echo_rsp(uint16_t gap_handle, uint32_t rtt, struct os_mbuf *om)
{
int handle = nimble_netif_conn_get_by_gaphandle(gap_handle);
printf("ECHO_RSP handle:%i rtt:%u size:%u\n",
handle, (unsigned)rtt, (unsigned)OS_MBUF_PKTLEN(om));
}
static int _ishelp(char *argv)
{
return memcmp(argv, "help", 4) == 0;
@ -425,9 +419,9 @@ int _nimble_netif_handler(int argc, char **argv)
{
if ((argc == 1) || _ishelp(argv[1])) {
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
printf("usage: %s [help|info|adv|scan|connect|close|update|chanmap|ping]\n", argv[0]);
printf("usage: %s [help|info|adv|scan|connect|close|update|chanmap]\n", argv[0]);
#else
printf("usage: %s [help|info|close|update|chanmap|ping]\n", argv[0]);
printf("usage: %s [help|info|close|update|chanmap]\n", argv[0]);
#endif
return 0;
}
@ -550,21 +544,6 @@ int _nimble_netif_handler(int argc, char **argv)
}
return 0;
}
else if ((memcmp(argv[1], "ping", 4) == 0)) {
if ((argc < 3) || _ishelp(argv[2])) {
printf("usage: %s %s <handle>\n", argv[0], argv[1]);
return 0;
}
int handle = atoi(argv[2]);
char *data = (argc > 3) ? argv[3] : NULL;
uint16_t data_len = (data != NULL) ? (uint16_t)strlen(data) : 0;
int res = nimble_netif_l2cap_ping(handle, _on_echo_rsp, data, data_len);
if (res != 0) {
printf("err: unable to send ping (%i)\n", res);
}
}
else {
printf("unable to parse the command. Use '%s help' for more help\n",
argv[0]);

View File

@ -0,0 +1,25 @@
BOARD ?= nrf52840dk
include ../Makefile.tests_common
# we want shell support
USEMODULE += shell
USEMODULE += shell_commands
# setup NimBLE specific modules
USEMODULE += nimble_scanner
USEMODULE += nimble_scanlist
USEMODULE += nimble_adv_ext
USEMODULE += nimble_phy_2mbit
ifneq (,$(filter nrf52840dk nrf52840dongle,$(BOARD)))
USEMODULE += nimble_phy_coded
endif
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for build testing NimBLE extended advertising
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "timex.h"
#include "ztimer.h"
#include "shell.h"
#include "shell_commands.h"
#include "nimble_scanner.h"
#include "nimble_scanlist.h"
/* default scan interval */
#define DEFAULT_SCAN_INTERVAL_MS 30
/* default scan duration (1s) */
#define DEFAULT_DURATION_MS (1 * MS_PER_SEC)
int _cmd_scan(int argc, char **argv)
{
uint32_t timeout = DEFAULT_DURATION_MS;
if ((argc == 2) && (memcmp(argv[1], "help", 4) == 0)) {
printf("usage: %s [timeout in ms]\n", argv[0]);
return 0;
}
if (argc >= 2) {
timeout = atoi(argv[1]);
}
nimble_scanlist_clear();
printf("Scanning for %"PRIu32" ms now ...\n", timeout);
nimble_scanner_start();
ztimer_sleep(ZTIMER_MSEC, timeout);
nimble_scanner_stop();
puts("Done, results:");
nimble_scanlist_print();
puts("");
return 0;
}
static const shell_command_t _commands[] = {
{ "scan", "trigger a BLE scan", _cmd_scan },
{ NULL, NULL, NULL }
};
int main(void)
{
puts("NimBLE Scanner Example Application");
puts("Type `scan help` for more information");
/* in this example, we want Nimble to scan 'full time', so we set the
* window equal the interval */
nimble_scanner_cfg_t params = {
.itvl_ms = DEFAULT_SCAN_INTERVAL_MS,
.win_ms = DEFAULT_SCAN_INTERVAL_MS,
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
.flags = NIMBLE_SCANNER_PHY_1M | NIMBLE_SCANNER_PHY_CODED,
#else
.flags = NIMBLE_SCANNER_PHY_1M,
#endif
};
/* initialize the nimble scanner */
nimble_scanlist_init();
nimble_scanner_init(&params, nimble_scanlist_update);
/* start shell */
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}