mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 04:52:59 +01:00
pkg/nimble: add 'autoconn' connection manager
This commit is contained in:
parent
a7d951a0d7
commit
004eb5e0b6
@ -59,6 +59,7 @@ PSEUDOMODULES += netstats_l2
|
||||
PSEUDOMODULES += netstats_ipv6
|
||||
PSEUDOMODULES += netstats_rpl
|
||||
PSEUDOMODULES += nimble
|
||||
PSEUDOMODULES += nimble_autoconn_%
|
||||
PSEUDOMODULES += newlib
|
||||
PSEUDOMODULES += newlib_gnu_source
|
||||
PSEUDOMODULES += newlib_nano
|
||||
|
@ -21,7 +21,8 @@ else
|
||||
CFLAGS += -Wno-unused-but-set-variable
|
||||
endif
|
||||
|
||||
SUBMODS := $(filter nimble_%,$(USEMODULE))
|
||||
IGNORE := nimble_autoconn_%
|
||||
SUBMODS := $(filter-out $(IGNORE),$(filter nimble_%,$(USEMODULE)))
|
||||
|
||||
.PHONY: all
|
||||
|
||||
@ -74,6 +75,9 @@ nimble_drivers_nrf5x:
|
||||
nimble_addr:
|
||||
"$(MAKE)" -C $(TDIR)/addr/
|
||||
|
||||
nimble_autoconn:
|
||||
"$(MAKE)" -C $(TDIR)/autoconn
|
||||
|
||||
nimble_netif:
|
||||
"$(MAKE)" -C $(TDIR)/netif/
|
||||
|
||||
|
@ -39,6 +39,16 @@ ifneq (,$(filter nimble_addr,$(USEMODULE)))
|
||||
USEMODULE += bluetil_addr
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nimble_autoconn_%,$(USEMODULE)))
|
||||
USEMODULE += nimble_autoconn
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nimble_autoconn,$(USEMODULE)))
|
||||
USEMODULE += nimble_netif
|
||||
USEMODULE += nimble_scanner
|
||||
USEMODULE += bluetil_ad
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nimble_scanlist,$(USEMODULE)))
|
||||
USEMODULE += nimble_addr
|
||||
USEMODULE += bluetil_ad
|
||||
|
@ -76,6 +76,9 @@ endif
|
||||
ifneq (,$(filter nimble_addr,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTPKG)/nimble/addr/include
|
||||
endif
|
||||
ifneq (,$(filter nimble_autoconn,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTPKG)/nimble/autoconn/include
|
||||
endif
|
||||
ifneq (,$(filter nimble_netif,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTPKG)/nimble/netif/include
|
||||
|
||||
|
3
pkg/nimble/autoconn/Makefile
Normal file
3
pkg/nimble/autoconn/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = nimble_autoconn
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
202
pkg/nimble/autoconn/include/nimble_autoconn.h
Normal file
202
pkg/nimble/autoconn/include/nimble_autoconn.h
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup pkg_nimble_autoconn Autoconn
|
||||
* @ingroup pkg_nimble
|
||||
* @brief Simple connection manager that automatically opens BLE
|
||||
* connections to any node that fits some given filter criteria
|
||||
*
|
||||
* @experimental
|
||||
*
|
||||
* # WARNING
|
||||
* This module is highly experimental! Expect bugs, instabilities and sudden API
|
||||
* changes :-)
|
||||
*
|
||||
*
|
||||
* # About
|
||||
* This NimBLE submodule implements a connection manager for BLE. It takes care
|
||||
* of scanning, advertising, and opening connections to neighboring nodes. For
|
||||
* this autoconn periodically switches between advertising and scanning mode,
|
||||
* hence from accepting incoming connection requests to scanning actively for
|
||||
* new neighbors.
|
||||
*
|
||||
*
|
||||
* # Concept
|
||||
* The IETF and BT SIG standards describing IP-over-BLE only describe how to
|
||||
* transfer IP data over L2CAP connection oriented channels. But they do not
|
||||
* say anything about when BLE connections should be established between two
|
||||
* BLE nodes in the first place. While this can be done manually (e.g. via RIOTs
|
||||
* `ble` shell command), this is certainly no option in massive M2M deployments.
|
||||
*
|
||||
* To enable nodes to automatically connect to their neighbors, autoconn
|
||||
* implements a naive strategy which makes nodes to connect to any neighbor they
|
||||
* see, as long as the neighbor signals a predefined set of capabilities.
|
||||
*
|
||||
* In particular, neighbors are simply filtered by looking at the 16-bit service
|
||||
* UUIDs included in the `Incomplete List of 16-bit Service UUIDs` field in the
|
||||
* advertising data that is received from neighbors.
|
||||
*
|
||||
* The logical network topology (as seen by IP) is formed by the established
|
||||
* BLE link layer connections. It is important to node, that the autoconn module
|
||||
* will form a random topology on the link layer, as no further context
|
||||
* information is used for the connection decisions. This can potentially lead
|
||||
* to fragmented, non-connected sub-networks in larger deployments!
|
||||
*
|
||||
*
|
||||
* # State Machine
|
||||
* Autoconn implements a state machine, that switches a nodes role periodically
|
||||
* between scanning and advertising. To make sure, that nodes always have a
|
||||
* chance to see each other, especially when booted at the same point in time,
|
||||
* the intervals of each role consist of a constant amount of time plus a
|
||||
* random interval. This way two nodes will eventually see each other and be
|
||||
* able to establish a connection.
|
||||
*
|
||||
* All timing values for the interval duration and the maximum amount of the
|
||||
* random offset are configurable.
|
||||
*
|
||||
*
|
||||
* # Usage
|
||||
* In the current state, the filtering of neighbors is hard coded into the
|
||||
* autoconn module. Two options are implemented:
|
||||
*
|
||||
* 1. connect to any neighbor capable of IP-over-BLE -> @ref BLE_GATT_SVC_IPSS
|
||||
* UUID included in the BLE_GAP_AD_UUID16_INCOMP field of the received
|
||||
* advertising data
|
||||
* 2. connect to any neighbor capable of NDN-over-BLE -> @ref BLE_GATT_SVC_NDNSS
|
||||
* UUID included in the BLE_GAP_AD_UUID16_INCOMP field of the received
|
||||
* advertising data
|
||||
*
|
||||
* The active filter used in autoconn is selected using one of two submodules
|
||||
* during build time:
|
||||
*
|
||||
* 1. `USEMDOULE += nimble_autoconn_ipsp`
|
||||
* 2. `USEMODULE += nibmle_autoconn_ndnsp'
|
||||
*
|
||||
* @note The NDN support service (NDNSP) is defined by us and it is not at
|
||||
* all standardized nor sanctioned by the BT SIG. For experimental use
|
||||
* only...
|
||||
*
|
||||
*
|
||||
* # Implementation Status
|
||||
* - The filter function could be more powerful. It is probably a good idea to
|
||||
* extend this module to allow for passing custom filter functions using a
|
||||
* function pointer
|
||||
* - Currently this module does not allow to use NimBLE as IP-over-BLE node and
|
||||
* as a GATT server concurrently. This could be enabled by adding an
|
||||
* additional callback function which exposes some/all GAP events to a user
|
||||
* application (i.e. BLE_GAP_EVENT_SUBSCRIBE, BLE_GAP_EVENT_NOTIFY_RX,
|
||||
* BLE_GAP_EVENT_NOTIFY_TX).
|
||||
* - It might make sense to get rid of the periodic switching between scanning
|
||||
* and advertising in favor of doing both in parallel. This would simplify the
|
||||
* code (and configuration) quite a bit. But in the past, there were severe
|
||||
* stability issues with NimBLE doing this, so it needs to be evaluated in the
|
||||
* future if this is a feasible option.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Simple automated connection manager for NimBLE netif
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_AUTOCONN_H
|
||||
#define NIMBLE_AUTOCONN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return codes used by the autoconn module
|
||||
*/
|
||||
enum {
|
||||
NIMBLE_AUTOCONN_OK = 0, /**< like a walk in the park */
|
||||
NIMBLE_AUTOCONN_PARAMERR = -1, /**< invalid parameters given */
|
||||
NIMBLE_AUTOCONN_ADERR = -2, /**< error generating advertising data */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set of configuration parameters needed to run autoconn
|
||||
*/
|
||||
typedef struct {
|
||||
/** amount of time spend in scanning mode [in ms] */
|
||||
uint32_t period_scan;
|
||||
/** amount of time spend in advertising mode [in ms] */
|
||||
uint32_t period_adv;
|
||||
/** 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;
|
||||
/** advertising interval used when in advertising mode [in ms] */
|
||||
uint32_t adv_itvl;
|
||||
/** scan interval applied while in scanning state [in ms] */
|
||||
uint32_t scan_itvl;
|
||||
/** scan window applied while in scanning state [in ms] */
|
||||
uint32_t scan_win;
|
||||
/** connection interval used when opening a new connection [in ms] */
|
||||
uint32_t conn_itvl;
|
||||
/** slave latency used for new connections [in ms] */
|
||||
uint16_t conn_latency;
|
||||
/** supervision timeout used for new connections [in ms] */
|
||||
uint32_t conn_super_to;
|
||||
/** node ID included in the advertising data, may be NULL */
|
||||
const char *node_id;
|
||||
} nimble_autoconn_params_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize and enable the autoconn module
|
||||
*
|
||||
* @warning This function **must** only be called once. Typically this is during
|
||||
* system initialization or at the beginning of the user application.
|
||||
* Use nimble_autoconn_update() to update parameters at runtime.
|
||||
*
|
||||
* @warning Autoconn expects nimble_netif to be initialized. So make sure
|
||||
* nimble_netif_init() was called before calling nimble_autoconn_init().
|
||||
*
|
||||
* @param[in] params timing parameters to use
|
||||
* @param[in] ad advertising data, if NULL it is generated
|
||||
* @param[in] adlen length of @p ad in bytes
|
||||
*/
|
||||
int nimble_autoconn_init(const nimble_autoconn_params_t *params,
|
||||
const uint8_t *ad, size_t adlen);
|
||||
|
||||
/**
|
||||
* @brief Update the used parameters (timing and node ID)
|
||||
*
|
||||
* @param[in] params new parameters to apply
|
||||
* @param[in] ad advertising data, if NULL it is generated
|
||||
* @param[in] adlen length of @p ad in bytes
|
||||
*
|
||||
* @return NIMBLE_AUTOCONN_OK if everything went fine
|
||||
* @return NIMBLE_AUTOCONN_INVALID if given parameters can not be applied
|
||||
*/
|
||||
int nimble_autoconn_update(const nimble_autoconn_params_t *params,
|
||||
const uint8_t *ad, size_t adlen);
|
||||
|
||||
/**
|
||||
* @brief Enable automated creation of new BLE connections
|
||||
*/
|
||||
void nimble_autoconn_enable(void);
|
||||
|
||||
/**
|
||||
* @brief Disable the automated connection management
|
||||
*
|
||||
* @note All existing connections are kept, only the scanning and advertising
|
||||
* is canceled
|
||||
*/
|
||||
void nimble_autoconn_disable(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NIMBLE_AUTOCONN_H */
|
||||
/** @} */
|
91
pkg/nimble/autoconn/include/nimble_autoconn_params.h
Normal file
91
pkg/nimble/autoconn/include/nimble_autoconn_params.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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 pkg_nimble_autoconn
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief Default configuration for the nimble_autoconn module
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_AUTOCONN_PARAMS_H
|
||||
#define NIMBLE_AUTOCONN_PARAMS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Default parameters used for the nimble_netif_autoconn module
|
||||
* @{
|
||||
*/
|
||||
#ifndef NIMBLE_AUTOCONN_PERIOD_SCAN
|
||||
#define NIMBLE_AUTOCONN_PERIOD_SCAN (2000U) /* 2s */
|
||||
#endif
|
||||
#ifndef NIMBLE_AUTOCONN_PERIOD_ADV
|
||||
#define NIMBLE_AUTOCONN_PERIOD_ADV (10000U) /* 10s */
|
||||
#endif
|
||||
#ifndef NIMBLE_AUTOCONN_PERIOD_JITTER
|
||||
#define NIMBLE_AUTOCONN_PERIOD_JITTER (5000U) /* 0-5s */
|
||||
#endif
|
||||
|
||||
#ifndef NIMBLE_AUTOCONN_ADV_ITVL
|
||||
#define NIMBLE_AUTOCONN_ADV_ITVL (100U) /* 100ms */
|
||||
#endif
|
||||
|
||||
#ifndef NIMBLE_AUTOCONN_SCAN_ITVL
|
||||
#define NIMBLE_AUTOCONN_SCAN_ITVL (1500U) /* 1.5s */
|
||||
#endif
|
||||
#ifndef NIMBLE_AUTOCONN_SCAN_WIN
|
||||
#define NIMBLE_AUTOCONN_SCAN_WIN (110U) /* 110ms */
|
||||
#endif
|
||||
|
||||
#ifndef NIMBLE_AUTOCONN_CONN_ITVL
|
||||
#define NIMBLE_AUTOCONN_CONN_ITVL (75U) /* 75ms */
|
||||
#endif
|
||||
#ifndef NIMBLE_AUTOCONN_CONN_LATENCY
|
||||
#define NIMBLE_AUTOCONN_CONN_LATENCY (0)
|
||||
#endif
|
||||
#ifndef NIMBLE_AUTOCONN_CONN_SUPER_TO
|
||||
#define NIMBLE_AUTOCONN_CONN_SUPER_TO (2500U) /* 2.5s */
|
||||
#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, \
|
||||
.period_adv = NIMBLE_AUTOCONN_PERIOD_ADV, \
|
||||
.period_jitter = NIMBLE_AUTOCONN_PERIOD_JITTER, \
|
||||
.adv_itvl = NIMBLE_AUTOCONN_ADV_ITVL, \
|
||||
.scan_itvl = NIMBLE_AUTOCONN_SCAN_ITVL, \
|
||||
.scan_win = NIMBLE_AUTOCONN_SCAN_WIN, \
|
||||
.conn_itvl = NIMBLE_AUTOCONN_CONN_ITVL, \
|
||||
.conn_latency = NIMBLE_AUTOCONN_CONN_LATENCY, \
|
||||
.conn_super_to = NIMBLE_AUTOCONN_CONN_SUPER_TO, \
|
||||
.node_id = NIMBLE_AUTOCONN_NODE_ID, }
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @brief nimble_netif_autoconn configuration
|
||||
*/
|
||||
static const nimble_autoconn_params_t nimble_autoconn_params =
|
||||
NIMBLE_AUTOCONN_PARAMS;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NIMBLE_AUTOCONN_PARAMS_H */
|
||||
/** @} */
|
301
pkg/nimble/autoconn/nimble_autoconn.c
Normal file
301
pkg/nimble/autoconn/nimble_autoconn.c
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2018-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 pkg_nimble_autoconn
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Autoconn connection manager implementation
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "random.h"
|
||||
#include "net/bluetil/ad.h"
|
||||
#include "net/bluetil/addr.h"
|
||||
#include "nimble_netif.h"
|
||||
#include "nimble_netif_conn.h"
|
||||
#include "nimble_scanner.h"
|
||||
#include "nimble_autoconn.h"
|
||||
#include "nimble_autoconn_params.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if defined(MODULE_NIMBLE_AUTOCONN_IPSP)
|
||||
#define SVC_FILTER BLE_GATT_SVC_IPSS
|
||||
#elif defined(MODULE_NIMBLE_AUTOCONN_NDNSP)
|
||||
#define SVC_FILTER BLE_GATT_SVC_NDNSS
|
||||
#else
|
||||
#error "NimBLE autoconn: please select a fitting submodule"
|
||||
#endif
|
||||
|
||||
#define CONN_TIMEOUT_MUL (5U)
|
||||
|
||||
enum {
|
||||
STATE_SCAN,
|
||||
STATE_ADV,
|
||||
STATE_IDLE,
|
||||
STATE_CONN,
|
||||
};
|
||||
|
||||
static volatile uint8_t _state = STATE_IDLE;
|
||||
|
||||
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 struct ble_npl_callout _state_evt;
|
||||
static ble_npl_time_t _timeout_adv_period;
|
||||
static ble_npl_time_t _timeout_scan_period;
|
||||
static ble_npl_time_t _period_jitter;
|
||||
|
||||
/* this is run inside the NimBLE host thread */
|
||||
static void _on_state_change(struct ble_npl_event *ev)
|
||||
{
|
||||
(void)ev;
|
||||
ble_npl_time_t offset;
|
||||
offset = (ble_npl_time_t)random_uint32_range(0, (uint32_t)_period_jitter);
|
||||
|
||||
if (_state == STATE_SCAN) {
|
||||
/* stop scanning */
|
||||
nimble_scanner_stop();
|
||||
/* start advertising/accepting */
|
||||
int res = nimble_netif_accept(_ad.buf, _ad.pos, &_adv_params);
|
||||
assert((res == NIMBLE_NETIF_OK) || (res == NIMBLE_NETIF_NOMEM));
|
||||
(void)res;
|
||||
|
||||
/* schedule next state change */
|
||||
_state = STATE_ADV;
|
||||
ble_npl_callout_reset(&_state_evt, (_timeout_adv_period + offset));
|
||||
}
|
||||
else if (_state == STATE_ADV) {
|
||||
/* stop advertising/accepting */
|
||||
nimble_netif_accept_stop();
|
||||
/* start scanning */
|
||||
nimble_scanner_start();
|
||||
_state = STATE_SCAN;
|
||||
ble_npl_callout_reset(&_state_evt, (_timeout_scan_period + offset));
|
||||
}
|
||||
}
|
||||
|
||||
static int _filter_uuid(const bluetil_ad_t *ad)
|
||||
{
|
||||
bluetil_ad_data_t incomp;
|
||||
if (bluetil_ad_find(ad, BLE_GAP_AD_UUID16_INCOMP, &incomp) == BLUETIL_AD_OK) {
|
||||
uint16_t filter_uuid = SVC_FILTER;
|
||||
for (unsigned i = 0; i < incomp.len; i += 2) {
|
||||
if (memcmp(&filter_uuid, &incomp.data[i], 2) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _on_scan_evt(uint8_t type, const ble_addr_t *addr, int8_t rssi,
|
||||
const uint8_t *ad_buf, size_t ad_len)
|
||||
{
|
||||
(void)rssi;
|
||||
|
||||
/* we are only interested in ADV_IND packets, the rest can be dropped right
|
||||
* away */
|
||||
if (type != BLE_HCI_ADV_TYPE_ADV_IND) {
|
||||
return;
|
||||
}
|
||||
|
||||
bluetil_ad_t ad = {
|
||||
.buf = (uint8_t *)ad_buf,
|
||||
.pos = ad_len,
|
||||
.size = ad_len
|
||||
};
|
||||
|
||||
/* for connection checking we need the address in network byte order */
|
||||
uint8_t addrn[BLE_ADDR_LEN];
|
||||
bluetil_addr_swapped_cp(addr->val, addrn);
|
||||
|
||||
if (_filter_uuid(&ad) && !nimble_netif_conn_connected(addrn)) {
|
||||
nimble_autoconn_disable();
|
||||
_state = STATE_CONN;
|
||||
int res = nimble_netif_connect(addr, &_conn_params, _conn_timeout);
|
||||
assert(res >= 0);
|
||||
(void)res;
|
||||
DEBUG("[autoconn] SCAN success, initiating connection\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _on_netif_evt(int handle, nimble_netif_event_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case NIMBLE_NETIF_CONNECTED_MASTER:
|
||||
DEBUG("[autoconn] CONNECTED as master %i\n", handle);
|
||||
assert(_state == STATE_CONN);
|
||||
_state = STATE_IDLE;
|
||||
nimble_autoconn_enable();
|
||||
break;
|
||||
case NIMBLE_NETIF_CONNECTED_SLAVE:
|
||||
DEBUG("[autoconn] CONNECTED as slave %i\n", handle);
|
||||
nimble_autoconn_enable();
|
||||
break;
|
||||
case NIMBLE_NETIF_CLOSED_MASTER:
|
||||
DEBUG("[autoconn] CLOSED master connection\n");
|
||||
nimble_autoconn_enable();
|
||||
break;
|
||||
case NIMBLE_NETIF_CLOSED_SLAVE:
|
||||
DEBUG("[autoconn] CLOSED slave connection\n");
|
||||
nimble_autoconn_enable();
|
||||
break;
|
||||
case NIMBLE_NETIF_CONNECT_ABORT:
|
||||
DEBUG("[autoconn] CONNECT ABORT\n");
|
||||
assert(_state == STATE_CONN);
|
||||
_state = STATE_IDLE;
|
||||
nimble_autoconn_enable();
|
||||
break;
|
||||
case NIMBLE_NETIF_CONN_UPDATED:
|
||||
DEBUG("[autoconn] CONNECTION UPDATED %i\n", handle);
|
||||
/* nothing to do here */
|
||||
break;
|
||||
default:
|
||||
/* this should never happen */
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int _conn_update(nimble_netif_conn_t *conn, int handle, void *arg)
|
||||
{
|
||||
(void)conn;
|
||||
nimble_netif_update(handle, (const struct ble_gap_upd_params *)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nimble_autoconn_init(const nimble_autoconn_params_t *params,
|
||||
const uint8_t *ad, size_t adlen)
|
||||
{
|
||||
/* register our event callback */
|
||||
nimble_netif_eventcb(_on_netif_evt);
|
||||
/* setup state machine timer (we use NimBLEs callouts for this) */
|
||||
ble_npl_callout_init(&_state_evt, nimble_port_get_dflt_eventq(),
|
||||
_on_state_change, NULL);
|
||||
/* at last, set the given parameters */
|
||||
return nimble_autoconn_update(params, ad, adlen);
|
||||
}
|
||||
|
||||
int nimble_autoconn_update(const nimble_autoconn_params_t *params,
|
||||
const uint8_t *ad, size_t adlen)
|
||||
{
|
||||
int res;
|
||||
(void)res;
|
||||
|
||||
if ((params == NULL) || (adlen > sizeof(_ad_buf)) ||
|
||||
((adlen > 0) && (ad == NULL))) {
|
||||
return NIMBLE_AUTOCONN_PARAMERR;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* populate the connection parameters */
|
||||
_conn_params.scan_itvl = ((params->scan_itvl * 1000) / BLE_HCI_SCAN_ITVL);
|
||||
_conn_params.scan_window = ((params->scan_win * 1000) / BLE_HCI_SCAN_ITVL);
|
||||
_conn_params.itvl_min = ((params->conn_itvl * 1000) / BLE_HCI_CONN_ITVL);
|
||||
_conn_params.itvl_max = ((params->conn_itvl * 1000) / BLE_HCI_CONN_ITVL);
|
||||
_conn_params.latency = 0;
|
||||
_conn_params.supervision_timeout = (params->conn_super_to / 10);
|
||||
_conn_params.min_ce_len = 0;
|
||||
_conn_params.max_ce_len = 0;
|
||||
_conn_timeout = params->adv_itvl * CONN_TIMEOUT_MUL;
|
||||
|
||||
/* 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.min_ce_len = 0;
|
||||
conn_update_params.max_ce_len = 0;
|
||||
|
||||
/* calculate the used scan parameters */
|
||||
struct ble_gap_disc_params scan_params;
|
||||
scan_params.itvl = ((params->scan_itvl * 1000) / BLE_HCI_SCAN_ITVL),
|
||||
scan_params.window = ((params->scan_win * 1000) / BLE_HCI_SCAN_ITVL),
|
||||
scan_params.filter_policy = 0,
|
||||
scan_params.limited = 0,
|
||||
scan_params.passive = 0,
|
||||
scan_params.filter_duplicates = 1,
|
||||
|
||||
/* 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 = ((params->adv_itvl * 1000) / BLE_HCI_ADV_ITVL);
|
||||
_adv_params.itvl_max = ((params->adv_itvl * 1000) / BLE_HCI_ADV_ITVL);
|
||||
_adv_params.channel_map = 0;
|
||||
_adv_params.filter_policy = 0;
|
||||
_adv_params.high_duty_cycle = 0;
|
||||
|
||||
/* initialize the advertising data that will be used */
|
||||
if (adlen > 0) {
|
||||
memcpy(_ad_buf, ad, adlen);
|
||||
bluetil_ad_init(&_ad, _ad_buf, adlen, sizeof(_ad_buf));
|
||||
}
|
||||
else {
|
||||
uint16_t svc = SVC_FILTER;
|
||||
bluetil_ad_init_with_flags(&_ad, _ad_buf, sizeof(_ad_buf),
|
||||
BLUETIL_AD_FLAGS_DEFAULT);
|
||||
bluetil_ad_add(&_ad, BLE_GAP_AD_UUID16_INCOMP, &svc, sizeof(svc));
|
||||
if (params->node_id) {
|
||||
res = bluetil_ad_add(&_ad, BLE_GAP_AD_NAME,
|
||||
params->node_id, strlen(params->node_id));
|
||||
if (res != BLUETIL_AD_OK) {
|
||||
return NIMBLE_AUTOCONN_ADERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize scanner with default parameters */
|
||||
nimble_scanner_init(&scan_params, _on_scan_evt);
|
||||
|
||||
/* we also need to apply the new connection parameters to all BLE
|
||||
* connections where we are in the MASTER role */
|
||||
nimble_netif_conn_foreach(NIMBLE_NETIF_GAP_MASTER, _conn_update,
|
||||
&conn_update_params);
|
||||
|
||||
return NIMBLE_AUTOCONN_OK;
|
||||
}
|
||||
|
||||
void nimble_autoconn_enable(void)
|
||||
{
|
||||
DEBUG("[autoconn] ACTIVE\n");
|
||||
if (nimble_netif_conn_count(NIMBLE_NETIF_UNUSED) > 0) {
|
||||
_state = STATE_ADV;
|
||||
_on_state_change(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void nimble_autoconn_disable(void)
|
||||
{
|
||||
DEBUG("[autoconn] DISABLED\n");
|
||||
if ((_state == STATE_ADV) || (_state == STATE_SCAN)) {
|
||||
_state = STATE_IDLE;
|
||||
ble_npl_callout_stop(&_state_evt);
|
||||
nimble_scanner_stop();
|
||||
nimble_netif_accept_stop();
|
||||
}
|
||||
}
|
@ -35,6 +35,11 @@
|
||||
#include "services/ipss/ble_svc_ipss.h"
|
||||
#endif
|
||||
|
||||
#if defined(MODULE_NIMBLE_AUTOCONN) && !defined(MODULE_NIMBLE_AUTOCONN_NOAUTOINIT)
|
||||
#include "nimble_autoconn.h"
|
||||
#include "nimble_autoconn_params.h"
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_NIMBLE_CONTROLLER
|
||||
#if defined(CPU_FAM_NRF52) || defined(CPU_FAM_NRF51)
|
||||
#include "nrf_clock.h"
|
||||
@ -81,6 +86,9 @@ static void *_host_thread(void *arg)
|
||||
|
||||
void nimble_riot_init(void)
|
||||
{
|
||||
int res;
|
||||
(void)res;
|
||||
|
||||
/* and finally initialize and run the host */
|
||||
thread_create(_stack_host, sizeof(_stack_host),
|
||||
NIMBLE_HOST_PRIO,
|
||||
@ -94,11 +102,10 @@ void nimble_riot_init(void)
|
||||
|
||||
/* for reducing code duplication, we read our own address type once here
|
||||
* so it can be re-used later on */
|
||||
int res = ble_hs_util_ensure_addr(0);
|
||||
res = ble_hs_util_ensure_addr(0);
|
||||
assert(res == 0);
|
||||
res = ble_hs_id_infer_auto(0, &nimble_riot_own_addr_type);
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
|
||||
#ifdef MODULE_NIMBLE_NETIF
|
||||
extern void nimble_netif_init(void);
|
||||
@ -119,4 +126,13 @@ void nimble_riot_init(void)
|
||||
#ifdef MODULE_NIMBLE_SVC_IPSS
|
||||
ble_svc_ipss_init();
|
||||
#endif
|
||||
|
||||
#if defined(MODULE_NIMBLE_AUTOCONN) && !defined(MODULE_NIMBLE_AUTOCONN_NOAUTOINIT)
|
||||
ble_gatts_start();
|
||||
/* CAUTION: this must be called after nimble_netif_init() and also only
|
||||
* after the GATT server has been initialized */
|
||||
res = nimble_autoconn_init(&nimble_autoconn_params, NULL, 0);
|
||||
assert(res == NIMBLE_AUTOCONN_OK);
|
||||
nimble_autoconn_enable();
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user