Bluetooth: Mesh: Added support for randomly delaying publications
The section 3.7.3.1 of the mesh specification recommends to delay a message publication in certain cases: - at power-up or upon state change for a time between 20 to 500 ms - for periodic publications for a time between 20 to 50 ms This change implements this recommendation by adding the `CONFIG_BT_MESH_DELAYABLE_PUBLICATION` Kconfig option which enables the randomization code and by adding the `bt_mesh_model_pub.delayable` bit field which allows each model decide whether the publications should be delayed for this model or not. Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
parent
640a493c1d
commit
fe70e50d41
7 changed files with 311 additions and 16 deletions
|
@ -672,6 +672,15 @@ config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT
|
|||
|
||||
endif # BT_MESH_ACCESS_DELAYABLE_MSG
|
||||
|
||||
config BT_MESH_DELAYABLE_PUBLICATION
|
||||
bool "Delayable publication"
|
||||
default y
|
||||
help
|
||||
When enabled, the periodic publications are randomly delayed by 20 to 50ms. Publications
|
||||
triggered at the start of the stack or by the bt_mesh_model_publish() call are delayed by
|
||||
20 to 500ms. This option reduces the probability of collisions when multiple nodes publish
|
||||
at the same time.
|
||||
|
||||
endmenu # Access layer
|
||||
|
||||
menu "Models"
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_access);
|
||||
|
||||
/* 20 - 50ms */
|
||||
#define RANDOM_DELAY_SHORT 30
|
||||
/* 20 - 500ms */
|
||||
#define RANDOM_DELAY_LONG 480
|
||||
|
||||
/* Model publication information for persistent storage. */
|
||||
struct mod_pub_val {
|
||||
struct {
|
||||
|
@ -761,8 +766,16 @@ static int32_t next_period(const struct bt_mesh_model *mod)
|
|||
|
||||
if (period && elapsed >= period) {
|
||||
LOG_WRN("Retransmission interval is too short");
|
||||
/* Return smallest positive number since 0 means disabled */
|
||||
return 1;
|
||||
|
||||
if (!!pub->delayable) {
|
||||
LOG_WRN("Publication period is too short for"
|
||||
" retransmissions");
|
||||
}
|
||||
|
||||
/* Keep retransmitting the message with the interval sacrificing the
|
||||
* next publication period start.
|
||||
*/
|
||||
return BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -775,6 +788,11 @@ static int32_t next_period(const struct bt_mesh_model *mod)
|
|||
|
||||
if (elapsed >= period) {
|
||||
LOG_WRN("Publication sending took longer than the period");
|
||||
|
||||
if (!!pub->delayable) {
|
||||
LOG_WRN("Publication period is too short to be delayable");
|
||||
}
|
||||
|
||||
/* Return smallest positive number since 0 means disabled */
|
||||
return 1;
|
||||
}
|
||||
|
@ -855,6 +873,39 @@ static int pub_period_start(struct bt_mesh_model_pub *pub)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t pub_delay_get(int random_delay_window)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_DELAYABLE_PUBLICATION)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t num = 0;
|
||||
|
||||
(void)bt_rand(&num, sizeof(num));
|
||||
|
||||
return 20 + (num % random_delay_window);
|
||||
}
|
||||
|
||||
static int pub_delay_schedule(struct bt_mesh_model_pub *pub, int delay)
|
||||
{
|
||||
uint16_t random;
|
||||
int err;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_DELAYABLE_PUBLICATION)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
random = pub_delay_get(delay);
|
||||
err = k_work_reschedule(&pub->timer, K_MSEC(random));
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to delay publication (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Publication delayed by %dms", random);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mod_publish(struct k_work *work)
|
||||
{
|
||||
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
||||
|
@ -890,6 +941,13 @@ static void mod_publish(struct k_work *work)
|
|||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Delay the first publication in a period. */
|
||||
if (!!pub->delayable && !pub_delay_schedule(pub, RANDOM_DELAY_SHORT)) {
|
||||
/* Increment count as it would do BT_MESH_PUB_MSG_TOTAL */
|
||||
pub->count++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
err = publish_transmit(pub->mod);
|
||||
|
@ -1564,6 +1622,18 @@ int bt_mesh_model_publish(const struct bt_mesh_model *model)
|
|||
LOG_DBG("Publish Retransmit Count %u Interval %ums", pub->count,
|
||||
BT_MESH_PUB_TRANSMIT_INT(pub->retransmit));
|
||||
|
||||
/* Delay the publication for longer time when the publication is triggered manually (section
|
||||
* 3.7.3.1):
|
||||
*
|
||||
* When the publication of a message is the result of a power-up, a state transition
|
||||
* progress update, or completion of a state transition, multiple nodes may be reporting the
|
||||
* state change at the same time. To reduce the probability of a message collision, these
|
||||
* messages should be sent with a random delay between 20 and 500 milliseconds.
|
||||
*/
|
||||
if (!!pub->delayable && !pub_delay_schedule(pub, RANDOM_DELAY_LONG)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_work_reschedule(&pub->timer, K_NO_WAIT);
|
||||
|
||||
return 0;
|
||||
|
@ -2568,8 +2638,21 @@ static void commit_mod(const struct bt_mesh_model *mod, const struct bt_mesh_ele
|
|||
int32_t ms = bt_mesh_model_pub_period_get(mod);
|
||||
|
||||
if (ms > 0) {
|
||||
LOG_DBG("Starting publish timer (period %u ms)", ms);
|
||||
k_work_schedule(&mod->pub->timer, K_MSEC(ms));
|
||||
/* Delay the first publication after power-up for longer time (section
|
||||
* 3.7.3.1):
|
||||
*
|
||||
* When the publication of a message is the result of a power-up, a state
|
||||
* transition progress update, or completion of a state transition, multiple
|
||||
* nodes may be reporting the state change at the same time. To reduce the
|
||||
* probability of a message collision, these messages should be sent with a
|
||||
* random delay between 20 and 500 milliseconds.
|
||||
*/
|
||||
uint16_t random;
|
||||
|
||||
random = !!mod->pub->delayable ? pub_delay_get(RANDOM_DELAY_LONG) : 0;
|
||||
|
||||
LOG_DBG("Starting publish timer (period %u ms, delay %u ms)", ms, random);
|
||||
k_work_schedule(&mod->pub->timer, K_MSEC(ms + random));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue