Bluetooth: Mesh: Extended advertising support
Adds support for extended advertiser commands in the mesh. This doubles throughput for common packet sending, and significantly improves timing accuracy for the Friend and Low Power features. The proxy module's advertisement control has been moved inside the adv module to abstract away the different advertiser modes. The extended advertiser mode does not need an advertising thread to operate, and ends up with a net reduction in RAM usage. Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no>
This commit is contained in:
parent
e52fabcf3c
commit
81bf99145a
10 changed files with 617 additions and 233 deletions
|
@ -20,6 +20,10 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH
|
|||
health_srv.c
|
||||
)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_ADV_LEGACY adv_legacy.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_ADV_EXT adv_ext.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_SETTINGS settings.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_LOW_POWER lpn.c)
|
||||
|
|
|
@ -228,8 +228,32 @@ config BT_MESH_ADV_BUF_COUNT
|
|||
be at least three more advertising buffers than the maximum
|
||||
supported outgoing segment count (BT_MESH_TX_SEG_MAX).
|
||||
|
||||
choice BT_MESH_ADV
|
||||
prompt "Advertiser mode"
|
||||
default BT_MESH_ADV_EXT if BT_EXT_ADV
|
||||
default BT_MESH_ADV_LEGACY
|
||||
|
||||
config BT_MESH_ADV_LEGACY
|
||||
bool "Legacy advertising"
|
||||
help
|
||||
Use legacy advertising commands for mesh sending. Legacy
|
||||
advertising is significantly slower than the extended advertising, but
|
||||
is supported by all controllers.
|
||||
|
||||
config BT_MESH_ADV_EXT
|
||||
bool "Extended advertising"
|
||||
depends on BT_CTLR_ADV_EXT || !BT_CTLR
|
||||
depends on BT_EXT_ADV
|
||||
help
|
||||
Use extended advertising commands for operating the advertiser.
|
||||
Extended advertising is faster and uses less memory than legacy
|
||||
advertising, but isn't supported by all controllers.
|
||||
|
||||
endchoice
|
||||
|
||||
config BT_MESH_ADV_STACK_SIZE
|
||||
int "Mesh advertiser thread stack size"
|
||||
depends on BT_MESH_ADV_LEGACY
|
||||
default 1024 if BT_HOST_CRYPTO
|
||||
default 768
|
||||
help
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#define LOG_MODULE_NAME bt_mesh_adv
|
||||
#include "common/log.h"
|
||||
|
||||
#include "host/hci_core.h"
|
||||
|
||||
#include "adv.h"
|
||||
#include "net.h"
|
||||
#include "foundation.h"
|
||||
|
@ -30,24 +28,18 @@
|
|||
#include "prov.h"
|
||||
#include "proxy.h"
|
||||
|
||||
/* Convert from ms to 0.625ms units */
|
||||
#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5)
|
||||
|
||||
/* Window and Interval are equal for continuous scanning */
|
||||
#define MESH_SCAN_INTERVAL_MS 30
|
||||
#define MESH_SCAN_WINDOW_MS 30
|
||||
#define MESH_SCAN_INTERVAL ADV_SCAN_UNIT(MESH_SCAN_INTERVAL_MS)
|
||||
#define MESH_SCAN_WINDOW ADV_SCAN_UNIT(MESH_SCAN_WINDOW_MS)
|
||||
#define MESH_SCAN_INTERVAL BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_INTERVAL_MS)
|
||||
#define MESH_SCAN_WINDOW BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_WINDOW_MS)
|
||||
|
||||
/* Pre-5.0 controllers enforce a minimum interval of 100ms
|
||||
* whereas 5.0+ controllers can go down to 20ms.
|
||||
*/
|
||||
#define ADV_INT_DEFAULT_MS 100
|
||||
#define ADV_INT_FAST_MS 20
|
||||
const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES] = {
|
||||
[BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV,
|
||||
[BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE,
|
||||
[BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON,
|
||||
[BT_MESH_ADV_URI] = BT_DATA_URI,
|
||||
};
|
||||
|
||||
static K_FIFO_DEFINE(adv_queue);
|
||||
static struct k_thread adv_thread_data;
|
||||
static K_KERNEL_STACK_DEFINE(adv_thread_stack, CONFIG_BT_MESH_ADV_STACK_SIZE);
|
||||
K_FIFO_DEFINE(bt_mesh_adv_queue);
|
||||
|
||||
NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BT_MESH_ADV_BUF_COUNT,
|
||||
BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, NULL);
|
||||
|
@ -59,134 +51,6 @@ static struct bt_mesh_adv *adv_alloc(int id)
|
|||
return &adv_pool[id];
|
||||
}
|
||||
|
||||
static inline void adv_send_start(uint16_t duration, int err,
|
||||
const struct bt_mesh_send_cb *cb,
|
||||
void *cb_data)
|
||||
{
|
||||
if (cb && cb->start) {
|
||||
cb->start(duration, err, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb,
|
||||
void *cb_data)
|
||||
{
|
||||
if (cb && cb->end) {
|
||||
cb->end(err, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void adv_send(struct net_buf *buf)
|
||||
{
|
||||
static const uint8_t adv_type[] = {
|
||||
[BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV,
|
||||
[BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE,
|
||||
[BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON,
|
||||
[BT_MESH_ADV_URI] = BT_DATA_URI,
|
||||
};
|
||||
const int32_t adv_int_min = ((bt_dev.hci_version >= BT_HCI_VERSION_5_0) ?
|
||||
ADV_INT_FAST_MS : ADV_INT_DEFAULT_MS);
|
||||
const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
|
||||
void *cb_data = BT_MESH_ADV(buf)->cb_data;
|
||||
struct bt_le_adv_param param = {};
|
||||
uint16_t duration, adv_int;
|
||||
struct bt_data ad;
|
||||
int err;
|
||||
|
||||
adv_int = MAX(adv_int_min,
|
||||
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
|
||||
duration = (MESH_SCAN_WINDOW_MS +
|
||||
((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
|
||||
(adv_int + 10)));
|
||||
|
||||
BT_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type,
|
||||
buf->len, bt_hex(buf->data, buf->len));
|
||||
BT_DBG("count %u interval %ums duration %ums",
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int,
|
||||
duration);
|
||||
|
||||
ad.type = adv_type[BT_MESH_ADV(buf)->type];
|
||||
ad.data_len = buf->len;
|
||||
ad.data = buf->data;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR)) {
|
||||
param.options = BT_LE_ADV_OPT_USE_IDENTITY;
|
||||
} else {
|
||||
param.options = 0U;
|
||||
}
|
||||
|
||||
param.id = BT_ID_DEFAULT;
|
||||
param.interval_min = ADV_SCAN_UNIT(adv_int);
|
||||
param.interval_max = param.interval_min;
|
||||
|
||||
err = bt_le_adv_start(¶m, &ad, 1, NULL, 0);
|
||||
net_buf_unref(buf);
|
||||
adv_send_start(duration, err, cb, cb_data);
|
||||
if (err) {
|
||||
BT_ERR("Advertising failed: err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("Advertising started. Sleeping %u ms", duration);
|
||||
|
||||
k_sleep(K_MSEC(duration));
|
||||
|
||||
err = bt_le_adv_stop();
|
||||
adv_send_end(err, cb, cb_data);
|
||||
if (err) {
|
||||
BT_ERR("Stopping advertising failed: err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("Advertising stopped");
|
||||
}
|
||||
|
||||
static void adv_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
BT_DBG("started");
|
||||
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY)) {
|
||||
buf = net_buf_get(&adv_queue, K_NO_WAIT);
|
||||
while (!buf) {
|
||||
k_timeout_t timeout;
|
||||
|
||||
timeout = bt_mesh_proxy_adv_start();
|
||||
BT_DBG("Proxy Advertising");
|
||||
|
||||
buf = net_buf_get(&adv_queue, timeout);
|
||||
bt_mesh_proxy_adv_stop();
|
||||
}
|
||||
} else {
|
||||
buf = net_buf_get(&adv_queue, K_FOREVER);
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* busy == 0 means this was canceled */
|
||||
if (BT_MESH_ADV(buf)->busy) {
|
||||
BT_MESH_ADV(buf)->busy = 0U;
|
||||
adv_send(buf);
|
||||
} else {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
/* Give other threads a chance to run */
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_adv_update(void)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
k_fifo_cancel_wait(&adv_queue);
|
||||
}
|
||||
|
||||
struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool,
|
||||
bt_mesh_adv_alloc_t get_id,
|
||||
enum bt_mesh_adv_type type,
|
||||
|
@ -233,7 +97,8 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb,
|
|||
BT_MESH_ADV(buf)->cb_data = cb_data;
|
||||
BT_MESH_ADV(buf)->busy = 1U;
|
||||
|
||||
net_buf_put(&adv_queue, net_buf_ref(buf));
|
||||
net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf));
|
||||
bt_mesh_adv_buf_ready();
|
||||
}
|
||||
|
||||
static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
|
||||
|
@ -287,14 +152,6 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
|
|||
}
|
||||
}
|
||||
|
||||
void bt_mesh_adv_init(void)
|
||||
{
|
||||
k_thread_create(&adv_thread_data, adv_thread_stack,
|
||||
K_KERNEL_STACK_SIZEOF(adv_thread_stack), adv_thread,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
k_thread_name_set(&adv_thread_data, "BT Mesh adv");
|
||||
}
|
||||
|
||||
int bt_mesh_scan_enable(void)
|
||||
{
|
||||
struct bt_le_scan_param scan_param = {
|
||||
|
|
|
@ -14,11 +14,17 @@
|
|||
|
||||
#define BT_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf))
|
||||
|
||||
#define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5)
|
||||
#define BT_MESH_SCAN_INTERVAL_MS 30
|
||||
#define BT_MESH_SCAN_WINDOW_MS 30
|
||||
|
||||
enum bt_mesh_adv_type {
|
||||
BT_MESH_ADV_PROV,
|
||||
BT_MESH_ADV_DATA,
|
||||
BT_MESH_ADV_BEACON,
|
||||
BT_MESH_ADV_URI,
|
||||
|
||||
BT_MESH_ADV_TYPES,
|
||||
};
|
||||
|
||||
typedef void (*bt_mesh_adv_func_t)(struct net_buf *buf, uint16_t duration,
|
||||
|
@ -35,6 +41,11 @@ struct bt_mesh_adv {
|
|||
|
||||
typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id);
|
||||
|
||||
extern struct k_fifo bt_mesh_adv_queue;
|
||||
|
||||
/* Lookup table for Advertising data types for bt_mesh_adv_type: */
|
||||
extern const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES];
|
||||
|
||||
/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */
|
||||
struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
|
||||
k_timeout_t timeout);
|
||||
|
@ -54,3 +65,28 @@ void bt_mesh_adv_init(void);
|
|||
int bt_mesh_scan_enable(void);
|
||||
|
||||
int bt_mesh_scan_disable(void);
|
||||
|
||||
int bt_mesh_adv_enable(void);
|
||||
|
||||
void bt_mesh_adv_buf_ready(void);
|
||||
|
||||
int bt_mesh_adv_start(const struct bt_le_adv_param *param, int32_t duration,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len);
|
||||
|
||||
static inline void bt_mesh_adv_send_start(uint16_t duration, int err,
|
||||
const struct bt_mesh_send_cb *cb,
|
||||
void *cb_data)
|
||||
{
|
||||
if (cb && cb->start) {
|
||||
cb->start(duration, err, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bt_mesh_adv_send_end(
|
||||
int err, const struct bt_mesh_send_cb *cb, void *cb_data)
|
||||
{
|
||||
if (cb && cb->end) {
|
||||
cb->end(err, cb_data);
|
||||
}
|
||||
}
|
||||
|
|
282
subsys/bluetooth/mesh/adv_ext.c
Normal file
282
subsys/bluetooth/mesh/adv_ext.c
Normal file
|
@ -0,0 +1,282 @@
|
|||
/* Bluetooth Mesh */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <debug/stack.h>
|
||||
|
||||
#include <net/buf.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/mesh.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_ADV)
|
||||
#define LOG_MODULE_NAME bt_mesh_adv_ext
|
||||
#include "common/log.h"
|
||||
|
||||
#include "host/hci_core.h"
|
||||
|
||||
#include "adv.h"
|
||||
#include "net.h"
|
||||
#include "proxy.h"
|
||||
|
||||
/* Convert from ms to 0.625ms units */
|
||||
#define ADV_INT_FAST_MS 20
|
||||
|
||||
static struct bt_le_adv_param adv_param = {
|
||||
.id = BT_ID_DEFAULT,
|
||||
.interval_min = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS),
|
||||
.interval_max = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS),
|
||||
#if defined(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR)
|
||||
.options = BT_LE_ADV_OPT_USE_IDENTITY,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum {
|
||||
/** Controller is currently advertising */
|
||||
ADV_FLAG_ACTIVE,
|
||||
/** Currently performing proxy advertising */
|
||||
ADV_FLAG_PROXY,
|
||||
/** The send-call has been scheduled. */
|
||||
ADV_FLAG_SCHEDULED,
|
||||
/** Custom adv params have been set, we need to update the parameters on
|
||||
* the next send.
|
||||
*/
|
||||
ADV_FLAG_UPDATE_PARAMS,
|
||||
|
||||
/* Number of adv flags. */
|
||||
ADV_FLAGS_NUM
|
||||
};
|
||||
|
||||
static struct {
|
||||
ATOMIC_DEFINE(flags, ADV_FLAGS_NUM);
|
||||
struct bt_le_ext_adv *instance;
|
||||
const struct bt_mesh_send_cb *cb;
|
||||
void *cb_data;
|
||||
uint64_t timestamp;
|
||||
struct k_delayed_work work;
|
||||
} adv;
|
||||
|
||||
static int adv_start(const struct bt_le_adv_param *param,
|
||||
struct bt_le_ext_adv_start_param *start,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!adv.instance) {
|
||||
BT_ERR("Mesh advertiser not enabled");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (atomic_test_and_set_bit(adv.flags, ADV_FLAG_ACTIVE)) {
|
||||
BT_ERR("Advertiser is busy");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS)) {
|
||||
err = bt_le_ext_adv_update_param(adv.instance, param);
|
||||
if (err) {
|
||||
BT_ERR("Failed updating adv params: %d", err);
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE);
|
||||
return err;
|
||||
}
|
||||
|
||||
atomic_set_bit_to(adv.flags, ADV_FLAG_UPDATE_PARAMS,
|
||||
param != &adv_param);
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_set_data(adv.instance, ad, ad_len, sd, sd_len);
|
||||
if (err) {
|
||||
BT_ERR("Failed setting adv data: %d", err);
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE);
|
||||
return err;
|
||||
}
|
||||
|
||||
adv.timestamp = k_uptime_get();
|
||||
|
||||
err = bt_le_ext_adv_start(adv.instance, start);
|
||||
if (err) {
|
||||
BT_ERR("Advertising failed: err %d", err);
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int buf_send(struct net_buf *buf)
|
||||
{
|
||||
struct bt_le_ext_adv_start_param start = {
|
||||
.num_events =
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1,
|
||||
};
|
||||
uint16_t duration, adv_int;
|
||||
struct bt_data ad;
|
||||
int err;
|
||||
|
||||
adv_int = MAX(ADV_INT_FAST_MS,
|
||||
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
|
||||
/* Upper boundary estimate: */
|
||||
duration = start.num_events * (adv_int + 10);
|
||||
|
||||
BT_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type,
|
||||
buf->len, bt_hex(buf->data, buf->len));
|
||||
BT_DBG("count %u interval %ums duration %ums",
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int,
|
||||
duration);
|
||||
|
||||
ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type];
|
||||
ad.data_len = buf->len;
|
||||
ad.data = buf->data;
|
||||
|
||||
/* Only update advertising parameters if they're different */
|
||||
if (adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_int)) {
|
||||
adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_int);
|
||||
adv_param.interval_max = adv_param.interval_min;
|
||||
atomic_set_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS);
|
||||
}
|
||||
|
||||
adv.cb = BT_MESH_ADV(buf)->cb;
|
||||
adv.cb_data = BT_MESH_ADV(buf)->cb_data;
|
||||
|
||||
err = adv_start(&adv_param, &start, &ad, 1, NULL, 0);
|
||||
net_buf_unref(buf);
|
||||
bt_mesh_adv_send_start(duration, err, adv.cb, adv.cb_data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void send_pending_adv(struct k_work *work)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
int err;
|
||||
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_SCHEDULED);
|
||||
|
||||
while ((buf = net_buf_get(&bt_mesh_adv_queue, K_NO_WAIT))) {
|
||||
/* busy == 0 means this was canceled */
|
||||
if (!BT_MESH_ADV(buf)->busy) {
|
||||
net_buf_unref(buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
BT_MESH_ADV(buf)->busy = 0U;
|
||||
err = buf_send(buf);
|
||||
if (!err) {
|
||||
return; /* Wait for advertising to finish */
|
||||
}
|
||||
}
|
||||
|
||||
/* No more pending buffers */
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY)) {
|
||||
BT_DBG("Proxy Advertising");
|
||||
err = bt_mesh_proxy_adv_start();
|
||||
if (!err) {
|
||||
atomic_set_bit(adv.flags, ADV_FLAG_PROXY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void schedule_send(void)
|
||||
{
|
||||
uint64_t timestamp = adv.timestamp;
|
||||
int64_t delta;
|
||||
|
||||
if (atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) {
|
||||
bt_le_ext_adv_stop(adv.instance);
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
if (atomic_test_bit(adv.flags, ADV_FLAG_ACTIVE) ||
|
||||
atomic_test_and_set_bit(adv.flags, ADV_FLAG_SCHEDULED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The controller will send the next advertisement immediately.
|
||||
* Introduce a delay here to avoid sending the next mesh packet closer
|
||||
* to the previous packet than what's permitted by the specification.
|
||||
*/
|
||||
delta = k_uptime_delta(×tamp);
|
||||
k_delayed_work_submit(&adv.work, K_MSEC(ADV_INT_FAST_MS - delta));
|
||||
}
|
||||
|
||||
void bt_mesh_adv_update(void)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
schedule_send();
|
||||
}
|
||||
|
||||
void bt_mesh_adv_buf_ready(void)
|
||||
{
|
||||
schedule_send();
|
||||
}
|
||||
|
||||
void bt_mesh_adv_init(void)
|
||||
{
|
||||
k_delayed_work_init(&adv.work, send_pending_adv);
|
||||
}
|
||||
|
||||
static void adv_sent(struct bt_le_ext_adv *instance,
|
||||
struct bt_le_ext_adv_sent_info *info)
|
||||
{
|
||||
/* Calling k_uptime_delta on a timestamp moves it to the current time.
|
||||
* This is essential here, as schedule_send() uses the end of the event
|
||||
* as a reference to avoid sending the next advertisement too soon.
|
||||
*/
|
||||
int64_t duration = k_uptime_delta(&adv.timestamp);
|
||||
|
||||
BT_DBG("Advertising stopped after %u ms", (uint32_t)duration);
|
||||
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE);
|
||||
|
||||
if (!atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) {
|
||||
bt_mesh_adv_send_end(0, adv.cb, adv.cb_data);
|
||||
}
|
||||
|
||||
schedule_send();
|
||||
}
|
||||
|
||||
static void connected(struct bt_le_ext_adv *instance,
|
||||
struct bt_le_ext_adv_connected_info *info)
|
||||
{
|
||||
if (atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) {
|
||||
atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE);
|
||||
schedule_send();
|
||||
}
|
||||
}
|
||||
|
||||
int bt_mesh_adv_enable(void)
|
||||
{
|
||||
static const struct bt_le_ext_adv_cb adv_cb = {
|
||||
.sent = adv_sent,
|
||||
.connected = connected,
|
||||
};
|
||||
|
||||
if (adv.instance) {
|
||||
/* Already initialized */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bt_le_ext_adv_create(&adv_param, &adv_cb, &adv.instance);
|
||||
}
|
||||
|
||||
int bt_mesh_adv_start(const struct bt_le_adv_param *param, int32_t duration,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len)
|
||||
{
|
||||
struct bt_le_ext_adv_start_param start = {
|
||||
/* Timeout is set in 10 ms steps, with 0 indicating "forever" */
|
||||
.timeout = (duration == SYS_FOREVER_MS) ? 0 : (duration / 10),
|
||||
};
|
||||
|
||||
BT_DBG("Start advertising %d ms", duration);
|
||||
|
||||
atomic_set_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS);
|
||||
|
||||
return adv_start(param, &start, ad, ad_len, sd, sd_len);
|
||||
}
|
181
subsys/bluetooth/mesh/adv_legacy.c
Normal file
181
subsys/bluetooth/mesh/adv_legacy.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/* Bluetooth Mesh */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <debug/stack.h>
|
||||
#include <sys/util.h>
|
||||
|
||||
#include <net/buf.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/conn.h>
|
||||
#include <bluetooth/mesh.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_ADV)
|
||||
#define LOG_MODULE_NAME bt_mesh_adv_legacy
|
||||
#include "common/log.h"
|
||||
|
||||
#include "host/hci_core.h"
|
||||
|
||||
#include "adv.h"
|
||||
#include "net.h"
|
||||
#include "foundation.h"
|
||||
#include "beacon.h"
|
||||
#include "prov.h"
|
||||
#include "proxy.h"
|
||||
|
||||
/* Pre-5.0 controllers enforce a minimum interval of 100ms
|
||||
* whereas 5.0+ controllers can go down to 20ms.
|
||||
*/
|
||||
#define ADV_INT_DEFAULT_MS 100
|
||||
#define ADV_INT_FAST_MS 20
|
||||
|
||||
static struct k_thread adv_thread_data;
|
||||
static K_KERNEL_STACK_DEFINE(adv_thread_stack, CONFIG_BT_MESH_ADV_STACK_SIZE);
|
||||
static int32_t adv_timeout;
|
||||
|
||||
static inline void adv_send(struct net_buf *buf)
|
||||
{
|
||||
const int32_t adv_int_min =
|
||||
((bt_dev.hci_version >= BT_HCI_VERSION_5_0) ?
|
||||
ADV_INT_FAST_MS :
|
||||
ADV_INT_DEFAULT_MS);
|
||||
const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
|
||||
void *cb_data = BT_MESH_ADV(buf)->cb_data;
|
||||
struct bt_le_adv_param param = {};
|
||||
uint16_t duration, adv_int;
|
||||
struct bt_data ad;
|
||||
int err;
|
||||
|
||||
adv_int = MAX(adv_int_min,
|
||||
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
|
||||
duration = (BT_MESH_SCAN_WINDOW_MS +
|
||||
((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
|
||||
(adv_int + 10)));
|
||||
|
||||
BT_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type,
|
||||
buf->len, bt_hex(buf->data, buf->len));
|
||||
BT_DBG("count %u interval %ums duration %ums",
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int,
|
||||
duration);
|
||||
|
||||
ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type];
|
||||
ad.data_len = buf->len;
|
||||
ad.data = buf->data;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR)) {
|
||||
param.options = BT_LE_ADV_OPT_USE_IDENTITY;
|
||||
} else {
|
||||
param.options = 0U;
|
||||
}
|
||||
|
||||
param.id = BT_ID_DEFAULT;
|
||||
param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_int);
|
||||
param.interval_max = param.interval_min;
|
||||
|
||||
uint64_t time = k_uptime_get();
|
||||
|
||||
err = bt_le_adv_start(¶m, &ad, 1, NULL, 0);
|
||||
net_buf_unref(buf);
|
||||
bt_mesh_adv_send_start(duration, err, cb, cb_data);
|
||||
if (err) {
|
||||
BT_ERR("Advertising failed: err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("Advertising started. Sleeping %u ms", duration);
|
||||
|
||||
k_sleep(K_MSEC(duration));
|
||||
|
||||
err = bt_le_adv_stop();
|
||||
bt_mesh_adv_send_end(err, cb, cb_data);
|
||||
if (err) {
|
||||
BT_ERR("Stopping advertising failed: err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("Advertising stopped (%u ms)", (uint32_t) k_uptime_delta(&time));
|
||||
}
|
||||
|
||||
static void adv_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
BT_DBG("started");
|
||||
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY)) {
|
||||
buf = net_buf_get(&bt_mesh_adv_queue, K_NO_WAIT);
|
||||
while (!buf) {
|
||||
|
||||
/* Adv timeout may be set by a call from proxy
|
||||
* to bt_mesh_adv_start:
|
||||
*/
|
||||
adv_timeout = SYS_FOREVER_MS;
|
||||
bt_mesh_proxy_adv_start();
|
||||
BT_DBG("Proxy Advertising");
|
||||
|
||||
buf = net_buf_get(&bt_mesh_adv_queue,
|
||||
SYS_TIMEOUT_MS(adv_timeout));
|
||||
bt_le_adv_stop();
|
||||
}
|
||||
} else {
|
||||
buf = net_buf_get(&bt_mesh_adv_queue, K_FOREVER);
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* busy == 0 means this was canceled */
|
||||
if (BT_MESH_ADV(buf)->busy) {
|
||||
BT_MESH_ADV(buf)->busy = 0U;
|
||||
adv_send(buf);
|
||||
} else {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
/* Give other threads a chance to run */
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_adv_update(void)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
k_fifo_cancel_wait(&bt_mesh_adv_queue);
|
||||
}
|
||||
|
||||
void bt_mesh_adv_buf_ready(void)
|
||||
{
|
||||
/* Will be handled automatically */
|
||||
}
|
||||
|
||||
void bt_mesh_adv_init(void)
|
||||
{
|
||||
k_thread_create(&adv_thread_data, adv_thread_stack,
|
||||
K_KERNEL_STACK_SIZEOF(adv_thread_stack), adv_thread,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_FOREVER);
|
||||
k_thread_name_set(&adv_thread_data, "BT Mesh adv");
|
||||
}
|
||||
|
||||
int bt_mesh_adv_enable(void)
|
||||
{
|
||||
k_thread_start(&adv_thread_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_mesh_adv_start(const struct bt_le_adv_param *param, int32_t duration,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len)
|
||||
{
|
||||
adv_timeout = duration;
|
||||
return bt_le_adv_start(param, ad, ad_len, sd, sd_len);
|
||||
}
|
|
@ -350,6 +350,14 @@ static void model_start(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|||
|
||||
int bt_mesh_start(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_adv_enable();
|
||||
if (err) {
|
||||
BT_ERR("Failed enabling advertiser");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (bt_mesh_beacon_enabled()) {
|
||||
bt_mesh_beacon_enable();
|
||||
} else {
|
||||
|
|
|
@ -816,8 +816,16 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf)
|
|||
static int prov_link_open(const uint8_t uuid[16], k_timeout_t timeout,
|
||||
const struct prov_bearer_cb *cb, void *cb_data)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("uuid %s", bt_hex(uuid, 16));
|
||||
|
||||
err = bt_mesh_adv_enable();
|
||||
if (err) {
|
||||
BT_ERR("Failed enabling advertiser");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACTIVE)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -839,6 +847,14 @@ static int prov_link_open(const uint8_t uuid[16], k_timeout_t timeout,
|
|||
|
||||
static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_adv_enable();
|
||||
if (err) {
|
||||
BT_ERR("Failed enabling advertiser");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
|
|
@ -54,10 +54,13 @@
|
|||
#define CLIENT_BUF_SIZE 68
|
||||
|
||||
#if defined(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR)
|
||||
#define ADV_OPT (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME | \
|
||||
BT_LE_ADV_OPT_USE_IDENTITY)
|
||||
#define ADV_OPT \
|
||||
(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | \
|
||||
BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_USE_IDENTITY)
|
||||
#else
|
||||
#define ADV_OPT (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME)
|
||||
#define ADV_OPT \
|
||||
(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | \
|
||||
BT_LE_ADV_OPT_ONE_TIME)
|
||||
#endif
|
||||
|
||||
static const struct bt_le_adv_param slow_adv_param = {
|
||||
|
@ -72,8 +75,6 @@ static const struct bt_le_adv_param fast_adv_param = {
|
|||
.interval_max = BT_GAP_ADV_FAST_INT_MAX_2,
|
||||
};
|
||||
|
||||
static bool proxy_adv_enabled;
|
||||
|
||||
#if defined(CONFIG_BT_MESH_GATT_PROXY)
|
||||
static void proxy_send_beacons(struct k_work *work);
|
||||
#endif
|
||||
|
@ -539,9 +540,6 @@ static void proxy_connected(struct bt_conn *conn, uint8_t err)
|
|||
|
||||
conn_count++;
|
||||
|
||||
/* Since we use ADV_OPT_ONE_TIME */
|
||||
proxy_adv_enabled = false;
|
||||
|
||||
/* Try to re-enable advertising in case it's possible */
|
||||
if (conn_count < CONFIG_BT_MAX_CONN) {
|
||||
bt_mesh_adv_update();
|
||||
|
@ -1059,7 +1057,7 @@ static const struct bt_data net_id_ad[] = {
|
|||
BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
|
||||
};
|
||||
|
||||
static int node_id_adv(struct bt_mesh_subnet *sub)
|
||||
static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
{
|
||||
uint8_t tmp[16];
|
||||
int err;
|
||||
|
@ -1085,19 +1083,17 @@ static int node_id_adv(struct bt_mesh_subnet *sub)
|
|||
|
||||
memcpy(proxy_svc_data + 3, tmp + 8, 8);
|
||||
|
||||
err = bt_le_adv_start(&fast_adv_param, node_id_ad,
|
||||
ARRAY_SIZE(node_id_ad), NULL, 0);
|
||||
err = bt_mesh_adv_start(&fast_adv_param, duration, node_id_ad,
|
||||
ARRAY_SIZE(node_id_ad), NULL, 0);
|
||||
if (err) {
|
||||
BT_WARN("Failed to advertise using Node ID (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
proxy_adv_enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_id_adv(struct bt_mesh_subnet *sub)
|
||||
static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -1110,15 +1106,13 @@ static int net_id_adv(struct bt_mesh_subnet *sub)
|
|||
|
||||
memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
|
||||
|
||||
err = bt_le_adv_start(&slow_adv_param, net_id_ad,
|
||||
ARRAY_SIZE(net_id_ad), NULL, 0);
|
||||
err = bt_mesh_adv_start(&slow_adv_param, duration, net_id_ad,
|
||||
ARRAY_SIZE(net_id_ad), NULL, 0);
|
||||
if (err) {
|
||||
BT_WARN("Failed to advertise using Network ID (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
proxy_adv_enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1178,40 +1172,23 @@ static int sub_count(void)
|
|||
return count;
|
||||
}
|
||||
|
||||
static k_timeout_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
||||
static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
int32_t remaining = SYS_FOREVER_MS;
|
||||
int subnet_count;
|
||||
int err = -EBUSY;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (conn_count == CONFIG_BT_MAX_CONN) {
|
||||
BT_DBG("Connectable advertising deferred (max connections)");
|
||||
return K_FOREVER;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub);
|
||||
if (!sub) {
|
||||
BT_WARN("No subnets to advertise on");
|
||||
return K_FOREVER;
|
||||
}
|
||||
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
|
||||
uint32_t active = k_uptime_get_32() - sub->node_id_start;
|
||||
|
||||
if (active < NODE_ID_TIMEOUT) {
|
||||
remaining = NODE_ID_TIMEOUT - active;
|
||||
BT_DBG("Node ID active for %u ms, %d ms remaining",
|
||||
active, remaining);
|
||||
node_id_adv(sub);
|
||||
} else {
|
||||
bt_mesh_proxy_identity_stop(sub);
|
||||
BT_DBG("Node ID stopped");
|
||||
}
|
||||
}
|
||||
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
|
||||
net_id_adv(sub);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
subnet_count = sub_count();
|
||||
|
@ -1232,11 +1209,29 @@ static k_timeout_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
|||
}
|
||||
}
|
||||
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
|
||||
uint32_t active = k_uptime_get_32() - sub->node_id_start;
|
||||
|
||||
if (active < NODE_ID_TIMEOUT) {
|
||||
remaining = NODE_ID_TIMEOUT - active;
|
||||
BT_DBG("Node ID active for %u ms, %d ms remaining",
|
||||
active, remaining);
|
||||
err = node_id_adv(sub, remaining);
|
||||
} else {
|
||||
bt_mesh_proxy_identity_stop(sub);
|
||||
BT_DBG("Node ID stopped");
|
||||
}
|
||||
}
|
||||
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
|
||||
err = net_id_adv(sub, remaining);
|
||||
}
|
||||
|
||||
BT_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx);
|
||||
|
||||
beacon_sub = bt_mesh_subnet_next(beacon_sub);
|
||||
|
||||
return SYS_TIMEOUT_MS(remaining);
|
||||
return err;
|
||||
}
|
||||
#endif /* GATT_PROXY */
|
||||
|
||||
|
@ -1286,38 +1281,38 @@ static size_t gatt_prov_adv_create(struct bt_data prov_sd[2])
|
|||
}
|
||||
#endif /* CONFIG_BT_MESH_PB_GATT */
|
||||
|
||||
k_timeout_t bt_mesh_proxy_adv_start(void)
|
||||
int bt_mesh_proxy_adv_start(void)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
if (gatt_svc == MESH_GATT_NONE) {
|
||||
return K_FOREVER;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PB_GATT)
|
||||
if (!bt_mesh_is_provisioned()) {
|
||||
const struct bt_le_adv_param *param;
|
||||
struct bt_data prov_sd[2];
|
||||
size_t prov_sd_len;
|
||||
|
||||
if (prov_fast_adv) {
|
||||
param = &fast_adv_param;
|
||||
} else {
|
||||
param = &slow_adv_param;
|
||||
}
|
||||
int err;
|
||||
|
||||
prov_sd_len = gatt_prov_adv_create(prov_sd);
|
||||
|
||||
if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad),
|
||||
prov_sd, prov_sd_len) == 0) {
|
||||
proxy_adv_enabled = true;
|
||||
|
||||
/* Advertise 60 seconds using fast interval */
|
||||
if (prov_fast_adv) {
|
||||
prov_fast_adv = false;
|
||||
return K_SECONDS(60);
|
||||
}
|
||||
if (!prov_fast_adv) {
|
||||
return bt_mesh_adv_start(&slow_adv_param,
|
||||
SYS_FOREVER_MS, prov_ad,
|
||||
ARRAY_SIZE(prov_ad), prov_sd,
|
||||
prov_sd_len);
|
||||
}
|
||||
|
||||
/* Advertise 60 seconds using fast interval */
|
||||
err = bt_mesh_adv_start(&fast_adv_param, (60 * MSEC_PER_SEC),
|
||||
prov_ad, ARRAY_SIZE(prov_ad),
|
||||
prov_sd, prov_sd_len);
|
||||
if (!err) {
|
||||
prov_fast_adv = false;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* PB_GATT */
|
||||
|
||||
|
@ -1327,25 +1322,7 @@ k_timeout_t bt_mesh_proxy_adv_start(void)
|
|||
}
|
||||
#endif /* GATT_PROXY */
|
||||
|
||||
return K_FOREVER;
|
||||
}
|
||||
|
||||
void bt_mesh_proxy_adv_stop(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("adv_enabled %u", proxy_adv_enabled);
|
||||
|
||||
if (!proxy_adv_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_adv_stop();
|
||||
if (err) {
|
||||
BT_ERR("Failed to stop advertising (err %d)", err);
|
||||
} else {
|
||||
proxy_adv_enabled = false;
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_GATT_PROXY)
|
||||
|
|
|
@ -31,8 +31,7 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub);
|
|||
|
||||
struct net_buf_simple *bt_mesh_proxy_get_buf(void);
|
||||
|
||||
k_timeout_t bt_mesh_proxy_adv_start(void);
|
||||
void bt_mesh_proxy_adv_stop(void);
|
||||
int bt_mesh_proxy_adv_start(void);
|
||||
|
||||
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub);
|
||||
void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue