From 9d849736ef6da918fc8685d6fa79a66d69d866e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 30 Aug 2023 14:16:46 +0200 Subject: [PATCH] Bluetooth: Mesh: Support for comp data page 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for composition data page 2 & 130. In this implementation the responsibillity for filling the page 2 buffer is left to the application through the new comp page 2 cb API. Only the application can know/decide if the device is NLC compliant, and must thus be given the responsibillity for cheking the NLC profile requirements, defined in the NLC specs, and filling the response buffer for comp data page 2. Signed-off-by: Anders Storrø --- include/zephyr/bluetooth/mesh/access.h | 45 ++++++++++++++++++ subsys/bluetooth/mesh/Kconfig | 5 ++ subsys/bluetooth/mesh/access.c | 66 +++++++++++++++++++++++++- subsys/bluetooth/mesh/access.h | 1 - subsys/bluetooth/mesh/cfg_srv.c | 8 +++- 5 files changed, 121 insertions(+), 4 deletions(-) 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) {