Bluetooth: Mesh: advertiser: add disable function

Adds a disable function for the extended advertising which stops and
deletes the advertising instances, allowing them to be properly
reinitialized when calling `bt_mesh_adv_enable()` after bluetooth has
been disabled and re-enabled.

For the legacy advertising, the function terminates the advertising
thread. If legacy advertising is used, `bt_mesh_adv_init()` must be
called before `bt_mesh_adv_enable()` to properly resume advertising
after suspension.

Signed-off-by: Håvard Reierstad <haavard.reierstad@nordicsemi.no>
This commit is contained in:
Håvard Reierstad 2023-11-23 12:09:17 +01:00 committed by Henrik Brix Andersen
commit 3be26c4cb9
4 changed files with 55 additions and 3 deletions

View file

@ -607,6 +607,10 @@ void bt_mesh_reset(void);
* If at all possible, the Friendship feature should be used instead, to
* make the node into a Low Power Node.
*
* @note Should not be called from work queue due to undefined behavior.
* This is due to k_work_flush_delayable() being used in disabling of the
* extended advertising.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_suspend(void);

View file

@ -80,6 +80,9 @@ int bt_mesh_scan_disable(void);
int bt_mesh_adv_enable(void);
/* Should not be called from work queue due to undefined behavior */
int bt_mesh_adv_disable(void);
void bt_mesh_adv_buf_local_ready(void);
void bt_mesh_adv_buf_relay_ready(void);

View file

@ -506,6 +506,36 @@ int bt_mesh_adv_enable(void)
return 0;
}
int bt_mesh_adv_disable(void)
{
int err;
struct k_work_sync sync;
for (int i = 0; i < ARRAY_SIZE(advs); i++) {
k_work_flush_delayable(&advs[i].work, &sync);
err = bt_le_ext_adv_stop(advs[i].instance);
if (err) {
LOG_ERR("Failed to stop adv %d", err);
return err;
}
/* `adv_sent` is called to finish transmission of an adv buffer that was pushed to
* the host before the advertiser was stopped, but did not finish.
*/
adv_sent(advs[i].instance, NULL);
err = bt_le_ext_adv_delete(advs[i].instance);
if (err) {
LOG_ERR("Failed to delete adv %d", err);
return err;
}
advs[i].instance = NULL;
}
return 0;
}
int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param,
int32_t duration,
const struct bt_data *ad, size_t ad_len,

View file

@ -39,6 +39,7 @@ LOG_MODULE_REGISTER(bt_mesh_adv_legacy);
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 bool enabled;
static int bt_data_send(uint8_t num_events, uint16_t adv_int,
const struct bt_data *ad, size_t ad_len,
@ -144,10 +145,9 @@ static inline void buf_send(struct net_buf *buf)
static void adv_thread(void *p1, void *p2, void *p3)
{
LOG_DBG("started");
struct net_buf *buf;
while (1) {
struct net_buf *buf;
while (enabled) {
if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) {
buf = bt_mesh_adv_buf_get(K_NO_WAIT);
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) {
@ -188,6 +188,12 @@ static void adv_thread(void *p1, void *p2, void *p3)
/* Give other threads a chance to run */
k_yield();
}
/* Empty the advertising pool when advertising is disabled */
while ((buf = bt_mesh_adv_buf_get(K_NO_WAIT))) {
bt_mesh_adv_send_start(0, -ENODEV, BT_MESH_ADV(buf));
net_buf_unref(buf);
}
}
void bt_mesh_adv_buf_local_ready(void)
@ -221,10 +227,19 @@ void bt_mesh_adv_init(void)
int bt_mesh_adv_enable(void)
{
enabled = true;
k_thread_start(&adv_thread_data);
return 0;
}
int bt_mesh_adv_disable(void)
{
enabled = false;
k_thread_join(&adv_thread_data, K_FOREVER);
LOG_DBG("Advertising disabled");
return 0;
}
int bt_mesh_adv_gatt_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)