Bluetooth: Mesh: Add Composition Data Page 1

Composition Data Page 1 contains information about relations between
models. Implementation saves relations into array of tuples
{ptr to base, ptr to extension, relation type} on model initialization
and uses this information to construct Composition Data Page 1.

Appropriate structures and methods were added to API, allowing user to
parse all received data into Composition Data Page 1 formats:
Composition Data Page 1 Element, Model Item, Model Extension Item.

Signed-off-by: Krzysztof Kopyściński <krzysztof.kopyscinski@codecoup.pl>
This commit is contained in:
Krzysztof Kopyściński 2022-08-31 11:58:06 +02:00 committed by Carles Cufí
commit 29f07abc89
7 changed files with 548 additions and 4 deletions

View file

@ -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, int bt_mesh_model_extend(struct bt_mesh_model *extending_mod,
struct bt_mesh_model *base_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. /** @brief Check if model is extended by another model.
* *
* @param model The model to check. * @param model The model to check.

View file

@ -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_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 */ /** @cond INTERNAL_HIDDEN */
extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb;

View file

@ -1260,6 +1260,21 @@ config BT_MESH_PRIV_BEACON_CLI
endif # BT_MESH_PRIV_BEACONS 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" menu "Transport SAR configuration"
config BT_MESH_SAR_TX_SEG_INT_STEP config BT_MESH_SAR_TX_SEG_INT_STEP

View file

@ -52,6 +52,54 @@ static const struct bt_mesh_comp *dev_comp;
static uint16_t dev_primary_addr; static uint16_t dev_primary_addr;
static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); 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, void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem, struct bt_mesh_elem *elem,
bool vnd, bool primary, 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; 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 bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
{ {
int32_t period; int32_t period;
@ -718,8 +897,33 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
dev_comp = comp; dev_comp = comp;
err = 0; 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); 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; return err;
} }
@ -1224,6 +1428,34 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *model,
} }
#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS #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) int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod)
{ {
struct bt_mesh_model *a = extending_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; 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; 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) bool bt_mesh_model_is_extended(struct bt_mesh_model *model)
{ {

View file

@ -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); 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); 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_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 */ /* Find local element based on unicast address */
struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr);

View file

@ -33,6 +33,12 @@ LOG_MODULE_REGISTER(bt_mesh_cfg_cli);
/* 2 byte dummy opcode for getting compile time buffer sizes. */ /* 2 byte dummy opcode for getting compile time buffer sizes. */
#define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff) #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 { struct comp_data {
uint8_t *page; uint8_t *page;
struct net_buf_simple *comp; struct net_buf_simple *comp;
@ -949,7 +955,7 @@ done:
} }
const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { 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_BEACON_STATUS, BT_MESH_LEN_EXACT(1), beacon_status },
{ OP_DEFAULT_TTL_STATUS, BT_MESH_LEN_EXACT(1), ttl_status }, { OP_DEFAULT_TTL_STATUS, BT_MESH_LEN_EXACT(1), ttl_status },
{ OP_FRIEND_STATUS, BT_MESH_LEN_EXACT(1), friend_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; 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;
}

View file

@ -61,17 +61,25 @@ static int dev_comp_data_get(struct bt_mesh_model *model,
page = net_buf_simple_pull_u8(buf); page = net_buf_simple_pull_u8(buf);
if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY)) { if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY)) {
LOG_DBG("Composition data page 128");
page = 128U; page = 128U;
} else if (page >= 1U && IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) {
page = 1U;
} else if (page != 0U) { } else if (page != 0U) {
LOG_DBG("Composition page %u not available", page); LOG_DBG("Composition page %u not available", page);
page = 0U; page = 0U;
} }
LOG_DBG("Preparing Composition data page %d", page);
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);
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; sdu.size -= BT_MESH_MIC_SHORT;
err = bt_mesh_comp_read(&sdu); err = bt_mesh_comp_read(&sdu);
if (err) { if (err) {