Bluetooth: Mesh: Separate adv tag/set for friend

The purpose of this commit is to facilitate future improvements to the
LPN and friendship feature. By being able to identify friendship related
messages on the advertising layer, it will be possible to treat these in
a specific manner so that message exchange between LPN and friend
devices can be conducted in a more power efficient manner.

This commit adds the following:
   - A separate tag for friendship related messages
   - A optional separate advertising set for friend related messages

Signed-off-by: Anders Storrø <anders.storro@nordicsemi.no>
This commit is contained in:
Anders Storrø 2023-01-11 10:35:46 +01:00 committed by Carles Cufí
commit c819f0f8d6
5 changed files with 117 additions and 36 deletions

View file

@ -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

View file

@ -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)

View file

@ -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,

View file

@ -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);
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(&timestamp);
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 = {

View file

@ -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");