Bluetooth: Mesh: Support for storing model publication persistently
Add support for storing the model publication information
persistently. The addresses are stored under the settings key
bt/mesh/s/<mod id>/pub for SIG models and bt/mesh/v/<mod id>/pub for
vendor models.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
diff --git a/subsys/bluetooth/host/mesh/access.h b/subsys/bluetooth/host/mesh/access.h
index 9d7720a..a6b9d0e 100644
--- a/subsys/bluetooth/host/mesh/access.h
+++ b/subsys/bluetooth/host/mesh/access.h
@@ -10,6 +10,7 @@
enum {
BT_MESH_MOD_BIND_PENDING = BIT(0),
BT_MESH_MOD_SUB_PENDING = BIT(1),
+ BT_MESH_MOD_PUB_PENDING = BIT(2),
};
void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count);
diff --git a/subsys/bluetooth/host/mesh/cfg_srv.c b/subsys/bluetooth/host/mesh/cfg_srv.c
index 8d543e0..c5afcf1 100644
--- a/subsys/bluetooth/host/mesh/cfg_srv.c
+++ b/subsys/bluetooth/host/mesh/cfg_srv.c
@@ -272,6 +272,10 @@
k_delayed_work_cancel(&model->pub->timer);
}
+ if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
+ bt_mesh_store_mod_pub(model);
+ }
+
return STATUS_SUCCESS;
}
@@ -299,6 +303,10 @@
}
}
+ if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
+ bt_mesh_store_mod_pub(model);
+ }
+
return STATUS_SUCCESS;
}
diff --git a/subsys/bluetooth/host/mesh/settings.c b/subsys/bluetooth/host/mesh/settings.c
index 6ac7deb..098c92c 100644
--- a/subsys/bluetooth/host/mesh/settings.c
+++ b/subsys/bluetooth/host/mesh/settings.c
@@ -84,6 +84,16 @@
u8_t val[2][16];
} __packed;
+struct mod_pub_val {
+ u16_t addr;
+ u16_t key;
+ u8_t ttl;
+ u8_t retransmit;
+ u8_t period;
+ u8_t period_div:4,
+ cred:1;
+};
+
static int net_set(int argc, char **argv, char *val)
{
struct net_val net;
@@ -458,6 +468,55 @@
return 0;
}
+static int mod_set_pub(struct bt_mesh_model *mod, char *val)
+{
+ struct mod_pub_val pub;
+ int len, err;
+
+ if (!mod->pub) {
+ BT_WARN("Model has no publication context!");
+ return -EINVAL;
+ }
+
+ if (!val) {
+ mod->pub->addr = BT_MESH_ADDR_UNASSIGNED;
+ mod->pub->key = 0;
+ mod->pub->cred = 0;
+ mod->pub->ttl = 0;
+ mod->pub->period = 0;
+ mod->pub->retransmit = 0;
+ mod->pub->count = 0;
+
+ BT_DBG("Cleared publication for model");
+ return 0;
+ }
+
+ len = sizeof(pub);
+ err = settings_bytes_from_str(val, &pub, &len);
+ if (err) {
+ BT_ERR("Failed to decode value %s (err %d)", val, err);
+ return -EINVAL;
+ }
+
+ if (len != sizeof(pub)) {
+ BT_ERR("Invalid length for model publication");
+ return -EINVAL;
+ }
+
+ mod->pub->addr = pub.addr;
+ mod->pub->key = pub.key;
+ mod->pub->cred = pub.cred;
+ mod->pub->ttl = pub.ttl;
+ mod->pub->period = pub.period;
+ mod->pub->retransmit = pub.retransmit;
+ mod->pub->count = 0;
+
+ BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x",
+ pub.addr, pub.key);
+
+ return 0;
+}
+
static int mod_set(bool vnd, int argc, char **argv, char *val)
{
struct bt_mesh_model *mod;
@@ -491,6 +550,10 @@
return mod_set_sub(mod, val);
}
+ if (!strcmp(argv[1], "pub")) {
+ return mod_set_pub(mod, val);
+ }
+
BT_WARN("Unknown module key %s", argv[1]);
return -ENOENT;
}
@@ -575,6 +638,19 @@
return 0;
}
+static void commit_mod(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->addr != BT_MESH_ADDR_UNASSIGNED) {
+ s32_t ms = bt_mesh_model_pub_period_get(mod);
+ if (ms) {
+ BT_DBG("Starting publish timer (period %u ms)", ms);
+ k_delayed_work_submit(&mod->pub->timer, ms);
+ }
+ }
+}
+
static int mesh_commit(void)
{
int i;
@@ -613,6 +689,8 @@
BT_MESH_NET_IVU_TIMEOUT);
}
+ bt_mesh_model_foreach(commit_mod, NULL);
+
bt_mesh.valid = 1;
bt_mesh_net_start();
@@ -993,6 +1071,38 @@
settings_save_one(path, val);
}
+static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
+{
+ char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))];
+ struct mod_pub_val pub;
+ char path[20];
+ char *val;
+
+ if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
+ val = NULL;
+ } else {
+ pub.addr = mod->pub->addr;
+ pub.key = mod->pub->key;
+ pub.ttl = mod->pub->ttl;
+ pub.retransmit = mod->pub->retransmit;
+ pub.period = mod->pub->period;
+ pub.period_div = mod->pub->period_div;
+ pub.cred = mod->pub->cred;
+
+ val = settings_str_from_bytes(&pub, sizeof(pub),
+ buf, sizeof(buf));
+ if (!val) {
+ BT_ERR("Unable to encode model publication as value");
+ return;
+ }
+ }
+
+ encode_mod_path(mod, vnd, "pub", path, sizeof(path));
+
+ BT_DBG("Saving %s as %s", path, val ? val : "(null)");
+ settings_save_one(path, val);
+}
+
static void store_pending_mod(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem, bool vnd,
bool primary, void *user_data)
@@ -1010,6 +1120,11 @@
mod->flags &= ~BT_MESH_MOD_SUB_PENDING;
store_pending_mod_sub(mod, vnd);
}
+
+ if (mod->flags & BT_MESH_MOD_PUB_PENDING) {
+ mod->flags &= ~BT_MESH_MOD_PUB_PENDING;
+ store_pending_mod_pub(mod, vnd);
+ }
}
static void store_pending(struct k_work *work)
@@ -1215,6 +1330,12 @@
schedule_store(BT_MESH_MOD_PENDING);
}
+void bt_mesh_store_mod_pub(struct bt_mesh_model *mod)
+{
+ mod->flags |= BT_MESH_MOD_PUB_PENDING;
+ schedule_store(BT_MESH_MOD_PENDING);
+}
+
void bt_mesh_settings_init(void)
{
k_delayed_work_init(&pending_store, store_pending);
diff --git a/subsys/bluetooth/host/mesh/settings.h b/subsys/bluetooth/host/mesh/settings.h
index cfb38d1..c8a8e46 100644
--- a/subsys/bluetooth/host/mesh/settings.h
+++ b/subsys/bluetooth/host/mesh/settings.h
@@ -12,6 +12,7 @@
void bt_mesh_store_app_key(struct bt_mesh_app_key *key);
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);
void bt_mesh_clear_net(void);
void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub);