diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 19fe6fb80ae..716d14cd30d 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -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) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 61a35edd43b..21232b0f900 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -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 diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index 1f1ed981c48..550e3628ae9 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -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 = { diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 94af6ad7079..b205ffd4565 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -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); + } +} diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c new file mode 100644 index 00000000000..c3dd892e782 --- /dev/null +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -0,0 +1,282 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include + +#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); +} diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c new file mode 100644 index 00000000000..9285e2d85ef --- /dev/null +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -0,0 +1,181 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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); +} diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 8b84648be63..d866cc04d85 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -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 { diff --git a/subsys/bluetooth/mesh/pb_adv.c b/subsys/bluetooth/mesh/pb_adv.c index 8034ad38a60..afca1b384f6 100644 --- a/subsys/bluetooth/mesh/pb_adv.c +++ b/subsys/bluetooth/mesh/pb_adv.c @@ -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; } diff --git a/subsys/bluetooth/mesh/proxy.c b/subsys/bluetooth/mesh/proxy.c index 925d9c37013..c4f9ade3792 100644 --- a/subsys/bluetooth/mesh/proxy.c +++ b/subsys/bluetooth/mesh/proxy.c @@ -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) diff --git a/subsys/bluetooth/mesh/proxy.h b/subsys/bluetooth/mesh/proxy.h index d0f20f29ede..56098c30e52 100644 --- a/subsys/bluetooth/mesh/proxy.h +++ b/subsys/bluetooth/mesh/proxy.h @@ -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);