1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-24 22:13:52 +01:00

Merge pull request #16860 from haukepetersen/add_nimble_netifextadv

nimble/netif: add support for BT5 PHY modes
This commit is contained in:
Francisco 2022-02-04 11:16:11 +01:00 committed by GitHub
commit dbae3ed706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1222 additions and 387 deletions

View File

@ -154,8 +154,11 @@ PSEUDOMODULES += netstats_rpl
PSEUDOMODULES += nimble
PSEUDOMODULES += nimble_adv_ext
PSEUDOMODULES += nimble_autoconn_%
PSEUDOMODULES += nimble_netif_ext
PSEUDOMODULES += nimble_phy_coded
PSEUDOMODULES += nimble_phy_2mbit
PSEUDOMODULES += nimble_rpble_ext
PSEUDOMODULES += nimble_statconn_ext
PSEUDOMODULES += newlib
PSEUDOMODULES += newlib_gnu_source
PSEUDOMODULES += newlib_nano

View File

@ -23,7 +23,7 @@ else
CFLAGS += -Wno-unused-but-set-variable
endif
IGNORE := nimble_autoconn_% nimble_phy_% nimble_adv_ext
IGNORE := nimble_autoconn_% nimble_phy_% nimble_%_ext
SUBMODS := $(filter-out $(IGNORE),$(filter nimble_%,$(USEMODULE)))
.PHONY: all

View File

@ -12,6 +12,15 @@ USEMODULE += nimble_riot_contrib
# RIOT port
USEMODULE += nimble_porting_nimble
# Pull in dependencies based on used features
ifneq (,$(filter ble_phy_coded,$(FEATURES_USED)))
USEMODULE += nimble_phy_coded
endif
ifneq (,$(filter ble_phy_2mbit,$(FEATURES_USED)))
USEMODULE += nimble_phy_2mbit
endif
# NOTE: this dependency depends on inclusion order, for it to work properly
# mynewt-core should be selected as nimble backend as early as possible,
# i.e. at the application level.
@ -56,6 +65,10 @@ ifneq (,$(filter nimble_autoadv,$(USEMODULE)))
USEMODULE += bluetil_ad
endif
ifneq (,$(filter nimble_autoconn_ext,$(USEMODULE)))
USEMODULE += nimble_netif_ext
endif
ifneq (,$(filter nimble_autoconn_%,$(USEMODULE)))
USEMODULE += nimble_autoconn
endif
@ -67,10 +80,6 @@ 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
@ -79,6 +88,11 @@ ifneq (,$(filter nimble_phy_coded,$(USEMODULE)))
FEATURES_REQUIRED += ble_phy_coded
endif
ifneq (,$(filter nimble_rpble_ext,$(USEMODULE)))
USEMODULE += nimble_rpble
USEMODULE += nimble_netif_ext
endif
ifneq (,$(filter nimble_rpble,$(USEMODULE)))
USEMODULE += gnrc_rpl
USEMODULE += nimble_netif
@ -92,12 +106,22 @@ ifneq (,$(filter nimble_scanlist,$(USEMODULE)))
USEMODULE += ztimer_usec
endif
ifneq (,$(filter nimble_statconn_ext,$(USEMODULE)))
USEMODULE += nimble_statconn
USEMODULE += nimble_netif_ext
endif
ifneq (,$(filter nimble_statconn,$(USEMODULE)))
USEMODULE += random
USEMODULE += nimble_netif
USEMODULE += nimble_addr
endif
ifneq (,$(filter nimble_netif_ext,$(USEMODULE)))
USEMODULE += nimble_netif
USEMODULE += nimble_adv_ext
endif
ifneq (,$(filter nimble_netif,$(USEMODULE)))
FEATURES_REQUIRED += ble_nimble_netif
USEMODULE += random

View File

