Skip to content

Commit

Permalink
Bluetooth: Mesh: restore ttl in Time model after unsolicited statuses
Browse files Browse the repository at this point in the history
Commit fixes the known issue when the Time model changes
the configured publishing ttl after sending any
unsolicited Time status.

Signed-off-by: Aleksandr Khromykh <[email protected]>
  • Loading branch information
alxelax authored and rlubos committed Feb 20, 2024
1 parent 7a74dca commit 0e3d208
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Bluetooth Mesh
* :ref:`bt_mesh_ug_reserved_ids` with model ID and opcodes for the new :ref:`bt_mesh_le_pair_resp_readme` model.
* :ref:`bt_mesh_light_ctrl_readme` APIs to match new Sensor APIs.
* :ref:`ug_bt_mesh_configuring` with the recommendation on how to configure persistent storage to increase performance.
* Fixed an issue when the Time Server model rewrites TTL to zero forever during the unsolicited Time Status publication.

Matter
------
Expand Down
5 changes: 5 additions & 0 deletions include/bluetooth/mesh/time_srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ struct bt_mesh_time_srv {
struct bt_mesh_time_srv_data data;
/** Delayable work to randomize status relaying. */
struct k_work_delayable status_delay;
/** Property whether the Time status was unsolicited. */
bool is_unsolicited;
/** Cached publishing TTL while server is sending the unsolicited Time Status with zero TTL.
*/
uint8_t cached_ttl;

/** @brief Update callback.
*
Expand Down
24 changes: 23 additions & 1 deletion subsys/bluetooth/mesh/time_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ static int bt_mesh_time_srv_init(const struct bt_mesh_model *model)
srv->model = model;
srv->data.timestamp = -STATUS_INTERVAL_MIN;
net_buf_simple_init(srv->pub.msg, 0);
srv->is_unsolicited = false;
srv->cached_ttl = 0;

k_work_init_delayable(&srv->status_delay, time_status_send_after_delay);

Expand All @@ -429,6 +431,8 @@ static void bt_mesh_time_srv_reset(const struct bt_mesh_model *model)

srv->data = data;
net_buf_simple_reset(srv->pub.msg);
srv->is_unsolicited = false;
srv->cached_ttl = 0;
(void)k_work_cancel_delayable(&srv->status_delay);

if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
Expand Down Expand Up @@ -489,6 +493,7 @@ const struct bt_mesh_model_cb _bt_mesh_time_setup_srv_cb = {
int _bt_mesh_time_srv_update_handler(const struct bt_mesh_model *model)
{
struct bt_mesh_time_srv *srv = model->rt->user_data;
struct bt_mesh_model_pub *pub = srv->model->pub;
struct bt_mesh_time_status status;
int64_t uptime;
int err;
Expand All @@ -504,6 +509,15 @@ int _bt_mesh_time_srv_update_handler(const struct bt_mesh_model *model)
return err;
}

/* If sent as an unsolicited message, the Time Status message shall be sent
* with TTL=0 to avoid building up cumulative time errors resulting from delays
* in processing the messages by relays.
*/
if (!bt_mesh_model_pub_is_retransmission(pub->mod) && srv->is_unsolicited) {
pub->ttl = srv->cached_ttl;
srv->is_unsolicited = false;
}

srv->data.timestamp = uptime;
/* Account for delay in TX processing: */
status.uncertainty += CONFIG_BT_MESH_TIME_MESH_HOP_UNCERTAINTY;
Expand All @@ -517,6 +531,7 @@ int _bt_mesh_time_srv_update_handler(const struct bt_mesh_model *model)
int bt_mesh_time_srv_time_status_send(struct bt_mesh_time_srv *srv,
struct bt_mesh_msg_ctx *ctx)
{
struct bt_mesh_model_pub *pub = srv->model->pub;
int64_t uptime = k_uptime_get();
int err;

Expand All @@ -528,7 +543,14 @@ int bt_mesh_time_srv_time_status_send(struct bt_mesh_time_srv *srv,
return -EOPNOTSUPP;
}

srv->model->pub->ttl = 0;
if (ctx) {
ctx->send_ttl = 0;
ctx->rnd_delay = false;
} else {
srv->cached_ttl = srv->is_unsolicited ? srv->cached_ttl : pub->ttl;
srv->is_unsolicited = true;
pub->ttl = 0;
}

err = send_time_status(srv->model, ctx, uptime);
if (!err) {
Expand Down
43 changes: 42 additions & 1 deletion tests/subsys/bluetooth/mesh/time_model/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ static struct bt_mesh_time_status expected_status;
static uint32_t time_status_rx_number;
static bool is_randomized;
static bool is_unsolicited;
static bool is_skipped;

static void tc_setup(void *f)
{
Expand All @@ -50,7 +51,12 @@ static void tc_setup(void *f)
.tm_hour = 0, .tm_min = 0, .tm_sec = 0,
};

is_randomized = false;
is_unsolicited = false;
is_skipped = false;
time_status_rx_number = 0;
mock_elem[0].models->pub->mod = mock_elem[0].models;
mock_elem[0].models->pub->ttl = 10;
zassert_not_null(_bt_mesh_time_srv_cb.init, "Init cb is null");
_bt_mesh_time_srv_cb.init(mock_elem[0].models);

Expand Down Expand Up @@ -91,6 +97,10 @@ int bt_mesh_msg_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *

zassert_equal_ptr(time_srv.model, model);

if (is_skipped) {
return 0;
}

if (is_randomized) {
zassert_is_null(ctx);
} else {
Expand Down Expand Up @@ -185,7 +195,6 @@ ZTEST(time_model, test_time_set_timing)
{
int64_t start_time = k_uptime_get();

is_randomized = false;
is_unsolicited = true;

while (k_uptime_get() - start_time < TEST_TIME) {
Expand Down Expand Up @@ -247,4 +256,36 @@ ZTEST(time_model, test_time_periodic_pub_status_mix)
zassert_equal(TEST_TIME / STATUS_INTERVAL_MIN, time_status_rx_number);
}

/** Test scenario: update handler of the Time model is called once
* (emulation of publication by timer). TTL should be equal configured value.
* Unsolicited Time Status is published. TTL should be 0.
* Unsolicited Time Status is published again. TTL is still 0.
* Update handler is called. TTL should go back to the configured value.
* Update handler is called again. TTL should be still equal the configured value.
*/
ZTEST(time_model, test_time_pub_ttl)
{
struct bt_mesh_model_pub *pub = mock_elem[0].models->pub;

is_skipped = true;

zassert_equal(10, pub->ttl);
zassert_ok(_bt_mesh_time_srv_update_handler(mock_elem[0].models));
zassert_equal(10, pub->ttl);

net_buf_simple_reset(pub->msg);
zassert_ok(bt_mesh_time_srv_time_status_send(&time_srv, NULL));
zassert_equal(0, pub->ttl);
net_buf_simple_reset(pub->msg);
zassert_ok(bt_mesh_time_srv_time_status_send(&time_srv, NULL));
zassert_equal(0, pub->ttl);

net_buf_simple_reset(pub->msg);
zassert_ok(_bt_mesh_time_srv_update_handler(mock_elem[0].models));
zassert_equal(10, pub->ttl);
net_buf_simple_reset(pub->msg);
zassert_ok(_bt_mesh_time_srv_update_handler(mock_elem[0].models));
zassert_equal(10, pub->ttl);
}

ZTEST_SUITE(time_model, NULL, NULL, tc_setup, tc_teardown, NULL);

0 comments on commit 0e3d208

Please sign in to comment.