From 85431fd69e03c9baeefc313b4d240d3a7085b248 Mon Sep 17 00:00:00 2001 From: Trond Einar Snekvik Date: Fri, 13 Mar 2020 15:58:47 +0100 Subject: [PATCH] Bluetooth: Mesh: Add composition data page 128 Composition data page 128 represents the new composition data after a composition refresh procedure. The implementation stores the old composition data (before applying a DFU or similar), and uses that as page 0 if present. As the device has already rebooted by the time page 128 becomes active, its active composition data is page 128, while the backed up data is the "old" data, which should be shown as page 0. Co-authored-by: Ingar Kulbrandstad Signed-off-by: Trond Einar Snekvik Signed-off-by: Pavel Vasilyev --- include/zephyr/bluetooth/mesh/access.h | 9 +++ subsys/bluetooth/mesh/access.c | 97 ++++++++++++++++++++++++++ subsys/bluetooth/mesh/access.h | 3 + subsys/bluetooth/mesh/cfg_cli.c | 2 +- subsys/bluetooth/mesh/cfg_srv.c | 25 +++++-- subsys/bluetooth/mesh/net.h | 1 + 6 files changed, 131 insertions(+), 6 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 99352e1da23..4a0aa9781b5 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -757,6 +757,15 @@ int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, */ bool bt_mesh_model_is_extended(struct bt_mesh_model *model); +/** @brief Indicate that the composition data will change on next bootup. + * + * Tell the config server that the composition data is expected to change on + * the next bootup, and the current composition data should be backed up. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_comp_change_prepare(void); + /** Node Composition */ struct bt_mesh_comp { uint16_t cid; /**< Company ID */ diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index ff436d03676..5cec971080b 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -1078,6 +1078,20 @@ static int vnd_mod_set(const char *name, size_t len_rd, BT_MESH_SETTINGS_DEFINE(vnd_mod, "v", vnd_mod_set); +static int comp_set(const char *name, size_t len_rd, settings_read_cb read_cb, + void *cb_arg) +{ + /* Only need to know that the entry exists. Will load the contents on + * demand. + */ + if (len_rd > 0) { + atomic_set_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY); + } + + return 0; +} +BT_MESH_SETTINGS_DEFINE(comp, "cmp", comp_set); + static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, const char *key, char *path, size_t path_len) { @@ -1222,6 +1236,89 @@ void bt_mesh_model_pub_store(struct bt_mesh_model *mod) bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } +int bt_mesh_comp_store(void) +{ + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); + int err; + + err = bt_mesh_comp_get_page_0(&buf); + if (err) { + LOG_ERR("Failed to read composition data: %d", err); + return err; + } + + err = settings_save_one("bt/mesh/cmp", buf.data, buf.len); + if (err) { + LOG_ERR("Failed to store composition data: %d", err); + } else { + LOG_DBG("Stored composition data"); + } + + return err; +} + +int bt_mesh_comp_change_prepare(void) +{ + if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { + return -ENOTSUP; + } + + return bt_mesh_comp_store(); +} + +void bt_mesh_comp_clear(void) +{ + int err; + + err = settings_delete("bt/mesh/cmp"); + if (err) { + LOG_ERR("Failed to clear composition data: %d", err); + } else { + LOG_DBG("Cleared composition data page 128"); + } + + atomic_clear_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY); +} + +static int read_comp_cb(const char *key, size_t len, settings_read_cb read_cb, + void *cb_arg, void *param) +{ + struct net_buf_simple *buf = param; + + if (len > net_buf_simple_tailroom(buf)) { + return -ENOBUFS; + } + + len = read_cb(cb_arg, net_buf_simple_tail(buf), len); + if (len > 0) { + net_buf_simple_add(buf, len); + } + + return -EALREADY; +} + +int bt_mesh_comp_read(struct net_buf_simple *buf) +{ + size_t original_len = buf->len; + int err; + + if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { + return -ENOTSUP; + } + + err = settings_load_subtree_direct("bt/mesh/cmp", read_comp_cb, buf); + if (err) { + LOG_ERR("Failed reading composition data: %d", err); + return err; + } + + if (buf->len == original_len) { + return -ENOENT; + } + + return 0; +} + int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, const char *name, const void *data, size_t data_len) diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 4d0bfafb1df..0fe1f514682 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -57,6 +57,9 @@ void bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); int bt_mesh_comp_register(const struct bt_mesh_comp *comp); +int bt_mesh_comp_store(void); +void bt_mesh_comp_clear(void); +int bt_mesh_comp_read(struct net_buf_simple *buf); void bt_mesh_model_pending_store(void); void bt_mesh_model_bind_store(struct bt_mesh_model *mod); diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index 079549e751e..de3a212413b 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -47,8 +47,8 @@ static int comp_data_status(struct bt_mesh_model *model, struct net_buf_simple *buf) { struct comp_data *param; - uint8_t page; size_t to_copy; + uint8_t page; LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index ccd63018676..5f36195c0ae 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -132,7 +132,11 @@ static int dev_comp_data_get(struct bt_mesh_model *model, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); page = net_buf_simple_pull_u8(buf); - if (page != 0U) { + + if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY)) { + LOG_DBG("Composition data page 128"); + page = 128U; + } else if (page != 0U) { LOG_DBG("Composition page %u not available", page); page = 0U; } @@ -140,10 +144,21 @@ static int dev_comp_data_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(&sdu, OP_DEV_COMP_DATA_STATUS); net_buf_simple_add_u8(&sdu, page); - err = bt_mesh_comp_get_page_0(&sdu); - if (err) { - LOG_ERR("Unable to get composition page 0"); - return err; + if (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) == (page == 0U)) { + sdu.size -= BT_MESH_MIC_SHORT; + err = bt_mesh_comp_read(&sdu); + if (err) { + LOG_ERR("Unable to get stored composition data"); + return err; + } + + sdu.size += BT_MESH_MIC_SHORT; + } else { + err = bt_mesh_comp_get_page_0(&sdu); + if (err < 0) { + LOG_ERR("Unable to get composition page 0"); + return err; + } } if (bt_mesh_model_send(model, ctx, &sdu, NULL, NULL)) { diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index a5002bbd68f..f877bfc6d13 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -177,6 +177,7 @@ enum { BT_MESH_IVU_INITIATOR, /* IV Update initiated by us */ BT_MESH_IVU_TEST, /* IV Update test mode */ BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */ + BT_MESH_COMP_DIRTY, /* Composition data is dirty */ /* Feature flags */ BT_MESH_RELAY,