@ -26,6 +26,14 @@ ifneq (,$(filter nimble_controller,$(USEMODULE)))
ifneq (,$(filter nimble_drivers_nrf5x,$(USEMODULE)))
INCLUDES += $(NIMIBASE)/nimble/drivers/$(CPU_FAM)/include
endif
# Enable additional PHY modes if requested by the build
ifneq (,$(filter ble_phy_2mbit,$(FEATURES_USED)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY=1
endif
ifneq (,$(filter ble_phy_coded,$(FEATURES_USED)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY=1
endif
endif
# include nimble host headers
@ -94,18 +102,6 @@ ifneq (,$(filter nimble_adv_ext,$(USEMODULE)))
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

View File

@ -131,29 +131,31 @@ enum {
*/
typedef struct {
/** amount of time spend in scanning mode [in ms] */
uint32_t period_scan;
uint32_t period_scan_ms;
/** amount of time spend in advertising mode [in ms] */
uint32_t period_adv;
uint32_t period_adv_ms;
/** a random value from 0 to this value is added to the duration of each
* scanning and advertising period [in ms] */
uint32_t period_jitter;
uint32_t period_jitter_ms;
/** advertising interval used when in advertising mode [in ms] */
uint32_t adv_itvl;
uint32_t adv_itvl_ms;
/** scan interval applied while in scanning state [in ms] */
uint32_t scan_itvl;
uint32_t scan_itvl_ms;
/** scan window applied while in scanning state [in ms] */
uint32_t scan_win;
uint32_t scan_win_ms;
/** opening a new connection is aborted after this time [in ms] */
uint32_t conn_timeout;
uint32_t conn_timeout_ms;
/** connection interval used when opening a new connection, lower bound.
* [in ms] */
uint32_t conn_itvl_min;
uint32_t conn_itvl_min_ms;
/** connection interval, upper bound [in ms] */
uint32_t conn_itvl_max;
/** slave latency used for new connections [in ms] */
uint32_t conn_itvl_max_ms;
/** slave latency used for new connections */
uint16_t conn_latency;
/** supervision timeout used for new connections [in ms] */
uint32_t conn_super_to;
uint32_t conn_super_to_ms;
/** BLE PHY mode to use */
nimble_phy_t phy_mode;
/** node ID included in the advertising data, may be NULL */
const char *node_id;
} nimble_autoconn_params_t;

View File

@ -64,24 +64,32 @@ extern "C" {
#define NIMBLE_AUTOCONN_CONN_SVTO_MS (2500U) /* 2.5s */
#endif
/**
* @brief Default BLE PHY mode used by autoconn
*/
#ifndef NIMBLE_AUTOCONN_PHY_MODE
#define NIMBLE_AUTOCONN_PHY_MODE NIMBLE_PHY_1M
#endif
#ifndef NIMBLE_AUTOCONN_NODE_ID
#define NIMBLE_AUTOCONN_NODE_ID "RIOT-autoconn"
#endif
#ifndef NIMBLE_AUTOCONN_PARAMS
#define NIMBLE_AUTOCONN_PARAMS \
{ .period_scan = NIMBLE_AUTOCONN_PERIOD_SCAN_MS, \
.period_adv = NIMBLE_AUTOCONN_PERIOD_ADV_MS, \
.period_jitter = NIMBLE_AUTOCONN_PERIOD_JITTER_MS, \
.adv_itvl = NIMBLE_AUTOCONN_ADV_ITVL_MS, \
.scan_itvl = NIMBLE_AUTOCONN_SCAN_ITVL_MS, \
.scan_win = NIMBLE_AUTOCONN_SCAN_WIN_MS, \
.conn_timeout = NIMBLE_AUTOCONN_CONN_TIMEOUT_MS, \
.conn_itvl_min = NIMBLE_AUTOCONN_CONN_ITVL_MIN_MS, \
.conn_itvl_max = NIMBLE_AUTOCONN_CONN_ITVL_MAX_MS, \
.conn_latency = NIMBLE_AUTOCONN_CONN_LATENCY, \
.conn_super_to = NIMBLE_AUTOCONN_CONN_SVTO_MS, \
.node_id = NIMBLE_AUTOCONN_NODE_ID, }
{ .period_scan_ms = NIMBLE_AUTOCONN_PERIOD_SCAN_MS, \
.period_adv_ms = NIMBLE_AUTOCONN_PERIOD_ADV_MS, \
.period_jitter_ms = NIMBLE_AUTOCONN_PERIOD_JITTER_MS, \
.adv_itvl_ms = NIMBLE_AUTOCONN_ADV_ITVL_MS, \
.scan_itvl_ms = NIMBLE_AUTOCONN_SCAN_ITVL_MS, \
.scan_win_ms = NIMBLE_AUTOCONN_SCAN_WIN_MS, \
.conn_timeout_ms = NIMBLE_AUTOCONN_CONN_TIMEOUT_MS, \
.conn_itvl_min_ms = NIMBLE_AUTOCONN_CONN_ITVL_MIN_MS, \
.conn_itvl_max_ms = NIMBLE_AUTOCONN_CONN_ITVL_MAX_MS, \
.conn_latency = NIMBLE_AUTOCONN_CONN_LATENCY, \
.conn_super_to_ms = NIMBLE_AUTOCONN_CONN_SVTO_MS, \
.phy_mode = NIMBLE_AUTOCONN_PHY_MODE, \
.node_id = NIMBLE_AUTOCONN_NODE_ID, }
#endif
/**@}*/

View File

@ -55,9 +55,8 @@ static volatile uint8_t _enabled = 0;
static bluetil_ad_t _ad;
static uint8_t _ad_buf[BLE_HS_ADV_MAX_SZ];
static struct ble_gap_adv_params _adv_params;
static struct ble_gap_conn_params _conn_params;
static uint32_t _conn_timeout;
static nimble_netif_accept_cfg_t _accept_params;
static nimble_netif_connect_cfg_t _conn_params;
static struct ble_npl_callout _state_evt;
static ble_npl_time_t _timeout_adv_period;
@ -77,7 +76,7 @@ static void _on_state_change(struct ble_npl_event *ev)
/* stop scanning */
nimble_scanner_stop();
/* start advertising/accepting */
int res = nimble_netif_accept(_ad.buf, _ad.pos, &_adv_params);
int res = nimble_netif_accept(_ad.buf, _ad.pos, &_accept_params);
assert((res == 0) || (res == -ENOMEM));
(void)res;
@ -137,11 +136,18 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
{
(void)info;
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
if ((type != (NIMBLE_SCANNER_EXT_ADV | BLE_HCI_ADV_CONN_MASK)) ||
(info->status != BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE)) {
return;
}
#else
/* we are only interested in ADV_IND packets, the rest can be dropped right
* away */
if (type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND) {
return;
}
#endif
bluetil_ad_t ad = {
.buf = (uint8_t *)ad_buf,
@ -157,7 +163,7 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
nimble_scanner_stop();
DEBUG("[autoconn] SCAN success, initiating connection\n");
_state = STATE_CONN;
int res = nimble_netif_connect(addr, &_conn_params, _conn_timeout);
int res = nimble_netif_connect(addr, &_conn_params);
assert(res >= 0);
(void)res;
}
@ -271,47 +277,66 @@ int nimble_autoconn_update(const nimble_autoconn_params_t *params,
}
/* scan and advertising period configuration */
ble_npl_time_ms_to_ticks(params->period_adv, &_timeout_adv_period);
ble_npl_time_ms_to_ticks(params->period_scan, &_timeout_scan_period);
ble_npl_time_ms_to_ticks(params->period_jitter, &_period_jitter);
ble_npl_time_ms_to_ticks(params->period_adv_ms, &_timeout_adv_period);
ble_npl_time_ms_to_ticks(params->period_scan_ms, &_timeout_scan_period);
ble_npl_time_ms_to_ticks(params->period_jitter_ms, &_period_jitter);
/* populate the connection parameters */
_conn_params.scan_itvl = BLE_GAP_SCAN_ITVL_MS(params->scan_win);
_conn_params.scan_window = _conn_params.scan_itvl;
_conn_params.itvl_min = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_min);
_conn_params.itvl_max = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_max);
_conn_params.latency = 0;
_conn_params.supervision_timeout = BLE_GAP_SUPERVISION_TIMEOUT_MS(
params->conn_super_to);
_conn_params.min_ce_len = 0;
_conn_params.max_ce_len = 0;
_conn_timeout = params->conn_timeout;
memset(&_conn_params, 0, sizeof(_conn_params));
_conn_params.scan_itvl_ms = params->scan_itvl_ms;
_conn_params.scan_window_ms = params->scan_win_ms;
_conn_params.conn_itvl_min_ms = params->conn_itvl_min_ms;
_conn_params.conn_itvl_max_ms = params->conn_itvl_max_ms;
_conn_params.conn_supervision_timeout_ms = params->conn_super_to_ms;
_conn_params.conn_slave_latency = params->conn_latency;
_conn_params.timeout_ms = params->conn_timeout_ms;
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
_conn_params.phy_mode = params->phy_mode;
#else
_conn_params.phy_mode = NIMBLE_PHY_1M;
#endif
_conn_params.own_addr_type = nimble_riot_own_addr_type;
/* we use the same values to updated existing connections */
struct ble_gap_upd_params conn_update_params;
conn_update_params.itvl_min = _conn_params.itvl_min;
conn_update_params.itvl_max = _conn_params.itvl_max;
conn_update_params.latency = _conn_params.latency;
conn_update_params.supervision_timeout = _conn_params.supervision_timeout;
conn_update_params.itvl_min = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_min_ms);
conn_update_params.itvl_max = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_max_ms);
conn_update_params.latency = params->conn_latency;
conn_update_params.supervision_timeout =
BLE_GAP_SUPERVISION_TIMEOUT_MS(params->conn_super_to_ms);
conn_update_params.min_ce_len = 0;
conn_update_params.max_ce_len = 0;
/* calculate the used scan parameters */
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_PASSIVE
| NIMBLE_SCANNER_FILTER_DUPS
| NIMBLE_SCANNER_PHY_1M;
scan_params.itvl_ms = params->scan_itvl_ms;
scan_params.win_ms = params->scan_win_ms;
scan_params.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_FILTER_DUPS);
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT) && IS_USED(MODULE_NIMBLE_PHY_CODED)
if (params->phy_mode == NIMBLE_PHY_CODED) {
scan_params.flags |= NIMBLE_SCANNER_PHY_CODED;
}
else {
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
}
#else
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
#endif
/* set the advertising parameters used */
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
_adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
_adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(params->adv_itvl);
_adv_params.itvl_max = _adv_params.itvl_min;
_adv_params.channel_map = 0;
_adv_params.filter_policy = 0;
_adv_params.high_duty_cycle = 0;
memset(&_accept_params, 0, sizeof(_accept_params));
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
_accept_params.flags = 0;
_accept_params.primary_phy = params->phy_mode;
_accept_params.secondary_phy = params->phy_mode;
#else
_accept_params.flags = NIMBLE_NETIF_FLAG_LEGACY;
_accept_params.primary_phy = NIMBLE_PHY_1M;
_accept_params.secondary_phy = NIMBLE_PHY_1M;
#endif
_accept_params.adv_itvl_ms = params->adv_itvl_ms;
_accept_params.timeout_ms = BLE_HS_FOREVER;
_accept_params.own_addr_type = nimble_riot_own_addr_type;
/* initialize the advertising data that will be used */
if (adlen > 0) {

View File

@ -69,6 +69,20 @@ extern "C" {
#define NIMBLE_HOST_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif
/**
* @brief BLE PHY modes
*/
typedef enum {
NIMBLE_PHY_INVALID, /**< PHY mode invalid */
NIMBLE_PHY_1M, /**< legacy 1Mbit PHY mode (always supported) */
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
NIMBLE_PHY_2M, /**< 2Mbit PHY mode */
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
NIMBLE_PHY_CODED, /**< Coded (long range) PHY mode */
#endif
} nimble_phy_t;
/**
* @brief Export our own address type for later usage
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2019 Freie Universität Berlin
* Copyright (C) 2018-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
@ -70,6 +70,7 @@
#include <errno.h>
#include "net/ble.h"
#include "nimble_riot.h"
#include "host/ble_hs.h"
@ -103,6 +104,46 @@ extern "C" {
#define NIMBLE_NETIF_MTU (1280U)
#endif
/**
* @brief Flags for enabling legacy advertisement and high-duty cycle mode
* when accepting incoming connections
*/
enum {
NIMBLE_NETIF_FLAG_LEGACY = 0x01, /**< use legacy advertising mode */
NIMBLE_NETIF_FLAG_HD_MODE = 0x02, /**< use high duty cycle mode, only
* valid for direct advertising */
};
/**
* @brief Parameter set used to configure accepting connections (advertising)
*/
typedef struct {
uint8_t flags; /**< flags */
uint8_t channel_map; /**< specify custom channel map */
uint8_t own_addr_type; /**< specify our own address type to use */
int8_t tx_power; /**< specify TX power to be used */
uint32_t adv_itvl_ms; /**< advertising interval [ms] */
uint32_t timeout_ms; /**< stop accepting after this time [ms] */
nimble_phy_t primary_phy; /**< primary PHY mode */
nimble_phy_t secondary_phy; /**< secondary PHY mode */
} nimble_netif_accept_cfg_t;
/**
* @brief Parameter set used to configure connection initiation
*/
typedef struct {
uint16_t scan_itvl_ms; /**< scan interval [ms] */
uint16_t scan_window_ms; /**< scan window [ms] */
uint16_t conn_itvl_min_ms; /**< connection interval, lower bound [ms] */
uint16_t conn_itvl_max_ms; /**< connection interval, upper bound [ms] */
uint16_t conn_supervision_timeout_ms; /**< supervision timeout [ms] */
uint16_t conn_slave_latency;/**< slave latency */
uint32_t timeout_ms; /**< abort connection initiation after this time
* [ms] */
uint8_t phy_mode; /**< PHY mode used for the connection */
uint8_t own_addr_type; /**< specify our own address type to use */
} nimble_netif_connect_cfg_t;
/**
* @brief Set to > 0 to enforce different connection intervals for each of the
* nodes BLE connections
@ -197,19 +238,18 @@ void nimble_netif_eventcb(nimble_netif_eventcb_t cb);
*
* @param[in] addr address of the advertising BLE slave, in the NimBLE
* addr format (little endian)
* @param[in] conn_params connection (timing) parameters, set to NULL to use
* NimBLEs default parameters
* @param[in] timeout connect timeout [in ms]
* @param[in] cfg connection parameters
*
* @return the used connection handle on success
* @return -EBUSY if already connected to the given address or if
* a connection setup procedure is in progress
* @return -EBUSY if already connected to the given address or if a connection
* setup procedure is in progress
* @return -ENOMEM if no connection context memory is available
* @return -ECANCELED if unable to find valid connection interval
* @return -EINVAL if unable to apply given PHY mode
* @return -EIO on all other NimBLE errors
*/
int nimble_netif_connect(const ble_addr_t *addr,
struct ble_gap_conn_params *conn_params,
uint32_t timeout);
const nimble_netif_connect_cfg_t *cfg);
/**
* @brief Close the connection with the given handle
@ -219,6 +259,7 @@ int nimble_netif_connect(const ble_addr_t *addr,
* @return 0 on success
* @return -EINVAL if the handle is invalid
* @return -ENOTCONN if context for given handle is not connected
* @return -EIO on all other NimBLE errors
*/
int nimble_netif_close(int handle);
@ -227,36 +268,39 @@ int nimble_netif_close(int handle);
*
* @param[in] ad advertising data (in BLE AD format)
* @param[in] ad_len length of @p ad in bytes
* @param[in] adv_params advertising (timing) parameters to use
* @param[in] cfg advertising parameters to use
*
* @return 0 on success
* @return -EALREADY if already advertising
* @return -ENOMEM on insufficient connection memory
* @return -EINVAL on invalid configuration parameters
* @return -ECANCELED on other errors
*/
int nimble_netif_accept(const uint8_t *ad, size_t ad_len,
const struct ble_gap_adv_params *adv_params);
const nimble_netif_accept_cfg_t *cfg);
/**
* @brief Wait for an incoming connection from a specific peer, sending
* directed advertisements (IND_DIR)
* directed advertisements
*
* @param[in] addr BLE address of the target peer
* @param[in] timeout_ms stop advertising after this time (in ms), set to
* BLE_HS_FOREVER to disable timeout
* @param[in] adv_params advertising (timing) parameters to use
* @param[in] cfg advertising parameters to use
*
* @return 0 on success
* @return -EALREADY if already advertising
* @return -ENOMEM on insufficient connection memory
* @return -EINVAL on invalid configuration parameters
* @return -ECANCELED on other errors
*/
int nimble_netif_accept_direct(const ble_addr_t *addr, uint32_t timeout_ms,
const struct ble_gap_adv_params *adv_params);
int nimble_netif_accept_direct(const ble_addr_t *addr,
const nimble_netif_accept_cfg_t *cfg);
/**
* @brief Stop accepting incoming connections (stop advertising)
* *
* @return 0 on success
* @return -EALREADY if not currently advertising
* @return -EIO on other NimBLE errors
*/
int nimble_netif_accept_stop(void);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2019 Freie Universität Berlin
* Copyright (C) 2018-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
@ -55,6 +55,8 @@
#define NIMBLE_NETIF_PRIO GNRC_NETIF_PRIO
#endif
#define EXT_ADV_INST 0
/* thread flag used for signaling transmit readiness */
#define FLAG_TX_UNSTALLED (1u << 13)
#define FLAG_TX_NOTCONN (1u << 12)
@ -543,10 +545,14 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
/* nothing to do here */
break;
case BLE_GAP_EVENT_ADV_COMPLETE: {
uint8_t addr[BLE_ADDR_LEN];
nimble_netif_conn_free(handle, addr);
_notify(handle, NIMBLE_NETIF_ACCEPT_STOP, addr);
if (conn->state == NIMBLE_NETIF_ADV) {
uint8_t addr[BLE_ADDR_LEN];
nimble_netif_conn_free(handle, addr);
_notify(handle, NIMBLE_NETIF_ACCEPT_STOP, addr);
}
}
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE:
break;
default:
break;
}
@ -577,14 +583,10 @@ void nimble_netif_eventcb(nimble_netif_eventcb_t cb)
}
int nimble_netif_connect(const ble_addr_t *addr,
struct ble_gap_conn_params *conn_params,
uint32_t timeout)
const nimble_netif_connect_cfg_t *params)
{
assert(addr);
assert(_eventcb);
uint16_t itvl_min = 0;
uint16_t itvl_max = 0;
assert(params);
/* the netif_conn module expects addresses in network byte order */
uint8_t addrn[BLE_ADDR_LEN];
@ -602,33 +604,63 @@ int nimble_netif_connect(const ble_addr_t *addr,
return -ENOMEM;
}
if ((conn_params != NULL)
&& (conn_params->itvl_min != conn_params->itvl_max)) {
/* we need to save the min/max intervals in order to restore them
* later on */
itvl_min = conn_params->itvl_min;
itvl_max = conn_params->itvl_max;
uint16_t itvl = nimble_netif_conn_gen_itvl(itvl_min, itvl_max);
if (itvl == 0) {
return -ECANCELED;
}
conn_params->itvl_min = itvl;
conn_params->itvl_max = itvl;
/* generate connection interval */
uint16_t itvl = params->conn_itvl_min_ms;
if (params->conn_itvl_min_ms < params->conn_itvl_max_ms) {
itvl = nimble_netif_conn_gen_itvl(params->conn_itvl_min_ms,
params->conn_itvl_max_ms);
}
if (itvl == 0) {
nimble_netif_conn_free(handle, NULL);
return -ECANCELED;
}
int res = ble_gap_connect(nimble_riot_own_addr_type, addr, timeout,
conn_params, _on_gap_master_evt, (void *)handle);
assert(res == 0);
(void)res;
struct ble_gap_conn_params p = {
.scan_itvl = BLE_GAP_SCAN_ITVL_MS(params->scan_itvl_ms),
.scan_window = BLE_GAP_SCAN_WIN_MS(params->scan_window_ms),
.itvl_min = BLE_GAP_CONN_ITVL_MS(itvl),
.itvl_max = BLE_GAP_CONN_ITVL_MS(itvl),
.latency = params->conn_slave_latency,
.supervision_timeout = BLE_GAP_SUPERVISION_TIMEOUT_MS(
params->conn_supervision_timeout_ms),
.min_ce_len = 0,
.max_ce_len = 0,
};
if (itvl_min != itvl_max) {
conn_params->itvl_min = itvl_min;
conn_params->itvl_max = itvl_max;
#if MYNEWT_VAL_BLE_EXT_ADV
uint8_t phy_mask;
if (params->phy_mode == NIMBLE_PHY_1M) {
phy_mask = BLE_GAP_LE_PHY_1M_MASK;
}
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
else if (params->phy_mode == NIMBLE_PHY_2M) {
phy_mask = (BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK);
}
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
else if (params->phy_mode == NIMBLE_PHY_CODED) {
phy_mask = BLE_GAP_LE_PHY_CODED_MASK;
}
#endif
else {
return -EINVAL;
}
int res = ble_gap_ext_connect(params->own_addr_type, addr,
params->timeout_ms, phy_mask, &p, &p, &p,
_on_gap_master_evt, (void *)handle);
#else
uint32_t timeout = (params->timeout_ms == 0) ? BLE_HS_FOREVER
: params->timeout_ms;
int res = ble_gap_connect(params->own_addr_type, addr,
timeout, &p,
_on_gap_master_evt, (void *)handle);
#endif
if (res != 0) {
return -EIO;
}
_notify(handle, NIMBLE_NETIF_INIT_MASTER, addrn);
return handle;
}
@ -642,63 +674,168 @@ int nimble_netif_close(int handle)
return -ENOTCONN;
}
int res = ble_gap_terminate(ble_l2cap_get_conn_handle(conn->coc),
BLE_ERR_REM_USER_CONN_TERM);
assert(res == 0);
(void)res;
int res = ble_gap_terminate(conn->gaphandle, BLE_ERR_REM_USER_CONN_TERM);
if (res != 0) {
return -EIO;
}
return 0;
}
static int _accept(const uint8_t *ad, size_t ad_len, const ble_addr_t *addr,
uint32_t timeout,
const struct ble_gap_adv_params *adv_params)
#if MYNEWT_VAL_BLE_EXT_ADV
static int _get_phy_hci(uint8_t mode)
{
assert(adv_params);
switch (mode) {
case NIMBLE_PHY_1M:
return BLE_HCI_LE_PHY_1M;
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
case NIMBLE_PHY_2M:
return BLE_HCI_LE_PHY_2M;
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
case NIMBLE_PHY_CODED:
return BLE_HCI_LE_PHY_CODED;
#endif
default:
return -1;
}
}
#endif
static int _accept(const uint8_t *ad, size_t ad_len, const ble_addr_t *addr,
const nimble_netif_accept_cfg_t *params)
{
int handle;
int res;
(void)res;
assert(params);
/* allocate a connection context for incoming connections */
handle = nimble_netif_conn_start_adv();
if (handle < 0) {
return handle;
}
/* set advertisement data */
if (ad != NULL) {
res = ble_gap_adv_set_data(ad, (int)ad_len);
assert(res == 0);
}
/* remember address if applicable */
if (addr) {
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
bluetil_addr_swapped_cp(addr->val, conn->addr);
}
/* remember context and start advertising */
res = ble_gap_adv_start(nimble_riot_own_addr_type, addr, timeout,
adv_params, _on_gap_slave_evt, (void *)handle);
assert(res == 0);
#if MYNEWT_VAL_BLE_EXT_ADV
struct ble_gap_ext_adv_params p;
memset(&p, 0, sizeof(p));
/* figure out PHY modes */
int phy_pri = _get_phy_hci(params->primary_phy);
int phy_sec = _get_phy_hci(params->secondary_phy);
if ((phy_pri < 0) || (phy_sec < 0)) {
nimble_netif_conn_free(handle, NULL);
return -EINVAL;
}
/* the 2M PHY is not allowed as primary phy, we need to used the 1M PHY
* instead. This is for convenience so uses may define 2M as primary PHY */
if (phy_pri == BLE_HCI_LE_PHY_2M) {
phy_pri = BLE_HCI_LE_PHY_1M;
}
if (addr != NULL) {
p.directed = 1;
memcpy(&p.peer, addr, sizeof(p.peer));
if (params->flags & NIMBLE_NETIF_FLAG_HD_MODE) {
p.high_duty_directed = 1;
}
}
else {
p.connectable = 1;
}
if (params->flags & NIMBLE_NETIF_FLAG_LEGACY) {
p.legacy_pdu = 1;
/* legacy connectable PDUs are always scannable */
p.scannable = 1;
}
p.itvl_min = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms);
p.itvl_max = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms);
p.channel_map = params->channel_map;
p.own_addr_type = params->own_addr_type;
p.primary_phy = (uint8_t)phy_pri;
p.secondary_phy = (uint8_t)phy_sec;
p.tx_power = params->tx_power;
res = ble_gap_ext_adv_configure(EXT_ADV_INST, &p, NULL,
_on_gap_slave_evt, (void *)handle);
if (res != 0) {
nimble_netif_conn_free(handle, NULL);
return -EINVAL;
}
if (ad != NULL) {
struct os_mbuf *data = os_msys_get_pkthdr(ad_len, 0);
if (data == NULL) {
nimble_netif_conn_free(handle, NULL);
return -ENOMEM;
}
res = os_mbuf_append(data, ad, ad_len);
if (res != 0) {
os_mbuf_free_chain(data);
nimble_netif_conn_free(handle, NULL);
return -ENOMEM;
}
res = ble_gap_ext_adv_set_data(EXT_ADV_INST, data);
assert(res == 0);
}
res = ble_gap_ext_adv_start(EXT_ADV_INST, params->timeout_ms / 10, 0);
#else
uint8_t mode = (addr != NULL) ? BLE_GAP_CONN_MODE_DIR
: BLE_GAP_CONN_MODE_UND;
struct ble_gap_adv_params p = {
.conn_mode = mode,
.disc_mode = BLE_GAP_DISC_MODE_GEN,
.itvl_min = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms),
.itvl_max = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms),
.channel_map = params->channel_map,
.filter_policy = 0,
.high_duty_cycle = (params->flags & NIMBLE_NETIF_FLAG_HD_MODE) ? 1 : 0,
};
/* set advertisement data, if applicable */
if (ad != NULL) {
res = ble_gap_adv_set_data(ad, (int)ad_len);
if (res != 0) {
nimble_netif_conn_free(handle, NULL);
return -EINVAL;
}
}
/* start advertising */
uint32_t timeout = (params->timeout_ms == 0) ? BLE_HS_FOREVER
: params->timeout_ms;
res = ble_gap_adv_start(params->own_addr_type, addr, timeout,
&p, _on_gap_slave_evt, (void *)handle);
#endif
if (res != 0) {
nimble_netif_conn_free(handle, NULL);
return -ECANCELED;
}
_notify(handle, NIMBLE_NETIF_ACCEPTING, _netif.l2addr);
return 0;
}
int nimble_netif_accept(const uint8_t *ad, size_t ad_len,
const struct ble_gap_adv_params *adv_params)
const nimble_netif_accept_cfg_t *params)
{
assert(ad != NULL);
assert(ad_len > 0);
return _accept(ad, ad_len, NULL, BLE_HS_FOREVER, adv_params);
return _accept(ad, ad_len, NULL, params);
}
int nimble_netif_accept_direct(const ble_addr_t *addr, uint32_t timeout,
const struct ble_gap_adv_params *adv_params)
int nimble_netif_accept_direct(const ble_addr_t *addr,
const nimble_netif_accept_cfg_t *params)
{
return _accept(NULL, 0, addr, timeout, adv_params);
assert(addr);
return _accept(NULL, 0, addr, params);
}
int nimble_netif_accept_stop(void)
@ -708,9 +845,15 @@ int nimble_netif_accept_stop(void)
return -EALREADY;
}
int res = ble_gap_adv_stop();
assert(res == 0);
(void)res;
int res;
#if MYNEWT_VAL_BLE_EXT_ADV
res = ble_gap_ext_adv_stop(EXT_ADV_INST);
#else
res = ble_gap_adv_stop();
#endif
if (res != 0) {
return -EIO;
}
nimble_netif_conn_free(handle, NULL);
_notify(handle, NIMBLE_NETIF_ACCEPT_STOP, _netif.l2addr);

View File

@ -113,6 +113,7 @@ typedef struct {
uint16_t conn_latency; /**< used slave latency for parent connection */
uint32_t conn_super_to_ms; /**< used supervision timeout for parent
* connection, in ms */
nimble_phy_t phy_mode; /**< BLE PHY mode to use */
uint32_t eval_itvl_min_ms; /**< amount of time a node searches for
* potential parents, lower bound in ms */
uint32_t eval_itvl_max_ms; /**< amount of time a node searches for

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
@ -69,6 +69,13 @@ extern "C" {
#define NIMBLE_RPBLE_EVAL_ITVL_MAX_MS 13000U
#endif
/**
* @brief Default BLE PHY mode used by rpble
*/
#ifndef NIMBLE_RPBLE_PHY_MODE
#define NIMBLE_RPBLE_PHY_MODE NIMBLE_PHY_1M
#endif
#ifndef NIMBLE_RPBLE_PARAMS
#define NIMBLE_RPBLE_PARAMS \
{ .scan_itvl_ms = NIMBLE_RPBLE_SCAN_ITVL_MS, \
@ -81,6 +88,7 @@ extern "C" {
.conn_itvl_max_ms = NIMBLE_RPBLE_CONN_ITVL_MAX_MS, \
.conn_latency = NIMBLE_RPBLE_CONN_LATENCY, \
.conn_super_to_ms = NIMBLE_RPBLE_CONN_SUPER_TO_MS, \
.phy_mode = NIMBLE_RPBLE_PHY_MODE, \
.eval_itvl_min_ms = NIMBLE_RPBLE_EVAL_ITVL_MIN_MS, \
.eval_itvl_max_ms = NIMBLE_RPBLE_EVAL_ITVL_MAX_MS }
#endif

View File

@ -50,9 +50,8 @@
#define POS_FREE_SLOTS 22
/* keep the timing parameters for connections and advertisements */
static struct ble_gap_adv_params _adv_params = { 0 };
static struct ble_gap_conn_params _conn_params = { 0 };
static uint32_t _conn_scan_to; /* in ms */
static nimble_netif_accept_cfg_t _accept_params;
static nimble_netif_connect_cfg_t _conn_params;
/* local RPL context */
static nimble_rpble_ctx_t _local_rpl_ctx;
@ -107,7 +106,7 @@ static void _children_accept(void)
assert(res == BLUETIL_AD_OK);
/* start advertising this node */
res = nimble_netif_accept(ad.buf, ad.pos, &_adv_params);
res = nimble_netif_accept(ad.buf, ad.pos, &_accept_params);
assert(res == 0);
}
@ -118,10 +117,17 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
int res;
(void)info;
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT)
if ((type != (NIMBLE_SCANNER_EXT_ADV | BLE_HCI_ADV_CONN_MASK)) ||
(info->status != BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE)) {
return;
}
#else
/* filter out all non-connectible advertisements */
if (type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND) {
return;
}
#endif
/* check if scanned node does actually speak rpble */
bluetil_ad_data_t sd_field;
@ -199,7 +205,7 @@ static void _parent_connect(struct ble_npl_event *ev)
}
/* try to connect to parent */
int res = nimble_netif_connect(&_psel.addr, &_conn_params, _conn_scan_to);
int res = nimble_netif_connect(&_psel.addr, &_conn_params);
if (res < 0) {
_parent_find();
return;
@ -283,19 +289,36 @@ int nimble_rpble_param_update(const nimble_rpble_cfg_t *cfg)
cfg->eval_itvl_max_ms);
ble_npl_time_ms_to_ticks(itvl, &_eval_itvl);
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
_adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
_adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(cfg->adv_itvl_ms);
_adv_params.itvl_max = _adv_params.itvl_min;
/* accept parameter extraction */
memset(&_accept_params, 0, sizeof(_accept_params));
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT)
_accept_params.flags = 0;
_accept_params.primary_phy = cfg->phy_mode;
_accept_params.secondary_phy = cfg->phy_mode;
#else
_accept_params.flags = NIMBLE_NETIF_FLAG_LEGACY;
_accept_params.primary_phy = NIMBLE_PHY_1M;
_accept_params.secondary_phy = NIMBLE_PHY_1M;
#endif
_accept_params.adv_itvl_ms = cfg->adv_itvl_ms;
_accept_params.timeout_ms = BLE_HS_FOREVER;
_accept_params.own_addr_type = nimble_riot_own_addr_type;
_conn_params.scan_itvl = BLE_GAP_SCAN_ITVL_MS(cfg->conn_scan_itvl_ms);
_conn_params.scan_window = BLE_GAP_SCAN_WIN_MS(cfg->conn_scan_win_ms);
_conn_params.latency = cfg->conn_latency;
_conn_params.supervision_timeout =
BLE_GAP_SUPERVISION_TIMEOUT_MS(cfg->conn_super_to_ms);
_conn_params.itvl_min = BLE_GAP_CONN_ITVL_MS(cfg->conn_itvl_min_ms);
_conn_params.itvl_max = BLE_GAP_CONN_ITVL_MS(cfg->conn_itvl_max_ms);
_conn_scan_to = cfg->conn_scan_to_ms;
/* connection parameter extraction */
memset(&_conn_params, 0, sizeof(_conn_params));
_conn_params.scan_itvl_ms = cfg->conn_scan_itvl_ms;
_conn_params.scan_window_ms = cfg->conn_scan_win_ms;
_conn_params.conn_itvl_min_ms = cfg->conn_itvl_min_ms;
_conn_params.conn_itvl_max_ms = cfg->conn_itvl_max_ms;
_conn_params.conn_supervision_timeout_ms = cfg->conn_super_to_ms;
_conn_params.conn_slave_latency = cfg->conn_latency;
_conn_params.timeout_ms = cfg->conn_scan_to_ms;
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT)
_conn_params.phy_mode = cfg->phy_mode;
#else
_conn_params.phy_mode = NIMBLE_PHY_1M;
#endif
_conn_params.own_addr_type = nimble_riot_own_addr_type;
/* register event callback */
nimble_netif_eventcb(_on_netif_evt);
@ -304,9 +327,18 @@ int nimble_rpble_param_update(const nimble_rpble_cfg_t *cfg)
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_PHY_1M;
scan_params.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_FILTER_DUPS);
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT) && IS_USED(MODULE_NIMBLE_PHY_CODED)
if (cfg->phy_mode == NIMBLE_PHY_CODED) {
scan_params.flags |= NIMBLE_SCANNER_PHY_CODED;
}
else {
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
}
#else
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
#endif
nimble_scanner_init(&scan_params, _on_scan_evt);
/* start to look for parents */

