Bluetooth: Mesh: Add artificial beacon delay
After removing 20ms in advertiser, all subnetwork beacons are sent as high dense packet of frames with minimal distance between them. That might cause collisions if beacon interval on devices will coincide. This commit adds an artificial delay between each subnet advertsing beacons. Signed-off-by: Anders Storrø <anders.storro@nordicsemi.no>
This commit is contained in:
parent
68799d507d
commit
93a6ee501a
2 changed files with 76 additions and 24 deletions
|
@ -40,6 +40,8 @@ LOG_MODULE_REGISTER(bt_mesh_beacon);
|
|||
#define PROV_XMIT BT_MESH_TRANSMIT(0, 20)
|
||||
|
||||
static struct k_work_delayable beacon_timer;
|
||||
static struct bt_mesh_subnet *beacon_send_sub_curr;
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
static struct {
|
||||
/**
|
||||
|
@ -111,13 +113,26 @@ void bt_mesh_beacon_cache_clear(struct bt_mesh_subnet *sub)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void beacon_start(uint16_t duration, int err, void *user_data)
|
||||
{
|
||||
if (err) {
|
||||
LOG_ERR("Failed to send beacon: err %d", err);
|
||||
if (beacon_send_sub_curr) {
|
||||
k_work_reschedule(&beacon_timer, K_NO_WAIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void beacon_complete(int err, void *user_data)
|
||||
{
|
||||
struct bt_mesh_beacon *beacon = user_data;
|
||||
|
||||
LOG_DBG("err %d", err);
|
||||
|
||||
beacon->sent = k_uptime_get_32();
|
||||
|
||||
if (beacon_send_sub_curr) {
|
||||
k_work_reschedule(&beacon_timer, K_MSEC(20));
|
||||
}
|
||||
}
|
||||
|
||||
static int secure_beacon_create(struct bt_mesh_subnet *sub,
|
||||
|
@ -247,11 +262,12 @@ static bool secure_beacon_is_running(void)
|
|||
atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR);
|
||||
}
|
||||
|
||||
static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *beacon,
|
||||
void *cb_data, int (*beacon_create)(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf))
|
||||
static int net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *beacon,
|
||||
int (*beacon_create)(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf))
|
||||
{
|
||||
static const struct bt_mesh_send_cb send_cb = {
|
||||
.start = beacon_start,
|
||||
.end = beacon_complete,
|
||||
};
|
||||
uint32_t now = k_uptime_get_32();
|
||||
|
@ -267,14 +283,14 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b
|
|||
if (time_diff < (600 * MSEC_PER_SEC) &&
|
||||
(time_diff < BEACON_THRESHOLD(beacon) ||
|
||||
time_since_last_recv < (10 * MSEC_PER_SEC))) {
|
||||
return false;
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
adv = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL,
|
||||
PROV_XMIT, K_NO_WAIT);
|
||||
if (!adv) {
|
||||
LOG_ERR("Unable to allocate beacon adv");
|
||||
return true; /* Bail out */
|
||||
return -ENOMEM; /* Bail out */
|
||||
}
|
||||
|
||||
err = beacon_create(sub, &adv->b);
|
||||
|
@ -284,12 +300,12 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b
|
|||
|
||||
bt_mesh_adv_unref(adv);
|
||||
|
||||
return err != 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool net_beacon_for_subnet_send(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
static int net_beacon_for_subnet_send(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
bool res = true;
|
||||
int err = -ENOMSG;
|
||||
|
||||
struct {
|
||||
struct bt_mesh_beacon *beacon;
|
||||
|
@ -315,14 +331,14 @@ static bool net_beacon_for_subnet_send(struct bt_mesh_subnet *sub, void *cb_data
|
|||
continue;
|
||||
}
|
||||
|
||||
res = net_beacon_send(sub, beacons[i].beacon, cb_data, beacons[i].create_fn);
|
||||
if (res) {
|
||||
err = net_beacon_send(sub, beacons[i].beacon, beacons[i].create_fn);
|
||||
if (err < 0) {
|
||||
/* Bail out */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int unprovisioned_beacon_send(void)
|
||||
|
@ -449,6 +465,30 @@ static bool net_beacon_is_running(void)
|
|||
(bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED);
|
||||
}
|
||||
|
||||
static bool beacons_send_next(void)
|
||||
{
|
||||
int err;
|
||||
struct bt_mesh_subnet *sub_first = bt_mesh_subnet_next(NULL);
|
||||
struct bt_mesh_subnet *sub_next;
|
||||
|
||||
do {
|
||||
sub_next = bt_mesh_subnet_next(beacon_send_sub_curr);
|
||||
if (sub_next == sub_first && beacon_send_sub_curr != NULL) {
|
||||
beacon_send_sub_curr = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
beacon_send_sub_curr = sub_next;
|
||||
err = net_beacon_for_subnet_send(beacon_send_sub_curr);
|
||||
if (err < 0 && (err != -ENOMSG)) {
|
||||
LOG_ERR("Failed to advertise subnet %d: err %d",
|
||||
beacon_send_sub_curr->net_idx, err);
|
||||
}
|
||||
} while (err);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void beacon_send(struct k_work *work)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
@ -458,10 +498,14 @@ static void beacon_send(struct k_work *work)
|
|||
return;
|
||||
}
|
||||
|
||||
update_beacon_observation();
|
||||
(void)bt_mesh_subnet_find(net_beacon_for_subnet_send, NULL);
|
||||
if (!beacon_send_sub_curr) {
|
||||
update_beacon_observation();
|
||||
}
|
||||
|
||||
if (!beacons_send_next()) {
|
||||
k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL);
|
||||
}
|
||||
|
||||
k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -473,7 +517,6 @@ static void beacon_send(struct k_work *work)
|
|||
|
||||
k_work_schedule(&beacon_timer, K_SECONDS(CONFIG_BT_MESH_UNPROV_BEACON_INT));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool auth_match(struct bt_mesh_subnet_keys *keys,
|
||||
|
@ -757,6 +800,7 @@ void bt_mesh_beacon_ivu_initiator(bool enable)
|
|||
* still have to implement an early exit mechanism, so we might as well
|
||||
* just use this every time.
|
||||
*/
|
||||
beacon_send_sub_curr = NULL;
|
||||
k_work_schedule(&beacon_timer, K_NO_WAIT);
|
||||
}
|
||||
|
||||
|
@ -779,11 +823,13 @@ void bt_mesh_beacon_enable(void)
|
|||
bt_mesh_subnet_foreach(subnet_beacon_enable);
|
||||
}
|
||||
|
||||
beacon_send_sub_curr = NULL;
|
||||
k_work_reschedule(&beacon_timer, K_NO_WAIT);
|
||||
}
|
||||
|
||||
void bt_mesh_beacon_disable(void)
|
||||
{
|
||||
/* If this fails, we'll do an early exit in the work handler. */
|
||||
beacon_send_sub_curr = NULL;
|
||||
(void)k_work_cancel_delayable(&beacon_timer);
|
||||
}
|
||||
|
|
|
@ -483,8 +483,11 @@ static void corrupted_beacon_test(const uint8_t *offsets,
|
|||
}
|
||||
|
||||
/* Now the beacon payload is valid and it shall trigger IV Update on the node. It shall also
|
||||
* increase the beacon interval.
|
||||
* increase the beacon interval. We delay the outgoing beacon for a couple of seconds to
|
||||
* avoid near perfect syncing with the beacon interval cycle of the device we just received
|
||||
* a beacon from.
|
||||
*/
|
||||
k_sleep(K_SECONDS(3));
|
||||
send_beacon(buf);
|
||||
|
||||
/* The beacon interval shall be changed and the node shall skip transmission of the next
|
||||
|
@ -1361,7 +1364,7 @@ static void test_tx_priv_interleave(void)
|
|||
struct bt_mesh_subnet *sub;
|
||||
|
||||
|
||||
bt_mesh_test_cfg_set(NULL, BEACON_INTERVAL_WAIT_TIME);
|
||||
bt_mesh_test_cfg_set(NULL, WAIT_TIME);
|
||||
bt_mesh_device_setup(&prov, &prb_comp);
|
||||
provision(&tx_cfg);
|
||||
|
||||
|
@ -1394,6 +1397,8 @@ static void test_tx_priv_interleave(void)
|
|||
k_sleep(K_SECONDS(BEACON_INTERVAL + 5));
|
||||
|
||||
toggle_priv_beacon(tx_cfg.addr, 0);
|
||||
/* Small delay to let beacons complete before subnet update is applied */
|
||||
k_sleep(K_MSEC(20));
|
||||
|
||||
status = bt_mesh_subnet_update(BT_MESH_KEY_PRIMARY, net_key_new);
|
||||
ASSERT_TRUE(status == STATUS_SUCCESS);
|
||||
|
@ -1419,7 +1424,7 @@ static void test_rx_priv_interleave(void)
|
|||
int err;
|
||||
bool same_random = false;
|
||||
|
||||
bt_mesh_test_cfg_set(&rx_cfg, BEACON_INTERVAL_WAIT_TIME);
|
||||
bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME);
|
||||
bt_mesh_crypto_init();
|
||||
k_sem_init(&observer_sem, 0, 1);
|
||||
|
||||
|
@ -1894,9 +1899,10 @@ static void proxy_adv_confirm_evt(struct expected_proxy_adv_evt *exp_evts, uint8
|
|||
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (exp_evts[i].evt_cnt) {
|
||||
LOG_ERR("Missing %d expected %s events in period %llums-%llums",
|
||||
LOG_ERR("Missing %d expected %s idx %d events in period %llums-%llums",
|
||||
exp_evts[i].evt_cnt, proxy_adv_str[exp_evts[i].evt_type],
|
||||
exp_evts[i].time.after, exp_evts[i].time.before);
|
||||
exp_evts[i].net_idx, exp_evts[i].time.after,
|
||||
exp_evts[i].time.before);
|
||||
missing_evts = true;
|
||||
}
|
||||
}
|
||||
|
@ -2029,13 +2035,13 @@ static void test_rx_proxy_adv_multi_subnet_coex(void)
|
|||
* is advertised by this subnet, and that the two others
|
||||
* continues to advertise NET_ID.
|
||||
*/
|
||||
{.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 17,
|
||||
{.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 16,
|
||||
.time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2,
|
||||
.before = PROXY_ADV_MULTI_CHECKPOINT_3}},
|
||||
{.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 17,
|
||||
{.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 16,
|
||||
.time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2,
|
||||
.before = PROXY_ADV_MULTI_CHECKPOINT_3}},
|
||||
{.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 17,
|
||||
{.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 16,
|
||||
.time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2,
|
||||
.before = PROXY_ADV_MULTI_CHECKPOINT_3}},
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue