From d42c018ffb9a6f2cb4b51e7429fe4450a1b1c8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Narajowski?= Date: Wed, 30 Jan 2019 15:49:15 +0100 Subject: [PATCH] mesh: Fix publish timer handling when sending fails Sending a model publication message could fail e.g. if there are no buffers available, however this doesn't mean that we should stop doing periodic publishing indefinitely. When an error occurs, make sure to call the publish_sent() function so that the periodic publishing timer gets resubmitted if necessary. --- nimble/host/mesh/include/mesh/main.h | 21 ++++++++ nimble/host/mesh/src/adv.c | 5 ++ nimble/host/mesh/src/cfg_srv.c | 7 +++ nimble/host/mesh/src/foundation.h | 1 + nimble/host/mesh/src/mesh.c | 79 ++++++++++++++++++++++++++++ nimble/host/mesh/src/net.h | 1 + 6 files changed, 114 insertions(+) diff --git a/nimble/host/mesh/include/mesh/main.h b/nimble/host/mesh/include/mesh/main.h index 8abb8f8de..515d1d527 100644 --- a/nimble/host/mesh/include/mesh/main.h +++ b/nimble/host/mesh/include/mesh/main.h @@ -281,6 +281,27 @@ int bt_mesh_init(u8_t own_addr_type, */ void bt_mesh_reset(void); +/** @brief Suspend the Mesh network temporarily. + * + * This API can be used for power saving purposes, but the user should be + * aware that leaving the local node suspended for a long period of time + * may cause it to become permanently disconnected from the Mesh network. + * If at all possible, the Friendship feature should be used instead, to + * make the node into a Low Power Node. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_suspend(void); + +/** @brief Resume a suspended Mesh network. + * + * This API resumes the local node, after it has been suspended using the + * bt_mesh_suspend() API. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_resume(void); + /** @brief Provision the local Mesh Node. * * This API should normally not be used directly by the application. The diff --git a/nimble/host/mesh/src/adv.c b/nimble/host/mesh/src/adv.c index 82c5c1bbf..6cb15ce6f 100644 --- a/nimble/host/mesh/src/adv.c +++ b/nimble/host/mesh/src/adv.c @@ -207,6 +207,11 @@ struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool, struct bt_mesh_adv *adv; struct os_mbuf *buf; + if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + BT_WARN("Refusing to allocate buffer while suspended"); + return NULL; + } + buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE); if (!buf) { return NULL; diff --git a/nimble/host/mesh/src/cfg_srv.c b/nimble/host/mesh/src/cfg_srv.c index f9f871ee6..faad75d8b 100644 --- a/nimble/host/mesh/src/cfg_srv.c +++ b/nimble/host/mesh/src/cfg_srv.c @@ -3574,6 +3574,13 @@ struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) return &conf->hb_pub; } +void bt_mesh_hb_pub_disable(void) +{ + if (conf) { + hb_pub_disable(conf); + } +} + struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) { return conf; diff --git a/nimble/host/mesh/src/foundation.h b/nimble/host/mesh/src/foundation.h index cd92c023f..2c257ee38 100644 --- a/nimble/host/mesh/src/foundation.h +++ b/nimble/host/mesh/src/foundation.h @@ -130,6 +130,7 @@ void bt_mesh_attention(struct bt_mesh_model *model, u8_t time); u8_t *bt_mesh_label_uuid_get(u16_t addr); struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void); +void bt_mesh_hb_pub_disable(void); struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void); u8_t bt_mesh_net_transmit_get(void); diff --git a/nimble/host/mesh/src/mesh.c b/nimble/host/mesh/src/mesh.c index 82755b98c..538a2d278 100644 --- a/nimble/host/mesh/src/mesh.c +++ b/nimble/host/mesh/src/mesh.c @@ -206,6 +206,85 @@ static int bt_mesh_gap_event(struct ble_gap_event *event, void *arg) return 0; } +static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (mod->pub && mod->pub->update) { + mod->pub->count = 0; + k_delayed_work_cancel(&mod->pub->timer); + } +} + +int bt_mesh_suspend(void) +{ + int err; + + if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + return -EINVAL; + } + + if (atomic_test_and_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + return -EALREADY; + } + + err = bt_mesh_scan_disable(); + if (err) { + atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); + BT_WARN("Disabling scanning failed (err %d)", err); + return err; + } + + bt_mesh_hb_pub_disable(); + + if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) { + bt_mesh_beacon_disable(); + } + + bt_mesh_model_foreach(model_suspend, NULL); + + return 0; +} + +static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (mod->pub && mod->pub->update) { + s32_t period_ms = bt_mesh_model_pub_period_get(mod); + + if (period_ms) { + k_delayed_work_submit(&mod->pub->timer, period_ms); + } + } +} + +int bt_mesh_resume(void) +{ + int err; + + if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + return -EINVAL; + } + + if (!atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + return -EALREADY; + } + + err = bt_mesh_scan_enable(); + if (err) { + BT_WARN("Re-enabling scanning failed (err %d)", err); + atomic_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED); + return err; + } + + if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) { + bt_mesh_beacon_enable(); + } + + bt_mesh_model_foreach(model_resume, NULL); + + return err; +} + int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov, const struct bt_mesh_comp *comp) { diff --git a/nimble/host/mesh/src/net.h b/nimble/host/mesh/src/net.h index aec11500c..e55102c06 100644 --- a/nimble/host/mesh/src/net.h +++ b/nimble/host/mesh/src/net.h @@ -202,6 +202,7 @@ struct bt_mesh_lpn { /* bt_mesh_net.flags */ enum { BT_MESH_VALID, /* We have been provisioned */ + BT_MESH_SUSPENDED, /* Network is temporarily suspended */ BT_MESH_IVU_IN_PROGRESS, /* IV Update in Progress */ BT_MESH_IVU_INITIATOR, /* IV Update initiated by us */ BT_MESH_IVU_TEST, /* IV Update test mode */