Bluetooth: Mesh: Fix accuracy of Publish Period

After the Publish Retransmit state was introduced the Publish Period
measurement would begin once the previous Publish message has finished
transmitting. This will however cause inaccurate periods, which is
particularly an issue with the PTS that expects accuracy of less than
0.5 seconds (apparently).

Since the publication timer is also used for the retransmissions we
can't simultaneously use if for the period as well. Therefore, we
introduce a new variable called period_start which makes a note of
when the period was supposed to start, and then once all
retransmissoins are done initializes the timer with the send duration
taken into account.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-11-20 20:17:31 +02:00 committed by Johan Hedberg
commit 15fe221f13
2 changed files with 32 additions and 4 deletions

View file

@ -271,6 +271,8 @@ struct bt_mesh_model_pub {
cred:1, /**< Friendship Credentials Flag. */
count:3; /**< Retransmissions left. */
u32_t period_start; /**< Start of the current period. */
/** @brief Buffer containing the publication message.
*
* The application is expected to initialize this with

View file

@ -97,6 +97,33 @@ s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
return period >> mod->pub->period_div;
}
static s32_t next_period(struct bt_mesh_model *mod)
{
u32_t elapsed, period, now = k_uptime_get_32();
struct bt_mesh_model_pub *pub = mod->pub;
period = bt_mesh_model_pub_period_get(mod);
if (!period) {
return 0;
}
if (now < pub->period_start) {
elapsed = now + (UINT32_MAX - pub->period_start);
} else {
elapsed = now - pub->period_start;
}
BT_DBG("Publishing took %ums", elapsed);
if (elapsed > period) {
BT_WARN("Publication sending took longer than the period");
/* Return smallest positive number since 0 means disabled */
return K_MSEC(1);
}
return period - elapsed;
}
static void publish_sent(int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
@ -107,7 +134,7 @@ static void publish_sent(int err, void *user_data)
if (mod->pub->count) {
delay = BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit);
} else {
delay = bt_mesh_model_pub_period_get(mod);
delay = next_period(mod);
}
if (delay) {
@ -187,11 +214,10 @@ static void mod_publish(struct k_work *work)
return;
}
/* Submit in advance so the timer is more accurate */
k_delayed_work_submit(&pub->timer, period_ms);
__ASSERT_NO_MSG(pub->update != NULL);
pub->period_start = k_uptime_get_32();
err = pub->update(pub->mod);
if (err) {
BT_ERR("Failed to update publication message");