diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index b58f0646758..3c28548dff3 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -857,6 +857,29 @@ int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod); +/** @brief Let a model correspond to another. + * + * Mesh models may correspond to each other, which means that if one is present, + * other must be present too. A Mesh model may correspond to any number of models, + * in any element. All models connected together via correspondence form single + * Correspondence Group, which has it's unique Correspondence ID. Information about + * Correspondence is used to construct Composition Data Page 1. + * + * This function must be called on already initialized base_mod. Because this function + * is designed to be called in corresponding_mod initializer, this means that base_mod + * shall be initialized before corresponding_mod is. + * + * @param corresponding_mod Mesh model that is corresponding to the base model. + * @param base_mod The model being corresponded to. + * + * @retval 0 Successfully saved correspondence to the base_mod model. + * @retval -ENOMEM There is no more space to save this relation. + * @retval -ENOTSUP Composition Data Page 1 is not supported. + */ + +int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, + struct bt_mesh_model *base_mod); + /** @brief Check if model is extended by another model. * * @param model The model to check. diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index e0c1a63fa12..74bd7ade70a 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -1545,6 +1545,102 @@ uint16_t bt_mesh_comp_p0_elem_mod(struct bt_mesh_comp_p0_elem *elem, int idx); */ struct bt_mesh_mod_id_vnd bt_mesh_comp_p0_elem_mod_vnd(struct bt_mesh_comp_p0_elem *elem, int idx); +struct bt_mesh_comp_p1_elem { + /** The number of SIG models in this element */ + size_t nsig; + /** The number of vendor models in this element */ + size_t nvnd; + /** Buffer containig SIG and Vendor Model Items */ + struct net_buf_simple *_buf; +}; + +/** Composition data page 1 model item representation */ +struct bt_mesh_comp_p1_model_item { + /** Corresponding_Group_ID field indicator */ + bool cor_present; + /** Determines the format of Extended Model Item */ + bool format; + /** Number of items in Extended Model Items*/ + uint8_t ext_item_cnt : 6; + /** Buffer containing Extended Model Items. + * If cor_present is set to 1 it starts with + * Corresponding_Group_ID + */ + uint8_t cor_id; + struct net_buf_simple *_buf; +}; + +/** Extended Model Item in short representation */ +struct bt_mesh_comp_p1_item_short { + /** Element address modifier */ + uint8_t elem_offset : 3; + /** Model Index */ + uint8_t mod_item_idx : 5; +}; + +/** Extended Model Item in long representation */ +struct bt_mesh_comp_p1_item_long { + /** Element address modifier */ + uint8_t elem_offset; + /** Model Index */ + uint8_t mod_item_idx; +}; + +/** Extended Model Item */ +struct bt_mesh_comp_p1_ext_item { + enum { SHORT, LONG } type; + + union { + /** Item in short representation */ + struct bt_mesh_comp_p1_item_short short_item; + /** Item in long representation */ + struct bt_mesh_comp_p1_item_long long_item; + }; +}; + +/** @brief Pull a Composition Data Page 1 Element from a composition data page 1 + * instance. + * + * Each call to this function will pull out a new element from the composition + * data page, until all elements have been pulled. + * + * @param buf Composition data page 1 buffer + * @param elem Element to fill. + * + * @return A pointer to @c elem on success, or NULL if no more elements could + * be pulled. + */ +struct bt_mesh_comp_p1_elem *bt_mesh_comp_p1_elem_pull( + struct net_buf_simple *buf, struct bt_mesh_comp_p1_elem *elem); + +/** @brief Pull a Composition Data Page 1 Model Item from a Composition Data + * Page 1 Element + * + * Each call to this function will pull out a new item from the Composition Data + * Page 1 Element, until all items have been pulled. + * + * @param elem Composition data page 1 Element + * @param item Model Item to fill. + * + * @return A pointer to @c item on success, or NULL if no more elements could + * be pulled. + */ +struct bt_mesh_comp_p1_model_item *bt_mesh_comp_p1_item_pull( + struct bt_mesh_comp_p1_elem *elem, struct bt_mesh_comp_p1_model_item *item); + +/** @brief Pull Extended Model Item contained in Model Item + * + * Each call to this function will pull out a new element + * from the Extended Model Item, until all elements have been pulled. + * + * @param item Model Item to pull Extended Model Items from + * @param ext_item Extended Model Item to fill + * + * @return A pointer to @c ext_item on success, or NULL if item could not be pulled + */ +struct bt_mesh_comp_p1_ext_item *bt_mesh_comp_p1_pull_ext_item( + struct bt_mesh_comp_p1_model_item *item, struct bt_mesh_comp_p1_ext_item *ext_item); + /** @cond INTERNAL_HIDDEN */ extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index c6e2794c7e8..0d1293c2937 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1260,6 +1260,21 @@ config BT_MESH_PRIV_BEACON_CLI endif # BT_MESH_PRIV_BEACONS +config BT_MESH_COMP_PAGE_1 + bool "Support for Composition Data Page 1" + depends on BT_MESH_MODEL_EXTENSIONS + help + Enable support for Composition Data Page 1. + +config BT_MESH_MODEL_EXTENSION_LIST_SIZE + int "Model extensions list size" + depends on BT_MESH_COMP_PAGE_1 + default 10 + help + This option specifies how many models relations can be saved. + Equals to the number of `bt_mesh_model_extend` and `bt_mesh_model_correspond` calls. + This information is used to construct Composition Data Page 1. + menu "Transport SAR configuration" config BT_MESH_SAR_TX_SEG_INT_STEP diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index f36f87cd822..604cd3f43e1 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -52,6 +52,54 @@ static const struct bt_mesh_comp *dev_comp; static uint16_t dev_primary_addr; static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); +/* Structure containing information about model extension */ +struct mod_relation { + /** Element that composition data base model belongs to. */ + uint8_t elem_base; + /** Index of composition data base model in its element. */ + uint8_t idx_base; + /** Element that composition data extension model belongs to. */ + uint8_t elem_ext; + /** Index of composition data extension model in its element. */ + uint8_t idx_ext; + /** Type of relation; value in range 0x00-0xFE marks correspondence + * and equals to Correspondence ID; value 0xFF marks extension + */ + uint8_t type; +}; + +#ifdef CONFIG_BT_MESH_MODEL_EXTENSION_LIST_SIZE +#define MOD_REL_LIST_SIZE CONFIG_BT_MESH_MODEL_EXTENSION_LIST_SIZE +#else +#define MOD_REL_LIST_SIZE 0 +#endif + +/* List of all existing extension relations between models */ +static struct mod_relation mod_rel_list[MOD_REL_LIST_SIZE]; + +#define MOD_REL_LIST_FOR_EACH(idx) \ + for ((idx) = 0; \ + (idx) < MOD_REL_LIST_SIZE && \ + !(mod_rel_list[(idx)].elem_base == 0 && \ + mod_rel_list[(idx)].idx_base == 0 && \ + mod_rel_list[(idx)].elem_ext == 0 && \ + mod_rel_list[(idx)].idx_ext == 0); \ + (idx)++) + +#define IS_MOD_BASE(mod, idx) \ + (mod_rel_list[(idx)].elem_base == (mod)->elem_idx && \ + mod_rel_list[(idx)].idx_base == (mod)->mod_idx && \ + !(mod_rel_list[(idx)].elem_ext != (mod)->elem_idx && \ + mod_rel_list[(idx)].idx_ext != (mod)->mod_idx)) + +#define IS_MOD_EXTENSION(mod, idx) \ + (mod_rel_list[(idx)].elem_ext == (mod)->elem_idx && \ + mod_rel_list[(idx)].idx_ext == (mod)->mod_idx && \ + !(mod_rel_list[(idx)].elem_base != (mod)->elem_idx && \ + mod_rel_list[(idx)].idx_base != (mod)->mod_idx)) + +#define RELATION_TYPE_EXT 0xFF + void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, @@ -414,6 +462,137 @@ int bt_mesh_comp_data_get_page_0(struct net_buf_simple *buf, size_t offset) return 0; } +static uint8_t count_mod_ext(struct bt_mesh_model *mod, uint8_t *max_offset) +{ + int i; + uint8_t extensions = 0; + int8_t offset, offset_record = 0; + + MOD_REL_LIST_FOR_EACH(i) { + if (IS_MOD_EXTENSION(mod, i) && + mod_rel_list[i].type == RELATION_TYPE_EXT) { + extensions++; + offset = mod_rel_list[i].elem_ext - + mod_rel_list[i].elem_base; + if (abs(offset) > abs(offset_record)) { + offset_record = offset; + } + } + } + memcpy(max_offset, &offset_record, sizeof(uint8_t)); + return extensions; +} + +static bool is_cor_present(struct bt_mesh_model *mod, uint8_t *cor_id) +{ + int i; + + MOD_REL_LIST_FOR_EACH(i) { + if ((IS_MOD_BASE(mod, i) || + IS_MOD_EXTENSION(mod, i)) && + mod_rel_list[i].type < RELATION_TYPE_EXT) { + memcpy(cor_id, &mod_rel_list[i].type, sizeof(uint8_t)); + return true; + } + } + return false; +} + +static void prep_model_item_header(struct bt_mesh_model *mod, uint8_t *cor_id, + uint8_t *mod_cnt, struct net_buf_simple *buf) +{ + uint8_t ext_mod_cnt; + bool cor_present; + uint8_t mod_elem_info = 0; + int8_t max_offset; + + ext_mod_cnt = count_mod_ext(mod, &max_offset); + cor_present = is_cor_present(mod, cor_id); + + mod_elem_info = ext_mod_cnt << 2; + if (ext_mod_cnt > 31 || + max_offset > 3 || + max_offset < -4) { + mod_elem_info |= BIT(1); + } + if (cor_present) { + mod_elem_info |= BIT(0); + } + net_buf_simple_add_u8(buf, mod_elem_info); + + if (cor_present) { + net_buf_simple_add_u8(buf, *cor_id); + } + memset(mod_cnt, ext_mod_cnt, sizeof(uint8_t)); +} + +static void add_items_to_page(struct net_buf_simple *buf, struct bt_mesh_model *mod, + uint8_t ext_mod_cnt) +{ + int i, offset; + uint8_t mod_idx; + + MOD_REL_LIST_FOR_EACH(i) { + if (IS_MOD_EXTENSION(mod, i)) { + offset = mod->elem_idx - mod_rel_list[i].elem_base; + mod_idx = mod_rel_list[i].idx_base; + if (ext_mod_cnt < 32 && + offset < 4 && + offset > -5) { + /* short format */ + if (offset < 0) { + offset += 8; + } + + offset |= mod_idx << 3; + net_buf_simple_add_u8(buf, offset); + } else { + /* long format */ + if (offset < 0) { + offset += 256; + } + net_buf_simple_add_u8(buf, offset); + net_buf_simple_add_u8(buf, mod_idx); + } + } + } +} + +int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf) +{ + const struct bt_mesh_comp *comp; + uint8_t cor_id = 0; + uint8_t ext_mod_cnt = 0; + int i, j; + + comp = bt_mesh_comp_get(); + + for (i = 0; i < comp->elem_count; i++) { + net_buf_simple_add_u8(buf, comp->elem[i].model_count); + net_buf_simple_add_u8(buf, comp->elem[i].vnd_model_count); + for (j = 0; j < comp->elem[i].model_count; j++) { + prep_model_item_header(&comp->elem[i].models[j], + &cor_id, &ext_mod_cnt, buf); + if (ext_mod_cnt != 0) { + add_items_to_page(buf, + &comp->elem[i].models[j], + ext_mod_cnt); + } + } + + for (j = 0; j < comp->elem[i].vnd_model_count; j++) { + prep_model_item_header(&comp->elem[i].vnd_models[j], + &cor_id, &ext_mod_cnt, buf); + if (ext_mod_cnt != 0) { + add_items_to_page(buf, + &comp->elem[i].vnd_models[j], + ext_mod_cnt); + } + } + } + return 0; +} + int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) { int32_t period; @@ -718,8 +897,33 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) dev_comp = comp; err = 0; + + if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) { + memset(mod_rel_list, 0, sizeof(mod_rel_list)); + } + bt_mesh_model_foreach(mod_init, &err); + if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) { + int i; + + MOD_REL_LIST_FOR_EACH(i) { + LOG_DBG("registered %s", + mod_rel_list[i].type < RELATION_TYPE_EXT ? + "correspondence" : "extension"); + LOG_DBG("\tbase: elem %u idx %u", + mod_rel_list[i].elem_base, + mod_rel_list[i].idx_base); + LOG_DBG("\text: elem %u idx %u", + mod_rel_list[i].elem_ext, + mod_rel_list[i].idx_ext); + } + if (i < MOD_REL_LIST_SIZE) { + LOG_WRN("Unused space in relation list: %d", + MOD_REL_LIST_SIZE - i); + } + } + return err; } @@ -1224,6 +1428,34 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *model, } #ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS +static int mod_rel_register(struct bt_mesh_model *base, + struct bt_mesh_model *ext, + uint8_t type) +{ + LOG_DBG(""); + struct mod_relation extension = { + base->elem_idx, + base->mod_idx, + ext->elem_idx, + ext->mod_idx, + type, + }; + int i; + + for (i = 0; i < MOD_REL_LIST_SIZE; i++) { + if (mod_rel_list[i].elem_base == 0 && + mod_rel_list[i].idx_base == 0 && + mod_rel_list[i].elem_ext == 0 && + mod_rel_list[i].idx_ext == 0) { + memcpy(&mod_rel_list[i], &extension, + sizeof(extension)); + return 0; + } + } + LOG_ERR("Failed to extend"); + return -ENOMEM; +} + int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod) { struct bt_mesh_model *a = extending_mod; @@ -1258,9 +1490,45 @@ int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_mod a->next = b; } + + if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) { + return mod_rel_register(base_mod, extending_mod, RELATION_TYPE_EXT); + } + return 0; } -#endif + +int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, + struct bt_mesh_model *base_mod) +{ + int i, err; + uint8_t cor_id = 0; + + if (!IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) { + return -ENOTSUP; + } + + MOD_REL_LIST_FOR_EACH(i) { + if (mod_rel_list[i].type < RELATION_TYPE_EXT && + mod_rel_list[i].type > cor_id) { + cor_id = mod_rel_list[i].type; + } + + if ((IS_MOD_BASE(base_mod, i) || + IS_MOD_EXTENSION(base_mod, i) || + IS_MOD_BASE(corresponding_mod, i) || + IS_MOD_EXTENSION(corresponding_mod, i)) && + mod_rel_list[i].type < RELATION_TYPE_EXT) { + return mod_rel_register(base_mod, corresponding_mod, mod_rel_list[i].type); + } + } + err = mod_rel_register(base_mod, corresponding_mod, cor_id); + if (err) { + return err; + } + return 0; +} +#endif /* CONFIG_BT_MESH_MODEL_EXTENSIONS */ bool bt_mesh_model_is_extended(struct bt_mesh_model *model) { diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index c3cc5d07c8e..1718f0d308f 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -26,6 +26,7 @@ size_t bt_mesh_comp_page_0_size(void); int bt_mesh_comp_data_get_page_0(struct net_buf_simple *buf, size_t offset); size_t bt_mesh_metadata_page_0_size(void); int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset); +int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf); /* Find local element based on unicast address */ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index de3a212413b..200d6d93538 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -33,6 +33,12 @@ LOG_MODULE_REGISTER(bt_mesh_cfg_cli); /* 2 byte dummy opcode for getting compile time buffer sizes. */ #define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff) +#define COR_PRESENT(hdr) ((hdr) & BIT(0)) +#define FMT(hdr) ((hdr) & BIT(1)) +#define EXT_ITEM_CNT(hdr) ((hdr) >> 2) +#define OFFSET(item) (item & (uint8_t)BIT_MASK(5)) +#define IDX(item) (item >> 3) + struct comp_data { uint8_t *page; struct net_buf_simple *comp; @@ -949,7 +955,7 @@ done: } const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { - { OP_DEV_COMP_DATA_STATUS, BT_MESH_LEN_MIN(15), comp_data_status }, + { OP_DEV_COMP_DATA_STATUS, BT_MESH_LEN_MIN(5), comp_data_status }, { OP_BEACON_STATUS, BT_MESH_LEN_EXACT(1), beacon_status }, { OP_DEFAULT_TTL_STATUS, BT_MESH_LEN_EXACT(1), ttl_status }, { OP_FRIEND_STATUS, BT_MESH_LEN_EXACT(1), friend_status }, @@ -2205,3 +2211,130 @@ struct bt_mesh_mod_id_vnd bt_mesh_comp_p0_elem_mod_vnd(struct bt_mesh_comp_p0_el return mod; } + +struct bt_mesh_comp_p1_elem *bt_mesh_comp_p1_elem_pull(struct net_buf_simple *buf, + struct bt_mesh_comp_p1_elem *elem) +{ + if (buf->len < 6) { + LOG_ERR("No more elements to pull or missing data"); + return NULL; + } + size_t elem_size = 0; + uint8_t header, ext_item_cnt; + bool fmt, cor_present; + int i; + + elem->nsig = net_buf_simple_pull_u8(buf); + elem->nvnd = net_buf_simple_pull_u8(buf); + for (i = 0; i < elem->nsig + elem->nvnd; i++) { + header = buf->data[elem_size]; + cor_present = COR_PRESENT(header); + fmt = FMT(header); + ext_item_cnt = EXT_ITEM_CNT(header); + + LOG_DBG("header %d, cor_present %d, fmt %d, ext_item_cnt %d", + header, cor_present, fmt, ext_item_cnt); + /* Size of element equals 1 octet (header) + optional 1 octet + * (Correspondence ID, if applies) + size of Extended Model Items + * (each 1 or 2 octet long, depending on format) + */ + elem_size += (1 + cor_present) + (fmt + 1) * ext_item_cnt; + } + + net_buf_simple_init_with_data(elem->_buf, + net_buf_simple_pull_mem(buf, elem_size), + elem_size); + return elem; +} + +struct bt_mesh_comp_p1_model_item *bt_mesh_comp_p1_item_pull( + struct bt_mesh_comp_p1_elem *elem, struct bt_mesh_comp_p1_model_item *item) +{ + if (elem->_buf->len < 1) { + LOG_ERR("Empty buffer"); + return NULL; + } + LOG_DBG("N_SIG %d, N_VND %d, buf len=%d:0x%s", + elem->nsig, elem->nvnd, elem->_buf->len, + bt_hex(elem->_buf->data, elem->_buf->len)); + + size_t item_size; + uint8_t header; + + header = net_buf_simple_pull_u8(elem->_buf); + item->cor_present = COR_PRESENT(header); + item->format = FMT(header); + item->ext_item_cnt = EXT_ITEM_CNT(header); + item_size = item->ext_item_cnt * (item->format + 1); + if (item->cor_present) { + item->cor_id = net_buf_simple_pull_u8(elem->_buf); + } + + net_buf_simple_init_with_data(item->_buf, + net_buf_simple_pull_mem(elem->_buf, item_size), + item_size); + return item; +} + + +static struct bt_mesh_comp_p1_item_short *comp_p1_pull_item_short( + struct bt_mesh_comp_p1_model_item *item, struct bt_mesh_comp_p1_item_short *ext_item) +{ + if (item->_buf->len < 1) { + LOG_ERR("Empty buffer"); + return NULL; + } + + LOG_DBG("Correspondence ID %s, format %s, extended items count=%d", + item->cor_present ? "present" : "not present", + item->format ? "long" : "short", + item->ext_item_cnt); + if (item->format == 1 || item->_buf->len != 1) { + return NULL; + } + uint8_t item_data = net_buf_simple_pull_u8(item->_buf); + + ext_item->elem_offset = OFFSET(item_data); + ext_item->mod_item_idx = IDX(item_data); + return ext_item; +} + +static struct bt_mesh_comp_p1_item_long *comp_p1_pull_item_long( + struct bt_mesh_comp_p1_model_item *item, struct bt_mesh_comp_p1_item_long *ext_item) +{ + if (item->_buf->len < 2) { + LOG_ERR("Missing data, buf len=%d", item->_buf->len); + return NULL; + } + + LOG_DBG("Correspondence ID %s, format %s, extended items count=%d", + item->cor_present ? "present" : "not present", + item->format ? "long" : "short", + item->ext_item_cnt); + if (item->format == 0 || item->_buf->len != 2) { + return NULL; + } + + ext_item->elem_offset = net_buf_simple_pull_u8(item->_buf); + ext_item->mod_item_idx = net_buf_simple_pull_u8(item->_buf); + + return ext_item; +} + +struct bt_mesh_comp_p1_ext_item *bt_mesh_comp_p1_pull_ext_item( + struct bt_mesh_comp_p1_model_item *item, struct bt_mesh_comp_p1_ext_item *ext_item) +{ + if (item->_buf->len < 1) { + LOG_ERR("Empty buffer"); + return NULL; + } else if (item->_buf->len < 2) { + LOG_DBG("Item in short format"); + ext_item->type = SHORT; + comp_p1_pull_item_short(item, &ext_item->short_item); + } else { + LOG_DBG("Item in long format"); + ext_item->type = LONG; + comp_p1_pull_item_long(item, &ext_item->long_item); + } + return ext_item; +} diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 15d4b43d46c..7dbba2e8b58 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -61,17 +61,25 @@ static int dev_comp_data_get(struct bt_mesh_model *model, page = net_buf_simple_pull_u8(buf); if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY)) { - LOG_DBG("Composition data page 128"); page = 128U; + } else if (page >= 1U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) { + page = 1U; } else if (page != 0U) { LOG_DBG("Composition page %u not available", page); page = 0U; } + LOG_DBG("Preparing Composition data page %d", page); bt_mesh_model_msg_init(&sdu, OP_DEV_COMP_DATA_STATUS); net_buf_simple_add_u8(&sdu, page); - if (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) == (page == 0U)) { + if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) && page == 1) { + err = bt_mesh_comp_data_get_page_1(&sdu); + if (err < 0) { + LOG_ERR("Unable to get composition page 1"); + return err; + } + } else 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) {