From 44bd56877bc817fd07a28c8f18211cda89be3a93 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 May 2018 18:50:07 +0300 Subject: [PATCH] Bluetooth: Mesh: Support for storing heartbeat publication persistently Add support for storing the heartbeat publication persistently. The information is only stored as "publish indefinitely" or as "periodic publishing disabled" since we can't know for how long the node is powered off. The information is stored under the settings key bt/mesh/HBPub. Signed-off-by: Johan Hedberg --- include/bluetooth/mesh/cfg_srv.h | 4 +- subsys/bluetooth/host/mesh/cfg_srv.c | 17 ++++ subsys/bluetooth/host/mesh/foundation.h | 2 + subsys/bluetooth/host/mesh/net.h | 1 + subsys/bluetooth/host/mesh/settings.c | 115 ++++++++++++++++++++++++ subsys/bluetooth/host/mesh/settings.h | 1 + 6 files changed, 138 insertions(+), 2 deletions(-) diff --git a/include/bluetooth/mesh/cfg_srv.h b/include/bluetooth/mesh/cfg_srv.h index 387480f38b8..5b7ba0c3650 100644 --- a/include/bluetooth/mesh/cfg_srv.h +++ b/include/bluetooth/mesh/cfg_srv.h @@ -30,7 +30,7 @@ struct bt_mesh_cfg_srv { u8_t default_ttl; /* Default TTL */ /* Heartbeat Publication */ - struct { + struct bt_mesh_hb_pub { struct k_delayed_work timer; u16_t dst; @@ -42,7 +42,7 @@ struct bt_mesh_cfg_srv { } hb_pub; /* Heartbeat Subscription */ - struct { + struct bt_mesh_hb_sub { s64_t expiry; u16_t src; diff --git a/subsys/bluetooth/host/mesh/cfg_srv.c b/subsys/bluetooth/host/mesh/cfg_srv.c index c5afcf11026..c4884647cfa 100644 --- a/subsys/bluetooth/host/mesh/cfg_srv.c +++ b/subsys/bluetooth/host/mesh/cfg_srv.c @@ -2902,6 +2902,10 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, } } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_hb_pub(); + } + hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); return; @@ -3338,12 +3342,25 @@ u8_t *bt_mesh_label_uuid_get(u16_t addr) return NULL; } +struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) +{ + if (!conf) { + return NULL; + } + + return &conf->hb_pub; +} + void bt_mesh_subnet_del(struct bt_mesh_subnet *sub) { int i; if (conf && conf->hb_pub.net_idx == sub->net_idx) { hb_pub_disable(conf); + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_hb_pub(); + } } /* Delete any app keys bound to this NetKey index */ diff --git a/subsys/bluetooth/host/mesh/foundation.h b/subsys/bluetooth/host/mesh/foundation.h index f5459e946b3..79aae6d3356 100644 --- a/subsys/bluetooth/host/mesh/foundation.h +++ b/subsys/bluetooth/host/mesh/foundation.h @@ -126,6 +126,8 @@ 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); + u8_t bt_mesh_net_transmit_get(void); u8_t bt_mesh_relay_get(void); u8_t bt_mesh_friend_get(void); diff --git a/subsys/bluetooth/host/mesh/net.h b/subsys/bluetooth/host/mesh/net.h index 6ab6170dda5..502345f04a6 100644 --- a/subsys/bluetooth/host/mesh/net.h +++ b/subsys/bluetooth/host/mesh/net.h @@ -204,6 +204,7 @@ enum { BT_MESH_NET_PENDING, BT_MESH_IV_PENDING, BT_MESH_SEQ_PENDING, + BT_MESH_HB_PUB_PENDING, BT_MESH_MOD_PENDING, /* Don't touch - intentionally last */ diff --git a/subsys/bluetooth/host/mesh/settings.c b/subsys/bluetooth/host/mesh/settings.c index 098c92c6573..ee036cf0162 100644 --- a/subsys/bluetooth/host/mesh/settings.c +++ b/subsys/bluetooth/host/mesh/settings.c @@ -58,6 +58,16 @@ struct seq_val { u8_t val[3]; } __packed; +/* Heartbeat Publication storage */ +struct hb_pub_val { + u16_t dst; + u8_t period; + u8_t ttl; + u16_t feat; + u16_t net_idx:12, + indefinite:1; +}; + /* IV Index & IV Update storage */ struct iv_val { u32_t iv_index; @@ -419,6 +429,59 @@ static int app_key_set(int argc, char **argv, char *val) return 0; } +static int hb_pub_set(int argc, char **argv, char *val) +{ + struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get(); + struct hb_pub_val hb_val; + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!pub) { + return -ENOENT; + } + + if (!val) { + pub->dst = BT_MESH_ADDR_UNASSIGNED; + pub->count = 0; + pub->ttl = 0; + pub->period = 0; + pub->feat = 0; + + BT_DBG("Cleared heartbeat publication"); + return 0; + } + + len = sizeof(hb_val); + err = settings_bytes_from_str(val, &hb_val, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(hb_val)) { + BT_ERR("Unexpected value length (%d != %zu)", len, + sizeof(hb_val)); + return -EINVAL; + } + + pub->dst = hb_val.dst; + pub->period = hb_val.period; + pub->ttl = hb_val.ttl; + pub->feat = hb_val.feat; + pub->net_idx = hb_val.net_idx; + + if (hb_val.indefinite) { + pub->count = 0xffff; + } else { + pub->count = 0; + } + + BT_DBG("Restored heartbeat publication"); + + return 0; +} + static int mod_set_bind(struct bt_mesh_model *mod, char *val) { int len, err, i; @@ -578,6 +641,7 @@ const struct mesh_setting { { "RPL", rpl_set }, { "NetKey", net_key_set }, { "AppKey", app_key_set }, + { "HBPub", hb_pub_set }, { "s", sig_mod_set }, { "v", vnd_mod_set }, }; @@ -653,6 +717,7 @@ static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, static int mesh_commit(void) { + struct bt_mesh_hb_pub *hb_pub; int i; BT_DBG("sub[0].net_idx 0x%03x", bt_mesh.sub[0].net_idx); @@ -691,6 +756,13 @@ static int mesh_commit(void) bt_mesh_model_foreach(commit_mod, NULL); + hb_pub = bt_mesh_hb_pub_get(); + if (hb_pub && hb_pub->dst != BT_MESH_ADDR_UNASSIGNED && + hb_pub->count && hb_pub->period) { + BT_DBG("Starting heartbeat publication"); + k_work_submit(&hb_pub->timer.work); + } + bt_mesh.valid = 1; bt_mesh_net_start(); @@ -880,6 +952,40 @@ static void store_pending_rpl(void) } } +static void store_pending_hb_pub(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))]; + struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get(); + struct hb_pub_val val; + char *str; + + if (!pub) { + return; + } + + if (pub->dst == BT_MESH_ADDR_UNASSIGNED) { + str = NULL; + } else { + val.indefinite = (pub->count = 0xffff); + val.dst = pub->dst; + val.period = pub->period; + val.ttl = pub->ttl; + val.feat = pub->feat; + val.net_idx = pub->net_idx; + + str = settings_str_from_bytes(&val, sizeof(val), + buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode hb pub as value"); + return; + } + } + + BT_DBG("Saving Heartbeat Publication as value %s", + str ? str : "(null)"); + settings_save_one("bt/mesh/HBPub", str); +} + static void clear_app_key(u16_t app_idx) { char path[20]; @@ -1163,6 +1269,10 @@ static void store_pending(struct k_work *work) store_pending_seq(); } + if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_HB_PUB_PENDING)) { + store_pending_hb_pub(); + } + if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { bt_mesh_model_foreach(store_pending_mod, NULL); } @@ -1255,6 +1365,11 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) schedule_store(BT_MESH_KEYS_PENDING); } +void bt_mesh_store_hb_pub(void) +{ + schedule_store(BT_MESH_HB_PUB_PENDING); +} + void bt_mesh_clear_net(void) { schedule_store(BT_MESH_NET_PENDING); diff --git a/subsys/bluetooth/host/mesh/settings.h b/subsys/bluetooth/host/mesh/settings.h index c8a8e4674e9..6b186094d71 100644 --- a/subsys/bluetooth/host/mesh/settings.h +++ b/subsys/bluetooth/host/mesh/settings.h @@ -10,6 +10,7 @@ void bt_mesh_store_seq(void); void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); void bt_mesh_store_subnet(struct bt_mesh_subnet *sub); void bt_mesh_store_app_key(struct bt_mesh_app_key *key); +void bt_mesh_store_hb_pub(void); void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); void bt_mesh_store_mod_pub(struct bt_mesh_model *mod);