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 <ingar.kulbrandstad@nordicsemi.no>
Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no>
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
Trond Einar Snekvik 2020-03-13 15:58:47 +01:00 committed by Carles Cufí
commit 85431fd69e
6 changed files with 131 additions and 6 deletions

View file

@ -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); 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 */ /** Node Composition */
struct bt_mesh_comp { struct bt_mesh_comp {
uint16_t cid; /**< Company ID */ uint16_t cid; /**< Company ID */

View file

@ -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); 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, static void encode_mod_path(struct bt_mesh_model *mod, bool vnd,
const char *key, char *path, size_t path_len) 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); 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, int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
const char *name, const void *data, const char *name, const void *data,
size_t data_len) size_t data_len)

View file

@ -57,6 +57,9 @@ void bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf); struct net_buf_simple *buf);
int bt_mesh_comp_register(const struct bt_mesh_comp *comp); 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_pending_store(void);
void bt_mesh_model_bind_store(struct bt_mesh_model *mod); void bt_mesh_model_bind_store(struct bt_mesh_model *mod);

View file

@ -47,8 +47,8 @@ static int comp_data_status(struct bt_mesh_model *model,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
struct comp_data *param; struct comp_data *param;
uint8_t page;
size_t to_copy; 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, 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)); ctx->addr, buf->len, bt_hex(buf->data, buf->len));

View file

@ -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)); ctx->addr, buf->len, bt_hex(buf->data, buf->len));
page = net_buf_simple_pull_u8(buf); 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); LOG_DBG("Composition page %u not available", page);
page = 0U; 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); bt_mesh_model_msg_init(&sdu, OP_DEV_COMP_DATA_STATUS);
net_buf_simple_add_u8(&sdu, page); net_buf_simple_add_u8(&sdu, page);
err = bt_mesh_comp_get_page_0(&sdu); if (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) == (page == 0U)) {
if (err) { sdu.size -= BT_MESH_MIC_SHORT;
LOG_ERR("Unable to get composition page 0"); err = bt_mesh_comp_read(&sdu);
return err; 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)) { if (bt_mesh_model_send(model, ctx, &sdu, NULL, NULL)) {

View file

@ -177,6 +177,7 @@ enum {
BT_MESH_IVU_INITIATOR, /* IV Update initiated by us */ BT_MESH_IVU_INITIATOR, /* IV Update initiated by us */
BT_MESH_IVU_TEST, /* IV Update test mode */ BT_MESH_IVU_TEST, /* IV Update test mode */
BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */ BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */
BT_MESH_COMP_DIRTY, /* Composition data is dirty */
/* Feature flags */ /* Feature flags */
BT_MESH_RELAY, BT_MESH_RELAY,