View File

@ -44,7 +44,9 @@ enum {
NIMBLE_SCANNER_LIMITED = 0x02, /**< do limited discovery */
NIMBLE_SCANNER_FILTER_DUPS = 0x04, /**< filter duplicates */
NIMBLE_SCANNER_PHY_1M = 0x10, /**< scan on 1Mbit PHY */
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
NIMBLE_SCANNER_PHY_CODED = 0x20, /**< scan on CODED PHY */
#endif
};
/**

View File

@ -100,9 +100,12 @@ int nimble_scanner_start(void)
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;
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
const struct ble_gap_ext_disc_params *coded =
(_scan_flags & NIMBLE_SCANNER_PHY_CODED) ? &_scan_params : NULL;
#else
const struct ble_gap_ext_disc_params *coded = NULL;
#endif
int32_t dur = (_scan_duration == BLE_HS_FOREVER) ? 0
: _scan_duration / 10;

View File

@ -113,6 +113,21 @@ extern "C" {
#define NIMBLE_STATCONN_CONN_SUPERTO_MS (2500U)
#endif
/**
* @brief BLE PHY mode used by statconn. This value is only used if statconn
* is used in its extended mode (module `nimble_statconn_ext`)
*/
#ifndef NIMBLE_STATCONN_PHY_MODE
#define NIMBLE_STATCONN_PHY_MODE NIMBLE_PHY_1M
#endif
/**
* @brief Statconn connection parameters
*/
typedef struct {
nimble_phy_t phy_mode; /**< BLE PHY mode used for the connection */
} nimble_statconn_cfg_t;
/**
* @brief Initialize the statconn module
*
@ -138,23 +153,31 @@ void nimble_statconn_eventcb(nimble_netif_eventcb_t cb);
* connection by that master.
*
* @param[in] addr BLE address of the peer
* @param[in] cfg additional connection parameters, set to NULL to apply
* default values
*
* @return 0 if peer was successfully added
* @return -EALREADY if the peer address is already in use
* @return -ENOMEM if no empty connection slot is available
* @return -EINVAL if invalid configuration parameters are given
*/
int nimble_statconn_add_master(const uint8_t *addr);
int nimble_statconn_add_master(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg);
/**
* @brief Connect to a peer (slave) with a given address as master
*
* @param[in] addr BLE address of the peer
* @param[in] cfg additional connection parameters, set to NULL to apply
* default values
*
* @return 0 if peer was successfully added
* @return -EALREADY if the peer address is already in use
* @return -ENOMEM if no empty connection slot is available
* @return -EINVAL if invalid configuration parameters are given
*/
int nimble_statconn_add_slave(const uint8_t *addr);
int nimble_statconn_add_slave(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg);
/**
* @brief Remove the connection to the given peer

View File

@ -44,6 +44,9 @@
typedef struct {
uint8_t addr[BLE_ADDR_LEN]; /**< peer addr, network byte order */
uint8_t state; /**< internal state */
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
nimble_phy_t phy_mode; /**< PHY mode used by this slot */
#endif
} slot_t;
static const uint8_t _ad[2] = { BLE_GAP_AD_FLAGS, BLUETIL_AD_FLAGS_DEFAULT };
@ -51,9 +54,8 @@ static const uint8_t _ad[2] = { BLE_GAP_AD_FLAGS, BLUETIL_AD_FLAGS_DEFAULT };
static mutex_t _lock = MUTEX_INIT;
static slot_t _slots[NIMBLE_NETIF_MAX_CONN];
static struct ble_gap_adv_params _adv_params;
static struct ble_gap_conn_params _conn_params;
static uint32_t _conn_timeout;
static nimble_netif_accept_cfg_t _accept_params;
static nimble_netif_connect_cfg_t _conn_params;
static nimble_netif_eventcb_t _eventcb = NULL;
@ -87,10 +89,17 @@ static void _activate(uint8_t role)
peer.type = BLE_ADDR_RANDOM;
bluetil_addr_swapped_cp(slot->addr, peer.val);
/* try to (re)open the connection */
nimble_netif_connect(&peer, &_conn_params, _conn_timeout);
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
_conn_params.phy_mode = slot->phy_mode;
#endif
nimble_netif_connect(&peer, &_conn_params);
}
else if (slot && (role == ROLE_S)) {
nimble_netif_accept(_ad, sizeof(_ad), &_adv_params);
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
_accept_params.primary_phy = slot->phy_mode;
_accept_params.secondary_phy = slot->phy_mode;
#endif
nimble_netif_accept(_ad, sizeof(_ad), &_accept_params);
}
mutex_unlock(&_lock);
}
@ -153,7 +162,8 @@ static void _on_netif_evt(int handle, nimble_netif_event_t event,
}
}
static int _be(uint8_t role, const uint8_t *addr)
static int _be(uint8_t role, const uint8_t *addr,
const nimble_statconn_cfg_t *cfg)
{
mutex_lock(&_lock);
slot_t *s = _get_addr(addr);
@ -170,6 +180,18 @@ static int _be(uint8_t role, const uint8_t *addr)
s->state = (role | PENDING);
memcpy(s->addr, addr, BLE_ADDR_LEN);
mutex_unlock(&_lock);
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
if (cfg != NULL) {
s->phy_mode = cfg->phy_mode;
}
else {
s->phy_mode = NIMBLE_STATCONN_PHY_MODE;
}
#else
(void)cfg;
#endif
_activate(role);
return 0;
}
@ -179,27 +201,31 @@ void nimble_statconn_init(void)
memset(_slots, 0, sizeof(_slots));
/* set the advertising parameters used */
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
_adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
_adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(NIMBLE_STATCONN_ADV_ITVL_MS);
_adv_params.itvl_max = _adv_params.itvl_min;
_adv_params.channel_map = 0;
_adv_params.filter_policy = 0;
_adv_params.high_duty_cycle = 0;
memset(&_accept_params, 0, sizeof(_accept_params));
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
_accept_params.flags = 0;
#else
_accept_params.flags = NIMBLE_NETIF_FLAG_LEGACY;
_accept_params.primary_phy = NIMBLE_PHY_1M;
_accept_params.secondary_phy = NIMBLE_PHY_1M;
#endif
_accept_params.adv_itvl_ms = NIMBLE_STATCONN_ADV_ITVL_MS;
_accept_params.timeout_ms = BLE_HS_FOREVER;
_accept_params.own_addr_type = nimble_riot_own_addr_type;
/* set connection parameters */
_conn_params.scan_itvl = BLE_GAP_SCAN_ITVL_MS(NIMBLE_STATCONN_CONN_WIN_MS);
_conn_params.scan_window = _conn_params.scan_itvl;
_conn_params.latency = NIMBLE_STATCONN_CONN_LATENCY;
_conn_params.supervision_timeout = BLE_GAP_SUPERVISION_TIMEOUT_MS(
NIMBLE_STATCONN_CONN_SUPERTO_MS);
_conn_params.itvl_min = BLE_GAP_CONN_ITVL_MS(
NIMBLE_STATCONN_CONN_ITVL_MIN_MS);
_conn_params.itvl_max = BLE_GAP_CONN_ITVL_MS(
NIMBLE_STATCONN_CONN_ITVL_MAX_MS);
_conn_params.min_ce_len = 0;
_conn_params.max_ce_len = 0;
_conn_timeout = NIMBLE_STATCONN_CONN_TIMEOUT_MS;
memset(&_conn_params, 0, sizeof(_conn_params));
#if !IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
_conn_params.phy_mode = NIMBLE_PHY_1M;
#endif
_conn_params.scan_itvl_ms = NIMBLE_STATCONN_CONN_WIN_MS;
_conn_params.scan_window_ms = NIMBLE_STATCONN_CONN_WIN_MS;
_conn_params.conn_itvl_min_ms = NIMBLE_STATCONN_CONN_ITVL_MIN_MS;
_conn_params.conn_itvl_max_ms = NIMBLE_STATCONN_CONN_ITVL_MAX_MS;
_conn_params.conn_supervision_timeout_ms = NIMBLE_STATCONN_CONN_SUPERTO_MS;
_conn_params.conn_slave_latency = NIMBLE_STATCONN_CONN_LATENCY;
_conn_params.timeout_ms = NIMBLE_STATCONN_CONN_TIMEOUT_MS;
_conn_params.own_addr_type = nimble_riot_own_addr_type;
/* register our event callback */
nimble_netif_eventcb(_on_netif_evt);
@ -210,14 +236,16 @@ void nimble_statconn_eventcb(nimble_netif_eventcb_t cb)
_eventcb = cb;
}
int nimble_statconn_add_master(const uint8_t *addr)
int nimble_statconn_add_master(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg)
{
return _be(ROLE_S, addr);
return _be(ROLE_S, addr, cfg);
}
int nimble_statconn_add_slave(const uint8_t *addr)
int nimble_statconn_add_slave(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg)
{
return _be(ROLE_M, addr);
return _be(ROLE_M, addr, cfg);
}
int nimble_statconn_rm(const uint8_t *addr)

View File

@ -21,6 +21,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "fmt.h"
#include "ztimer.h"
@ -30,17 +31,37 @@
#include "net/bluetil/ad.h"
#include "net/bluetil/addr.h"
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
#define FULL_CONTROL !IS_USED(MODULE_NIMBLE_AUTOCONN) && \
!IS_USED(MODULE_NIMBLE_STATCONN) && \
!IS_USED(MODULE_NIMBLE_RPBLE)
#if FULL_CONTROL
#include "nimble_scanlist.h"
#include "nimble_scanner.h"
#endif
#define DEFAULT_NODE_NAME "bleRIOT"
#define DEFAULT_SCAN_DURATION (500U) /* 500ms */
#define DEFAULT_CONN_TIMEOUT (500U) /* 500ms */
#define DEFAULT_SCAN_DURATION_MS 500U
#define DEFAULT_CONN_TIMEOUT_MS 500U
#define DEFAULT_SCAN_ITVL_MS 100U
#define DEFAULT_CONN_ITVL_MS 75U
#define DEFAULT_TX_POWER 0 /* 0dBm */
#define DEFAULT_ADV_ITVL_MS 75U
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
static const char *_phystr[] = { "N/A", "1M", "2M", "CODED" };
#if FULL_CONTROL
static const char *_name_to_connect = NULL;
static nimble_netif_connect_cfg_t _connect_params = {
.scan_itvl_ms = DEFAULT_SCAN_ITVL_MS,
.scan_window_ms = DEFAULT_SCAN_ITVL_MS,
.conn_itvl_min_ms = DEFAULT_CONN_ITVL_MS,
.conn_itvl_max_ms = DEFAULT_CONN_ITVL_MS,
.conn_supervision_timeout_ms = DEFAULT_CONN_ITVL_MS * 20,
.conn_slave_latency = 0,
.timeout_ms = 0, /* will be filled later */
.phy_mode = 0, /* will be filled later */
.own_addr_type = 0 /* will be filled later */,
};
static void _scan_for_name(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
@ -56,7 +77,7 @@ static void _scan_for_name(uint8_t type, const ble_addr_t *addr,
_name_to_connect, strlen(_name_to_connect));
if (res) {
nimble_scanner_stop();
nimble_netif_connect(addr, NULL, DEFAULT_CONN_TIMEOUT);
nimble_netif_connect(addr, &_connect_params);
}
}
@ -90,12 +111,34 @@ static void _on_ble_evt(int handle, nimble_netif_event_t event,
case NIMBLE_NETIF_ABORT_SLAVE:
_print_evt("CONNECTION ABORT", handle, addr);
break;
case NIMBLE_NETIF_ACCEPT_STOP:
_print_evt("ACCEPT STOP", handle, addr);
case NIMBLE_NETIF_CONN_UPDATED:
default:
/* do nothing */
break;
}
}
static uint8_t _parsephy(const char *phy_str)
{
if (memcmp(phy_str, "1M", 2) == 0) {
return NIMBLE_PHY_1M;
}
#if IS_ACTIVE(MODULE_NIMBLE_PHY_2MBIT)
else if (memcmp(phy_str, "2M", 2) == 0) {
return NIMBLE_PHY_2M;
}
#endif
#if IS_ACTIVE(MODULE_NIMBLE_PHY_CODED)
else if (memcmp(phy_str, "CODED", 5) == 0) {
return NIMBLE_PHY_CODED;
}
#endif
else {
return NIMBLE_PHY_INVALID;
}
}
#endif
static int _conn_dump(nimble_netif_conn_t *conn, int handle, void *arg)
@ -117,8 +160,20 @@ static int _conn_dump(nimble_netif_conn_t *conn, int handle, void *arg)
printf(" ");
bluetil_addr_ipv6_l2ll_print(conn->addr);
#endif
printf(" (%c,%ums,%ums,%i)", role, itvl, sto, (int)desc.conn_latency);
puts("");
#if IS_USED(MODULE_NIMBLE_NETIF_EXT)
uint8_t phy_rx, phy_tx;
(void)phy_tx;
res = ble_gap_read_le_phy(conn->gaphandle, &phy_tx, &phy_rx);
if (res != 0) {
phy_rx = 1;
}
#else
/* when not using extended advertisements we always use the 1M phy mode */
uint8_t phy_rx = 1;
#endif
printf(" (%c,%ums,%ums,%i,%s)\n",
role, itvl, sto, (int)desc.conn_latency, _phystr[phy_rx]);
return 0;
}
@ -159,7 +214,7 @@ static void _conn_list(void)
if (active > 0) {
nimble_netif_conn_foreach(NIMBLE_NETIF_L2CAP_CONNECTED,
_conn_dump, NULL);
puts(" (role, conn itvl, superv. timeout, slave latency)");
puts(" (role, conn itvl, superv. timeout, slave latency, PHY)");
}
}
@ -179,6 +234,15 @@ static void _cmd_info(void)
#endif
puts("");
printf("Supported PHY modes: 1M");
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
printf(" 2M");
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
printf(" CODED");
#endif
puts("");
printf(" Free slots: %u/%u\n", free, NIMBLE_NETIF_MAX_CONN);
printf("Advertising: ");
if (nimble_netif_conn_get_adv() != NIMBLE_NETIF_CONN_INVALID) {
@ -196,99 +260,107 @@ static void _cmd_info(void)
puts("");
}
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
static void _cmd_adv(const char *name)
#if FULL_CONTROL
static int _cmd_adv(int argc, char **argv, bool legacy)
{
int res;
(void)res;
uint8_t buf[BLE_HS_ADV_MAX_SZ];
bluetil_ad_t ad;
const struct ble_gap_adv_params _adv_params = {
.conn_mode = BLE_GAP_CONN_MODE_UND,
.disc_mode = BLE_GAP_DISC_MODE_LTD,
.itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN,
.itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX,
};
const char *name = NULL;
uint8_t addrn[BLE_ADDR_LEN];
ble_addr_t addr = { .type = nimble_riot_own_addr_type };
/* stop sub-command: stop advertising */
if (memcmp(argv[2], "stop", 4) == 0) {
res = nimble_netif_accept_stop();
if (res == 0) {
puts("advertising stopped");
}
else if (res == -EALREADY) {
puts("no advertising in progress");
}
return 0;
}
/* make sure no advertising is in progress */
if (nimble_netif_conn_is_adv()) {
puts("err: advertising already in progress");
return;
return 1;
}
/* build advertising data */
res = bluetil_ad_init_with_flags(&ad, buf, BLE_HS_ADV_MAX_SZ,
BLUETIL_AD_FLAGS_DEFAULT);
assert(res == BLUETIL_AD_OK);
uint16_t ipss = BLE_GATT_SVC_IPSS;
res = bluetil_ad_add(&ad, BLE_GAP_AD_UUID16_INCOMP, &ipss, sizeof(ipss));
assert(res == BLUETIL_AD_OK);
if (name == NULL) {
name = DEFAULT_NODE_NAME;
/* try if first parameter is a BLE address, if so, use directed
* advertisement */
if (bluetil_addr_from_str(addrn, argv[2]) != NULL) {
/* NimBLE expects address in little endian, so swap */
bluetil_addr_swapped_cp(addrn, addr.val);
puts("Found BLE address: sending directed advertisements");
}
res = bluetil_ad_add(&ad, BLE_GAP_AD_NAME, name, strlen(name));
if (res != BLUETIL_AD_OK) {
puts("err: the given name is too long");
return;
else {
name = argv[2];
}
uint32_t timeout = 0;
if (argc >= 4) {
timeout = (uint32_t)atoi(argv[3]);
}
uint8_t phy_sec = BLE_GAP_LE_PHY_1M;
if (argc >= 5) {
phy_sec = _parsephy(argv[4]);
if (phy_sec == 0) {
puts("err: PHY mode not supported\n");
return 1;
}
}
uint8_t phy_pri = (phy_sec == BLE_HCI_LE_PHY_2M) ? BLE_HCI_LE_PHY_1M
: phy_sec;
nimble_netif_accept_cfg_t p = {
.flags = (legacy) ? NIMBLE_NETIF_FLAG_LEGACY : 0,
.adv_itvl_ms = DEFAULT_ADV_ITVL_MS,
.primary_phy = phy_pri,
.secondary_phy = phy_sec,
.tx_power = DEFAULT_TX_POWER,
.channel_map = 0,
.timeout_ms = timeout,
.own_addr_type = nimble_riot_own_addr_type,
};
if (name != NULL) {
uint8_t buf[BLE_HS_ADV_MAX_SZ];
bluetil_ad_t ad;
/* build advertising data */
res = bluetil_ad_init_with_flags(&ad, buf, BLE_HS_ADV_MAX_SZ,
BLUETIL_AD_FLAGS_DEFAULT);
assert(res == BLUETIL_AD_OK);
uint16_t ipss = BLE_GATT_SVC_IPSS;
res = bluetil_ad_add(&ad, BLE_GAP_AD_UUID16_INCOMP, &ipss, sizeof(ipss));
assert(res == BLUETIL_AD_OK);
res = bluetil_ad_add(&ad, BLE_GAP_AD_NAME, name, strlen(name));
if (res != BLUETIL_AD_OK) {
puts("err: the given name is too long");
return 1;
}
res = nimble_netif_accept(ad.buf, ad.pos, &p);
}
else {
res = nimble_netif_accept_direct(&addr, &p);
}
/* start listening for incoming connections */
res = nimble_netif_accept(ad.buf, ad.pos, &_adv_params);
if (res != 0) {
printf("err: unable to start advertising (%i)\n", res);
}
else {
printf("success: advertising this node as '%s'\n", name);
}
}
static void _cmd_adv_direct(const char *addr_str)
{
int res;
(void)res;
uint8_t addrn[BLE_ADDR_LEN];
ble_addr_t addr;
const struct ble_gap_adv_params _adv_params = {
.conn_mode = BLE_GAP_CONN_MODE_DIR,
.disc_mode = BLE_GAP_DISC_MODE_GEN,
.itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN,
.itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX,
};
/* make sure no advertising is in progress */
if (nimble_netif_conn_is_adv()) {
puts("err: advertising already in progress");
return;
}
/* parse and convert address -> RIOT uses big endian notation, NimBLE
* expects little endian... */
if (bluetil_addr_from_str(addrn, addr_str) == NULL) {
puts("err: unable to parse BLE address");
return;
}
addr.type = nimble_riot_own_addr_type;
bluetil_addr_swapped_cp(addrn, addr.val);
/* start advertising directed advertising with the given BLE address */
res = nimble_netif_accept_direct(&addr, BLE_HS_FOREVER, &_adv_params);
if (res != 0) {
printf("err: unable to start directed advertising (%i)\n", res);
}
else {
puts("success: started to send directed advertisements");
}
}
static void _cmd_adv_stop(void)
{
int res = nimble_netif_accept_stop();
if (res == 0) {
puts("canceled advertising");
}
else {
puts("no advertising in progress");
if (name != NULL) {
printf("success: advertising this node as '%s'\n", name);
}
else {
printf("success: sending direct advertisements to ");
bluetil_addr_print(addrn);
puts("");
}
}
return 0;
}
static void _do_scan(nimble_scanner_cb cb, unsigned duration)
@ -301,7 +373,19 @@ static void _do_scan(nimble_scanner_cb cb, unsigned duration)
printf("err: scanner already active\n");
return;
}
nimble_scanner_init(NULL, cb);
nimble_scanner_cfg_t p = {
.itvl_ms = DEFAULT_SCAN_ITVL_MS,
.win_ms = DEFAULT_SCAN_ITVL_MS,
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_PHY_1M |
NIMBLE_SCANNER_PHY_CODED),
#else
.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_PHY_1M),
#endif
};
nimble_scanner_init(&p, cb);
nimble_scanlist_clear();
nimble_scanner_start();
ztimer_sleep(ZTIMER_MSEC, duration);
@ -316,58 +400,73 @@ static void _cmd_scan(unsigned duration)
nimble_scanlist_print();
}
static void _cmd_connect_addr(ble_addr_t *addr)
static void _cmd_connect(int argc, char **argv)
{
/* simply use NimBLEs default connection parameters */
int res = nimble_netif_connect(addr, NULL, DEFAULT_CONN_TIMEOUT);
if (res < 0) {
printf("err: unable to trigger connection sequence (%i)\n", res);
return;
}
ble_addr_t addr;
int proceed = 0;
printf("initiated connection procedure with ");
/* populate connection parameters */
_connect_params.timeout_ms = DEFAULT_CONN_TIMEOUT_MS;
if (argc >= 4) {
_connect_params.timeout_ms = (uint32_t)atoi(argv[3]);
}
_connect_params.phy_mode = NIMBLE_PHY_1M;
if (argc >= 5) {
_connect_params.phy_mode = _parsephy(argv[4]);
if (_connect_params.phy_mode == 0) {
puts("err: PHY mode not supported\n");
return;
}
}
_connect_params.own_addr_type = nimble_riot_own_addr_type;
/* try to parse address directly */
uint8_t addrn[BLE_ADDR_LEN];
bluetil_addr_swapped_cp(addr->val, addrn);
bluetil_addr_print(addrn);
puts("");
}
static void _cmd_connect_addr_raw(const uint8_t *addr_in)
{
/* RANDOM is the most common type, has no noticeable effect when connecting
anyhow... */
ble_addr_t addr = { .type = BLE_ADDR_RANDOM };
/* NimBLE expects address in little endian, so swap */
bluetil_addr_swapped_cp(addr_in, addr.val);
_cmd_connect_addr(&addr);
}
static void _cmd_connect_name(const char *name, unsigned duration)
{
if (_name_to_connect != NULL) {
printf("err: already trying to connect to '%s'\n", _name_to_connect);
if (bluetil_addr_from_str(addrn, argv[2]) != NULL) {
addr.type = nimble_riot_own_addr_type;
/* NimBLE expects address in little endian, so swap */
bluetil_addr_swapped_cp(addrn, addr.val);
proceed = 1;
}
/* try if param is a number, if so use it as scanlist entry number */
else if (fmt_is_number(argv[2])) {
unsigned pos = atoi(argv[2]);
nimble_scanlist_entry_t *sle = nimble_scanlist_get_by_pos(pos);
if (sle == NULL) {
puts("err: unable to find given entry in scanlist");
return;
}
_connect_params.phy_mode = sle->phy_sec;
memcpy(&addr, &sle->addr, sizeof(addr));
proceed = 1;
}
/* else interpret value as name and search for that peer */
else {
unsigned duration = DEFAULT_SCAN_DURATION_MS;
if (argc > 3) {
duration = atoi(argv[3]);
}
_name_to_connect = argv[2];
printf("trying to find and connect to a node with name '%s'\n", argv[2]);
_do_scan(_scan_for_name, duration);
if (_name_to_connect != NULL) {
printf("fail: unable to connect to '%s'\n", _name_to_connect);
_name_to_connect = NULL;
}
return;
}
_name_to_connect = name;
printf("trying to find and connect to a node with name '%s'\n", name);
_do_scan(_scan_for_name, duration);
if (_name_to_connect != NULL) {
printf("fail: unable to connect to '%s'\n", _name_to_connect);
_name_to_connect = NULL;
}
}
static void _cmd_connect_scanlist(unsigned pos)
{
nimble_scanlist_entry_t *sle = nimble_scanlist_get_by_pos(pos);
if (sle == NULL) {
puts("err: unable to find given entry in scanlist");
return;
if (proceed == 1) {
int res = nimble_netif_connect(&addr, &_connect_params);
if (res == 0) {
puts("Successfully connected 123");
}
else {
puts("err: unable to connect");
}
}
_cmd_connect_addr(&sle->addr);
}
#endif /* MODULE_NIMBLE_AUTOCONN */
#endif
static void _cmd_close(int handle)
{
@ -406,7 +505,7 @@ static int _ishelp(char *argv)
void sc_nimble_netif_init(void)
{
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
#if FULL_CONTROL
/* setup the scanning environment */
nimble_scanlist_init();
@ -418,8 +517,9 @@ void sc_nimble_netif_init(void)
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]\n", argv[0]);
#if FULL_CONTROL
printf("usage: %s [help|info|adv|adv_ext|adv_dir|"
"scan|connect|close|update|chanmap]\n", argv[0]);
#else
printf("usage: %s [help|info|close|update|chanmap]\n", argv[0]);
#endif
@ -429,34 +529,26 @@ int _nimble_netif_handler(int argc, char **argv)
_cmd_info();
}
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
else if (memcmp(argv[1], "adv", 3) == 0) {
char *name = NULL;
if (argc > 2) {
if (_ishelp(argv[2])) {
printf("usage: %s adv [help|stop|direct <addr>|<name>]\n",
argv[0]);
return 0;
}
if (memcmp(argv[2], "stop", 4) == 0) {
_cmd_adv_stop();
return 0;
}
if (memcmp(argv[2], "direct", 6) == 0) {
puts("DBG: direct adv");
if (argc < 4) {
printf("error, no BLE address given\n");
return 0;
}
_cmd_adv_direct(argv[3]);
return 0;
}
name = argv[2];
#if FULL_CONTROL
else if (memcmp(argv[1], "adv_ext", 7) == 0) {
if (argc <= 2 || _ishelp(argv[2])) {
printf("usage: %s adv_ext <help|stop|addr|name> [timeout] [phy mode]\n"
" timeout in ms, 0 for no timeout\n"
" phy mode: [1M|2M|CODED]\n", argv[0]);
return 0;
}
_cmd_adv(name);
return _cmd_adv(argc, argv, false);
}
else if (memcmp(argv[1], "adv", 3) == 0) {
if (argc <= 2 || _ishelp(argv[2])) {
printf("usage: %s adv <help|stop|addr|name> [timeout]\n"
" timeout in ms, 0 for no timeout\n", argv[0]);
return 0;
}
return _cmd_adv(argc, argv, true);
}
else if (memcmp(argv[1], "scan", 4) == 0) {
uint32_t duration = DEFAULT_SCAN_DURATION;
uint32_t duration = DEFAULT_SCAN_DURATION_MS;
if (argc > 2) {
if (_ishelp(argv[2])) {
printf("usage: %s scan [help|list|[duration in ms]]\n", argv[0]);
@ -472,32 +564,16 @@ int _nimble_netif_handler(int argc, char **argv)
}
else if (memcmp(argv[1], "connect", 7) == 0) {
if ((argc < 3) || _ishelp(argv[2])) {
printf("usage: %s connect [help|list|<scanlist entry #>|<BLE addr>|<name>]\n",
argv[0]);
printf("usage: %s %s [help|list|<scanlist #>|<BLE addr>|<name>] "
"[timeout ms] [phy mode]\n"
" phy mode: [1M|2M|CODED]\n", argv[0], argv[1]);
return 0;
}
if (memcmp(argv[2], "list", 4) == 0) {
_conn_list();
return 0;
}
/* try if param is an BLE address */
uint8_t addr[BLE_ADDR_LEN];
if (bluetil_addr_from_str(addr, argv[2]) != NULL) {
_cmd_connect_addr_raw(addr);
return 0;
}
/* try if param is a name (contains non-number chars) */
if (!fmt_is_number(argv[2])) {
unsigned duration = DEFAULT_SCAN_DURATION;
if (argc > 3) {
duration = atoi(argv[3]);
}
_cmd_connect_name(argv[2], duration);
return 0;
}
unsigned pos = atoi(argv[2]);
_cmd_connect_scanlist(pos);
_cmd_connect(argc, argv);
}
#endif
else if (memcmp(argv[1], "close", 5) == 0) {

View File

@ -24,13 +24,48 @@
#include "net/bluetil/addr.h"
#include "nimble_statconn.h"
static uint8_t _parsephy(const char *phy_str)
{
if (memcmp(phy_str, "1M", 2) == 0) {
return NIMBLE_PHY_1M;
}
#if IS_ACTIVE(MODULE_NIMBLE_PHY_2MBIT)
else if (memcmp(phy_str, "2M", 2) == 0) {
return NIMBLE_PHY_2M;
}
#endif
#if IS_ACTIVE(MODULE_NIMBLE_PHY_CODED)
else if (memcmp(phy_str, "CODED", 5) == 0) {
return NIMBLE_PHY_CODED;
}
#endif
else {
return NIMBLE_PHY_INVALID;
}
}
int _nimble_statconn_handler(int argc, char **argv)
{
nimble_statconn_cfg_t cfg;
if ((argc < 3)) {
printf("usage: %s <addm|adds|rm> <BLE addr>\n", argv[0]);
printf("usage: %s <addm|adds|rm> <BLE addr> [phy mode]\n"
" phy_mode := [1M, 2M, CODED]\n", argv[0]);
return 0;
}
if (argc >= 4) {
cfg.phy_mode = _parsephy(argv[3]);
if (cfg.phy_mode == NIMBLE_PHY_INVALID) {
puts("err: PHY mode not supported");
return 1;
}
}
else {
cfg.phy_mode = NIMBLE_STATCONN_PHY_MODE;
}
/* parse address */
uint8_t addr[BLE_ADDR_LEN];
if (bluetil_addr_from_str(addr, argv[2]) == NULL) {
@ -39,7 +74,7 @@ int _nimble_statconn_handler(int argc, char **argv)
}
if (strncmp(argv[1], "addm", 4) == 0) {
if (nimble_statconn_add_master(addr) == 0) {
if (nimble_statconn_add_master(addr, &cfg) == 0) {
puts("success: connecting to peer as slave");
}
else {
@ -47,7 +82,7 @@ int _nimble_statconn_handler(int argc, char **argv)
}
}
else if (strncmp(argv[1], "adds", 4) == 0) {
if (nimble_statconn_add_slave(addr) == 0) {
if (nimble_statconn_add_slave(addr, &cfg) == 0) {
puts("success: connecting to peer as master");
}
else {

View File

@ -0,0 +1,24 @@
BOARD ?= nrf52dk
include ../Makefile.tests_common
# include shell support
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Include GNRC and RPL
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_icmpv6_echo
USEMODULE += auto_init_gnrc_rpl
USEMODULE += gnrc_rpl
# Setup Nimble
USEMODULE += nimble_autoconn_ipsp
USEMODULE += nimble_autoconn_ext
FEATURES_OPTIONAL += ble_phy_2mbit
FEATURES_OPTIONAL += ble_phy_coded
TEST_ON_CI_WHITELIST += nrf52dk nrf52840dk
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,4 @@
BOARD_INSUFFICIENT_MEMORY := \
e104-bt5010a-tb \
e104-bt5011a-tb \
#

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 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 examples
* @{
*
* @file
* @brief Run IP-over-BLE using the 'autoconn' BLE connection manager
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "msg.h"
#define MAIN_QUEUE_SIZE (8)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
int main(void)
{
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
puts("IPv6-over-BLE with autoconn BLE connection manager");
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should never be reached */
return 0;
}

View File

@ -8,11 +8,8 @@ USEMODULE += shell_commands
USEMODULE += nimble_scanner
USEMODULE += nimble_scanlist
USEMODULE += nimble_adv_ext
USEMODULE += nimble_phy_2mbit
ifneq (,$(filter nrf52840dk nrf52840dongle,$(BOARD)))
USEMODULE += nimble_phy_coded
endif
FEATURES_OPTIONAL += ble_phy_2mbit
FEATURES_OPTIONAL += ble_phy_coded
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the

View File

@ -0,0 +1,24 @@
BOARD ?= nrf52dk
include ../Makefile.tests_common
# include shell support
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Include GNRC and RPL
USEMODULE += netdev_default
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_router_default
USEMODULE += auto_init_gnrc_rpl
USEMODULE += gnrc_rpl
USEMODULE += gnrc_icmpv6_echo
# Setup Nimble
USEMODULE += nimble_netif_ext
FEATURES_OPTIONAL += ble_phy_2mbit
FEATURES_OPTIONAL += ble_phy_coded
TEST_ON_CI_WHITELIST += nrf52dk nrf52840dk
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,4 @@
BOARD_INSUFFICIENT_MEMORY := \
e104-bt5010a-tb \
e104-bt5011a-tb \
#

View File

@ -0,0 +1,45 @@
/*
* 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 examples
* @{
*
* @file
* @brief Test extended advertising and additional PHY modes with
* nimble_netif
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "msg.h"
#define MAIN_QUEUE_SIZE (8)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
int main(void)
{
puts("Extended PHY mode test for IP over BLE");
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should never be reached */
return 0;
}

View File

@ -17,7 +17,7 @@ USEMODULE += auto_init_gnrc_rpl
# configure and use Nimble
USEMODULE += bluetil_addr
USEMODULE += nimble_rpble
NIMBLE_MAX_CONN := 3
NIMBLE_MAX_CONN = 3
DEVELHELP = 0

View File

@ -0,0 +1,30 @@
BOARD ?= nrf52dk
include ../Makefile.tests_common
# include shell support
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Enable single interface optimization.
# Remove this if more than one interface is present
USEMODULE += gnrc_netif_single
# Include GNRC and RPL
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_icmpv6_echo
USEMODULE += gnrc_rpl
USEMODULE += auto_init_gnrc_rpl
# configure and use Nimble
USEMODULE += bluetil_addr
USEMODULE += nimble_rpble_ext
FEATURES_OPTIONAL += ble_phy_2mbit
FEATURES_OPTIONAL += ble_phy_coded
NIMBLE_MAX_CONN = 3
DEVELHELP = 0
TEST_ON_CI_WHITELIST += nrf52dk nrf52840dk
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,4 @@
BOARD_INSUFFICIENT_MEMORY := \
e104-bt5010a-tb \
e104-bt5011a-tb \
#

View File

@ -0,0 +1,80 @@
/*
* 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 examples
* @{
*
* @file
* @brief Test for using rpble in its extended mode
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include "msg.h"
#include "shell.h"
#include "nimble_rpble.h"
#include "net/bluetil/addr.h"
#define MAIN_QUEUE_SIZE (8)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
static void _dump_evt(const char *text, const uint8_t *addr)
{
printf("[ble_event] %s (", text);
bluetil_addr_print(addr);
printf(")\n");
}
static void _on_rpble_event(int handle, nimble_netif_event_t event,
const uint8_t *addr)
{
(void)handle;
switch (event) {
case NIMBLE_NETIF_CONNECTED_MASTER:
_dump_evt("parent selected", addr);
break;
case NIMBLE_NETIF_CONNECTED_SLAVE:
_dump_evt("child added", addr);
break;
case NIMBLE_NETIF_CLOSED_MASTER:
_dump_evt("parent lost", addr);
break;
case NIMBLE_NETIF_CLOSED_SLAVE:
_dump_evt("child lost", addr);
break;
default:
/* not interested in any other BLE events here */
break;
}
}
int main(void)
{
puts("RPL-over-BLE Example Application");
/* register the custom event handler */
nimble_rpble_eventcb(_on_rpble_event);
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets (ping) */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
/* start shell */
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}

View File

@ -0,0 +1,23 @@
BOARD ?= nrf52dk
include ../Makefile.tests_common
# include shell support
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Include GNRC and RPL
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_router_default
USEMODULE += auto_init_gnrc_rpl
USEMODULE += gnrc_rpl
USEMODULE += gnrc_icmpv6_echo
# Setup Nimble
USEMODULE += nimble_statconn_ext
FEATURES_OPTIONAL += ble_phy_2mbit
FEATURES_OPTIONAL += ble_phy_coded
TEST_ON_CI_WHITELIST += nrf52dk nrf52840dk
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,4 @@
BOARD_INSUFFICIENT_MEMORY := \
e104-bt5010a-tb \
e104-bt5011a-tb \
#

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2020 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 examples
* @{
*
* @file
* @brief Run IP-over-BLE using the 'statconn' BLE connection manager
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "msg.h"
#include "nimble_statconn.h"
#include "net/bluetil/addr.h"
#define MAIN_QUEUE_SIZE (8)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
static void _print_evt(const char *msg, int handle, const uint8_t *addr)
{
printf("[ble] %s (%i|", msg, handle);
if (addr) {
bluetil_addr_print(addr);
}
else {
printf("n/a");
}
puts(")");
}
static void _on_ble_evt(int handle, nimble_netif_event_t event,
const uint8_t *addr)
{
switch (event) {
case NIMBLE_NETIF_CONNECTED_MASTER:
_print_evt("CONNECTED master", handle, addr);
break;
case NIMBLE_NETIF_CONNECTED_SLAVE:
_print_evt("CONNECTED slave", handle, addr);
break;
case NIMBLE_NETIF_CLOSED_MASTER:
_print_evt("CLOSED master", handle, addr);
break;
case NIMBLE_NETIF_CLOSED_SLAVE:
_print_evt("CLOSED slave", handle, addr);
break;
case NIMBLE_NETIF_CONN_UPDATED:
_print_evt("UPDATED", handle, addr);
break;
default:
/* do nothing */
return;
}
}
int main(void)
{
puts("IPv6-over-BLE with statconn BLE connection manager");
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
/* register for BLE events */
nimble_statconn_eventcb(_on_ble_evt);
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should never be reached */
return 0;
}