Bluetooth: Mesh: Add support for Models Metadata Page 128

This patch adds for handling Models Metadata Get Page 128.

Signed-off-by: Michal Narajowski <michal.narajowski@codecoup.pl>
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
Michal Narajowski 2022-07-20 13:26:32 +02:00 committed by Carles Cufí
commit d95fe3f52b
7 changed files with 175 additions and 31 deletions

View file

@ -897,6 +897,15 @@ bool bt_mesh_model_is_extended(struct bt_mesh_model *model);
*/
int bt_mesh_comp_change_prepare(void);
/** @brief Indicate that the metadata will change on next bootup.
*
* Tell the config server that the models metadata is expected to change on
* the next bootup, and the current models metadata should be backed up.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_models_metadata_change_prepare(void);
/** Node Composition */
struct bt_mesh_comp {
uint16_t cid; /**< Company ID */

View file

@ -1235,8 +1235,19 @@ config BT_MESH_LARGE_COMP_DATA_SRV
help
Enable support for the Large Composition Data Server model.
if BT_MESH_LARGE_COMP_DATA_SRV
config BT_MESH_MODELS_METADATA_PAGE_LEN
int "Maximum length of the Models Metadata Page"
default 150
help
This value is the combined total metadata length for
all models on the device.
endif # BT_MESH_LARGE_COMP_DATA_SRV
config BT_MESH_LARGE_COMP_DATA_CLI
bool "Support for Large Composition Data Client Model"
bool "Support for Large Composition Data Client model"
help
Enable support for the Large Composition Data Client model.

View file

@ -168,7 +168,7 @@ static void comp_add_model(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
}
}
#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV
#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
static void data_buf_add_mem_offset(struct net_buf_simple *buf,
const void *mem, size_t len,
size_t *offset)
@ -190,6 +190,10 @@ static size_t metadata_model_size(struct bt_mesh_model *mod,
const struct bt_mesh_models_metadata_entry *entry;
size_t size = 0;
if (!mod->metadata) {
return size;
}
if (vnd) {
size += sizeof(mod->vnd.company);
size += sizeof(mod->vnd.id);
@ -199,10 +203,6 @@ static size_t metadata_model_size(struct bt_mesh_model *mod,
size += sizeof(uint8_t);
if (!mod->metadata) {
return size;
}
for (entry = *mod->metadata; entry && entry->len; ++entry) {
size += sizeof(entry->len) + sizeof(entry->id) + entry->len;
}
@ -254,13 +254,13 @@ static int metadata_add_model(struct bt_mesh_model *mod,
model_size = metadata_model_size(mod, elem, vnd);
if (*offset <= model_size) {
if (*offset >= model_size) {
*offset -= model_size;
return 0;
}
if (net_buf_simple_tailroom(buf) < (model_size + BT_MESH_MIC_SHORT)) {
LOG_ERR("Too large metadata");
LOG_DBG("Model metadata didn't fit in the buffer");
return -E2BIG;
}
@ -293,7 +293,6 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset)
};
uint8_t *mod_count_ptr;
uint8_t *vnd_count_ptr;
uint8_t mod_count = 0;
int i, j, err;
comp = bt_mesh_comp_get();
@ -317,19 +316,16 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset)
continue;
}
++mod_count;
err = metadata_add_model(model, elem, false, &arg);
if (err) {
return err;
}
}
if (mod_count_ptr) {
*mod_count_ptr = mod_count;
if (mod_count_ptr) {
(*mod_count_ptr) += 1;
}
}
mod_count = 0;
for (j = 0; j < elem->vnd_model_count; j++) {
struct bt_mesh_model *model = &elem->vnd_models[j];
@ -337,15 +333,14 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset)
continue;
}
++mod_count;
err = metadata_add_model(model, elem, true, &arg);
if (err) {
return err;
}
}
if (vnd_count_ptr) {
*vnd_count_ptr = mod_count;
if (vnd_count_ptr) {
(*vnd_count_ptr) += 1;
}
}
}
@ -1990,6 +1985,116 @@ int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
return err;
}
#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
static int metadata_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_METADATA_DIRTY);
}
return 0;
}
BT_MESH_SETTINGS_DEFINE(metadata, "metadata", metadata_set);
int bt_mesh_models_metadata_store(void)
{
NET_BUF_SIMPLE_DEFINE(buf, CONFIG_BT_MESH_MODELS_METADATA_PAGE_LEN);
size_t total_size;
int err;
total_size = bt_mesh_metadata_page_0_size();
LOG_DBG("bt/mesh/metadata total %d", total_size);
net_buf_simple_init(&buf, 0);
net_buf_simple_add_le16(&buf, total_size);
err = bt_mesh_metadata_get_page_0(&buf, 0);
if (err == -E2BIG) {
LOG_ERR("Metadata too large");
return err;
}
if (err) {
LOG_ERR("Failed to read models metadata: %d", err);
return err;
}
LOG_DBG("bt/mesh/metadata len %d", buf.len);
err = settings_save_one("bt/mesh/metadata", buf.data, buf.len);
if (err) {
LOG_ERR("Failed to store models metadata: %d", err);
} else {
LOG_DBG("Stored models metadata");
}
return err;
}
int bt_mesh_models_metadata_read(struct net_buf_simple *buf, size_t offset)
{
NET_BUF_SIMPLE_DEFINE(stored_buf, CONFIG_BT_MESH_MODELS_METADATA_PAGE_LEN);
size_t original_len = buf->len;
int err;
if (!IS_ENABLED(CONFIG_BT_SETTINGS)) {
return -ENOTSUP;
}
net_buf_simple_init(&stored_buf, 0);
err = settings_load_subtree_direct("bt/mesh/metadata", read_comp_cb, &stored_buf);
if (err) {
LOG_ERR("Failed reading models metadata: %d", err);
return err;
}
/* First two bytes are total length */
offset += 2;
net_buf_simple_add_mem(buf, &stored_buf.data, MIN(net_buf_simple_tailroom(buf), 2));
if (offset >= stored_buf.len) {
return 0;
}
net_buf_simple_add_mem(buf, &stored_buf.data[offset],
MIN(net_buf_simple_tailroom(buf), stored_buf.len - offset));
LOG_DBG("metadata read %d", buf->len);
if (buf->len == original_len) {
return -ENOENT;
}
return 0;
}
#endif
void bt_mesh_models_metadata_clear(void)
{
int err;
err = settings_delete("bt/mesh/metadata");
if (err) {
LOG_ERR("Failed to clear models metadata: %d", err);
} else {
LOG_DBG("Cleared models metadata");
}
atomic_clear_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY);
}
int bt_mesh_models_metadata_change_prepare(void)
{
#if !IS_ENABLED(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
return -ENOTSUP;
#endif
return bt_mesh_models_metadata_store();
}
static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{

View file

@ -65,6 +65,10 @@ int bt_mesh_comp_store(void);
void bt_mesh_comp_clear(void);
int bt_mesh_comp_read(struct net_buf_simple *buf);
int bt_mesh_models_metadata_store(void);
void bt_mesh_models_metadata_clear(void);
int bt_mesh_models_metadata_read(struct net_buf_simple *buf, size_t offset);
void bt_mesh_model_pending_store(void);
void bt_mesh_model_bind_store(struct bt_mesh_model *mod);
void bt_mesh_model_sub_store(struct bt_mesh_model *mod);

View file

@ -91,8 +91,8 @@ static int handle_models_metadata_get(struct bt_mesh_model *model, struct bt_mes
{
BT_MESH_MODEL_BUF_DEFINE(rsp, OP_MODELS_METADATA_STATUS,
BT_MESH_MODEL_PAYLOAD_MAX);
uint8_t page;
size_t offset, total_size;
uint8_t page;
int err;
LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@ -104,25 +104,38 @@ static int handle_models_metadata_get(struct bt_mesh_model *model, struct bt_mes
LOG_DBG("page %u offset %u", page, offset);
bt_mesh_model_msg_init(&rsp, OP_MODELS_METADATA_STATUS);
if (page != 0U) {
LOG_DBG("Composition page %u not available", page);
if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY)) {
LOG_DBG("Models Metadata Page 128");
page = 128U;
} else if (page != 0U) {
LOG_DBG("Models Metadata Page %u not available", page);
page = 0U;
}
bt_mesh_model_msg_init(&rsp, OP_MODELS_METADATA_STATUS);
net_buf_simple_add_u8(&rsp, page);
total_size = bt_mesh_metadata_page_0_size();
net_buf_simple_add_le16(&rsp, offset);
net_buf_simple_add_le16(&rsp, total_size);
if (offset < total_size) {
err = bt_mesh_metadata_get_page_0(&rsp, offset);
if (err && err != -E2BIG) {
LOG_ERR("bt_mesh_metadata_get_page_0 returned error");
if (atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY) == (page == 0U)) {
rsp.size -= BT_MESH_MIC_SHORT;
err = bt_mesh_models_metadata_read(&rsp, offset);
if (err) {
LOG_ERR("Unable to get stored models metadata");
return err;
}
rsp.size += BT_MESH_MIC_SHORT;
} else {
total_size = bt_mesh_metadata_page_0_size();
net_buf_simple_add_le16(&rsp, total_size);
if (offset < total_size) {
err = bt_mesh_metadata_get_page_0(&rsp, offset);
if (err && err != -E2BIG) {
LOG_ERR("Failed to get Models Metadata Page 0: %d", err);
return err;
}
}
}
if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {

View file

@ -161,6 +161,7 @@ void bt_mesh_reprovision(uint16_t addr)
bt_mesh_net_pending_net_store();
bt_mesh_net_pending_seq_store();
bt_mesh_comp_clear();
bt_mesh_models_metadata_clear();
}
}

View file

@ -180,6 +180,7 @@ enum {
BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */
BT_MESH_COMP_DIRTY, /* Composition data is dirty */
BT_MESH_DEVKEY_CAND, /* Has device key candidate */
BT_MESH_METADATA_DIRTY, /* Models metadata is dirty */
/* Feature flags */
BT_MESH_RELAY,