diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index f3b6c373128..5b1653c2487 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -1137,6 +1137,51 @@ struct bt_mesh_comp { struct bt_mesh_elem *elem; /**< List of elements. */ }; +/** Composition data page 2 record. */ +struct bt_mesh_comp2_record { + /** Mesh profile ID. */ + uint16_t id; + /** Mesh Profile Version. */ + struct { + /** Major version. */ + uint8_t x; + /** Minor version. */ + uint8_t y; + /** Z version. */ + uint8_t z; + } version; + /** Element offset count. */ + uint8_t elem_offset_cnt; + /** Element offset list. */ + const uint8_t *elem_offset; + /** Length of additional data. */ + uint16_t data_len; + /** Additional data. */ + const void *data; +}; + +/** Node Composition data page 2 */ +struct bt_mesh_comp2 { + /** The number of Mesh Profile records on a device. */ + size_t record_cnt; + /** List of records. */ + const struct bt_mesh_comp2_record *record; +}; + +/** @brief Register composition data page 2 of the device. + * + * Register Mesh Profiles information (Ref section 3.12 in + * Bluetooth SIG Assigned Numbers) for composition data + * page 2 of the device. + * + * @note There must be at least one record present in @c comp2 + * + * @param comp2 Pointer to composition data page 2. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_mesh_comp2_register(const struct bt_mesh_comp2 *comp2); + #ifdef __cplusplus } #endif diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 945b45c12cc..99012e9646a 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1373,6 +1373,11 @@ config BT_MESH_COMP_PAGE_1 help Enable support for Composition Data Page 1. +config BT_MESH_COMP_PAGE_2 + bool "Support for Composition Data Page 2" + help + Enable support for Composition Data Page 2. + config BT_MESH_MODEL_EXTENSION_LIST_SIZE int "Model extensions list size" depends on BT_MESH_COMP_PAGE_1 diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index c022eedbadc..b6dab2d67a7 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -53,6 +53,7 @@ struct comp_foreach_model_arg { }; static const struct bt_mesh_comp *dev_comp; +static const struct bt_mesh_comp2 *dev_comp2; static uint16_t dev_primary_addr; static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -112,6 +113,9 @@ static const struct { #if IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) { "bt/mesh/cmp/1", 1, }, #endif +#if IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2) + { "bt/mesh/cmp/2", 2, }, +#endif }; void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, @@ -609,7 +613,7 @@ static size_t page1_elem_size(struct bt_mesh_elem *elem) return temp_size; } -int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf) +static int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf) { const struct bt_mesh_comp *comp; uint8_t cor_id = 0; @@ -660,6 +664,51 @@ int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf) return 0; } +static int bt_mesh_comp_data_get_page_2(struct net_buf_simple *buf) +{ + if (!dev_comp2) { + LOG_ERR("Composition data P2 not registered"); + return -ENODEV; + } + + for (int i = 0; i < dev_comp2->record_cnt; i++) { + if (net_buf_simple_tailroom(buf) < + (8 + dev_comp2->record[i].elem_offset_cnt + dev_comp2->record[i].data_len + + BT_MESH_MIC_SHORT)) { + if (IS_ENABLED(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)) { + /* Mesh Profile 1.1 Section 4.4.1.2.2: + * If the complete list of models does not fit in the Data field, + * the element shall not be reported. + */ + LOG_DBG("Record 0x%04x didn't fit in the Data field", + i); + return 0; + } + + LOG_ERR("Too large device composition"); + return -E2BIG; + } + + net_buf_simple_add_le16(buf, dev_comp2->record[i].id); + net_buf_simple_add_u8(buf, dev_comp2->record[i].version.x); + net_buf_simple_add_u8(buf, dev_comp2->record[i].version.y); + net_buf_simple_add_u8(buf, dev_comp2->record[i].version.z); + net_buf_simple_add_u8(buf, dev_comp2->record[i].elem_offset_cnt); + if (dev_comp2->record[i].elem_offset_cnt) { + net_buf_simple_add_mem(buf, dev_comp2->record[i].elem_offset, + dev_comp2->record[i].elem_offset_cnt); + } + + net_buf_simple_add_le16(buf, dev_comp2->record[i].data_len); + if (dev_comp2->record[i].data_len) { + net_buf_simple_add_mem(buf, dev_comp2->record[i].data, + dev_comp2->record[i].data_len); + } + } + + return 0; +} + int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) { int32_t period; @@ -994,6 +1043,17 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) return err; } +int bt_mesh_comp2_register(const struct bt_mesh_comp2 *comp2) +{ + if (!IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2)) { + return -EINVAL; + } + + dev_comp2 = comp2; + + return 0; +} + void bt_mesh_comp_provision(uint16_t addr) { int i; @@ -2151,8 +2211,10 @@ int bt_mesh_comp_data_get_page(struct net_buf_simple *buf, size_t page, size_t o { if (page == 0 || page == 128) { return bt_mesh_comp_data_get_page_0(buf, offset); - } else if (page == 1 || page == 129) { + } else if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) && (page == 1 || page == 129)) { return bt_mesh_comp_data_get_page_1(buf); + } else if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2) && (page == 2 || page == 130)) { + return bt_mesh_comp_data_get_page_2(buf); } return -EINVAL; diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index a7d3ffe5865..4740963dd21 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -27,7 +27,6 @@ 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_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 2fba9360206..eb732a34910 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -61,13 +61,19 @@ static int dev_comp_data_get(struct bt_mesh_model *model, page = net_buf_simple_pull_u8(buf); - if (page >= 129U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) && + if (page >= 130U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2) && + (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) || + IS_ENABLED(CONFIG_BT_MESH_RPR_SRV))) { + page = 130U; + } else if (page >= 129U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) && (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) || IS_ENABLED(CONFIG_BT_MESH_RPR_SRV))) { page = 129U; } else if (page >= 128U && (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) || IS_ENABLED(CONFIG_BT_MESH_RPR_SRV))) { page = 128U; + } else if (page >= 2U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2)) { + page = 2U; } else if (page >= 1U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) { page = 1U; } else if (page != 0U) {