diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index e6ae3f6f3ed..12aeb8cc50a 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -421,7 +421,17 @@ config BT_MESH_ADV_EXT_GATT_SEPARATE depends on BT_MESH_GATT_SERVER help Use a separate extended advertising set for GATT Server Advertising, - otherwise will be used a shared advertising set. + otherwise a shared advertising set will be used. + +config BT_MESH_ADV_EXT_FRIEND_SEPARATE + bool "Use a separate extended advertising set for Friend advertising" + depends on BT_MESH_FRIEND + help + Use a separate extended advertising set for Friend advertising, + otherwise a shared advertising set will be used. Using the separate + extended advertising set makes the Friend node send friendship + messages as close to the start of the ReceiveWindow as possible, + thus reducing the scanning time on the Low Power node. endif # BT_MESH_ADV_EXT @@ -880,12 +890,14 @@ config BT_MESH_FRIEND_SEG_RX config BT_MESH_FRIEND_ADV_LATENCY int "Latency for enabling advertising" + range 0 4 default 0 help - Latency in milliseconds that it takes to start friend advertising - after requesting it. Used to tune the receive delay window to make - Friend poll events more efficient by compensating for the time the - non-ideal latency otherwise would add to the delay. + Latency in milliseconds between request for and start of Friend + advertising. Used to tune the ReceiveDelay, making Friend + start sending a message earlier thus compensating for the time between + pushing the message to the Bluetooth host and the actual advertising + start. endif # BT_MESH_FRIEND diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index b517c59617d..f57e3717595 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -43,6 +43,7 @@ const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES] = { static K_FIFO_DEFINE(bt_mesh_adv_queue); static K_FIFO_DEFINE(bt_mesh_relay_queue); +static K_FIFO_DEFINE(bt_mesh_friend_queue); static void adv_buf_destroy(struct net_buf *buf) { @@ -67,6 +68,14 @@ NET_BUF_POOL_DEFINE(relay_buf_pool, CONFIG_BT_MESH_RELAY_BUF_COUNT, static struct bt_mesh_adv adv_relay_pool[CONFIG_BT_MESH_RELAY_BUF_COUNT]; #endif +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) +NET_BUF_POOL_DEFINE(friend_buf_pool, CONFIG_BT_MESH_FRIEND_LPN_COUNT, + BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, + adv_buf_destroy); + +static struct bt_mesh_adv adv_friend_pool[CONFIG_BT_MESH_FRIEND_LPN_COUNT]; +#endif + static struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *buf_pool, struct bt_mesh_adv *adv_pool, enum bt_mesh_adv_type type, @@ -110,11 +119,19 @@ struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, } #endif +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) + if (tag & BT_MESH_FRIEND_ADV) { + return bt_mesh_adv_create_from_pool(&friend_buf_pool, + adv_friend_pool, type, + tag, xmit, timeout); + } +#endif + return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_local_pool, type, tag, xmit, timeout); } -#if CONFIG_BT_MESH_RELAY_ADV_SETS +#if CONFIG_BT_MESH_RELAY_ADV_SETS || CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE static struct net_buf *process_events(struct k_poll_event *ev, int count) { for (; count; ev++, count--) { @@ -159,22 +176,21 @@ struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) return process_events(events, ARRAY_SIZE(events)); } -static struct net_buf *bt_mesh_adv_buf_relay_get(k_timeout_t timeout) -{ - return net_buf_get(&bt_mesh_relay_queue, timeout); -} - struct net_buf *bt_mesh_adv_buf_get_by_tag(uint8_t tag, k_timeout_t timeout) { - if (tag & BT_MESH_LOCAL_ADV) { - return bt_mesh_adv_buf_get(timeout); - } else if (tag & BT_MESH_RELAY_ADV) { - return bt_mesh_adv_buf_relay_get(timeout); - } else { - return NULL; + if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && tag & BT_MESH_FRIEND_ADV) { + return net_buf_get(&bt_mesh_friend_queue, timeout); } + +#if CONFIG_BT_MESH_RELAY_ADV_SETS + if (tag & BT_MESH_RELAY_ADV) { + return net_buf_get(&bt_mesh_relay_queue, timeout); + } +#endif + + return bt_mesh_adv_buf_get(timeout); } -#else /* !CONFIG_BT_MESH_RELAY_ADV_SETS */ +#else /* !(CONFIG_BT_MESH_RELAY_ADV_SETS || CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) */ struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) { return net_buf_get(&bt_mesh_adv_queue, timeout); @@ -186,7 +202,7 @@ struct net_buf *bt_mesh_adv_buf_get_by_tag(uint8_t tag, k_timeout_t timeout) return bt_mesh_adv_buf_get(timeout); } -#endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ +#endif /* CONFIG_BT_MESH_RELAY_ADV_SETS || CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */ void bt_mesh_adv_buf_get_cancel(void) { @@ -198,6 +214,9 @@ void bt_mesh_adv_buf_get_cancel(void) k_fifo_cancel_wait(&bt_mesh_relay_queue); #endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ + if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)) { + k_fifo_cancel_wait(&bt_mesh_friend_queue); + } } void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, @@ -210,18 +229,23 @@ 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; + if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && + BT_MESH_ADV(buf)->tag == BT_MESH_FRIEND_ADV) { + net_buf_put(&bt_mesh_friend_queue, net_buf_ref(buf)); + bt_mesh_adv_buf_friend_ready(); + return; + } + #if CONFIG_BT_MESH_RELAY_ADV_SETS - if (BT_MESH_ADV(buf)->tag == BT_MESH_LOCAL_ADV) { - net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf)); - bt_mesh_adv_buf_local_ready(); - } else { + if (BT_MESH_ADV(buf)->tag == BT_MESH_RELAY_ADV) { net_buf_put(&bt_mesh_relay_queue, net_buf_ref(buf)); bt_mesh_adv_buf_relay_ready(); + return; } -#else /* !CONFIG_BT_MESH_RELAY_ADV_SETS */ +#endif + net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf)); bt_mesh_adv_buf_local_ready(); -#endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ } int bt_mesh_adv_gatt_send(void) diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 220a59ba93d..f67a172afb0 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -29,6 +29,7 @@ enum bt_mesh_adv_tag { BT_MESH_LOCAL_ADV = BIT(0), BT_MESH_RELAY_ADV = BIT(1), BT_MESH_PROXY_ADV = BIT(2), + BT_MESH_FRIEND_ADV = BIT(3), }; struct bt_mesh_adv { @@ -38,7 +39,7 @@ struct bt_mesh_adv { uint8_t type:2, started:1, busy:1, - tag:3; + tag:4; uint8_t xmit; }; @@ -74,6 +75,8 @@ void bt_mesh_adv_buf_local_ready(void); void bt_mesh_adv_buf_relay_ready(void); +void bt_mesh_adv_buf_friend_ready(void); + int bt_mesh_adv_gatt_send(void); int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration, diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index c175bc03dde..f0ef1585a6e 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -68,6 +68,9 @@ static bool schedule_send(struct bt_mesh_ext_adv *adv); static STRUCT_SECTION_ITERABLE(bt_mesh_ext_adv, adv_main) = { .tag = ( +#if !defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) + BT_MESH_FRIEND_ADV | +#endif #if !defined(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE) BT_MESH_PROXY_ADV | #endif /* !CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */ @@ -88,16 +91,28 @@ static STRUCT_SECTION_ITERABLE(bt_mesh_ext_adv, adv_relay[CONFIG_BT_MESH_RELAY_A }; #endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) +#define ADV_EXT_FRIEND 1 +static STRUCT_SECTION_ITERABLE(bt_mesh_ext_adv, adv_friend) = { + .tag = BT_MESH_FRIEND_ADV, + .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), +}; +#else /* CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */ +#define ADV_EXT_FRIEND 0 +#endif /* CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */ + #if defined(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE) -#define BT_MESH_ADV_COUNT (1 + CONFIG_BT_MESH_RELAY_ADV_SETS + 1) +#define ADV_EXT_GATT 1 static STRUCT_SECTION_ITERABLE(bt_mesh_ext_adv, adv_gatt) = { .tag = BT_MESH_PROXY_ADV, .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), }; #else /* CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */ -#define BT_MESH_ADV_COUNT (1 + CONFIG_BT_MESH_RELAY_ADV_SETS) +#define ADV_EXT_GATT 0 #endif /* CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */ +#define BT_MESH_ADV_COUNT (1 + CONFIG_BT_MESH_RELAY_ADV_SETS + ADV_EXT_FRIEND + ADV_EXT_GATT) + BUILD_ASSERT(CONFIG_BT_EXT_ADV_MAX_ADV_SET >= BT_MESH_ADV_COUNT, "Insufficient adv instances"); @@ -208,6 +223,21 @@ static int buf_send(struct bt_mesh_ext_adv *adv, struct net_buf *buf) return err; } +static const char *adv_tag_to_str(enum bt_mesh_adv_tag tag) +{ + if (tag & BT_MESH_LOCAL_ADV) { + return "local adv"; + } else if (tag & BT_MESH_PROXY_ADV) { + return "proxy adv"; + } else if (tag & BT_MESH_RELAY_ADV) { + return "relay adv"; + } else if (tag & BT_MESH_FRIEND_ADV) { + return "friend adv"; + } else { + return "(unknown tag)"; + } +} + static void send_pending_adv(struct k_work *work) { struct bt_mesh_ext_adv *adv; @@ -223,7 +253,8 @@ static void send_pending_adv(struct k_work *work) */ int64_t duration = k_uptime_delta(&adv->timestamp); - LOG_DBG("Advertising stopped after %u ms", (uint32_t)duration); + LOG_DBG("Advertising stopped after %u ms for (%u) %s", (uint32_t)duration, adv->tag, + adv_tag_to_str(adv->tag)); atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); atomic_clear_bit(adv->flags, ADV_FLAG_PROXY); @@ -297,12 +328,16 @@ static bool schedule_send(struct bt_mesh_ext_adv *adv) atomic_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING); - /* 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_work_reschedule(&adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); + if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && adv->tag & BT_MESH_FRIEND_ADV) { + k_work_reschedule(&adv->work, K_NO_WAIT); + } else { + /* 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_work_reschedule(&adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); + } return true; } @@ -333,6 +368,13 @@ void bt_mesh_adv_buf_relay_ready(void) } } +void bt_mesh_adv_buf_friend_ready(void) +{ +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) + (void)schedule_send(&adv_friend); +#endif +} + void bt_mesh_adv_init(void) { struct bt_le_adv_param adv_param = { diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 2d532ccb759..18bfe6c110e 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -1269,7 +1269,7 @@ static void friend_timeout(struct k_work *work) frnd->queue_size--; send_last: - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_LOCAL_ADV, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_FRIEND_ADV, FRIEND_XMIT, K_NO_WAIT); if (!buf) { LOG_ERR("Unable to allocate friend adv buffer");