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);