Bluetooth: Mesh: Add missing comp pages to LCD mod
Adds support for all composition data pages to the Large Composition Data model. Signed-off-by: Anders Storrø <anders.storro@nordicsemi.no>
This commit is contained in:
parent
0eb027ab7c
commit
57cb1b1ccb
4 changed files with 199 additions and 94 deletions
|
@ -1375,6 +1375,16 @@ config BT_MESH_PRIV_BEACON_CLI
|
|||
|
||||
endif # BT_MESH_PRIV_BEACONS
|
||||
|
||||
config BT_MESH_COMP_PST_BUF_SIZE
|
||||
int "Composition Data Page persistence buffer size"
|
||||
default 100
|
||||
help
|
||||
Stack allocated buffer used to temporarily hold Composition
|
||||
Data Pages during flash operations. Should reflect the size
|
||||
of the largest Composition Data Page present in the application.
|
||||
Note that this buffer should still be large enough to restore previously stored
|
||||
pages after a performed device firmware update.
|
||||
|
||||
config BT_MESH_COMP_PAGE_1
|
||||
bool "Support for Composition Data Page 1"
|
||||
depends on BT_MESH_MODEL_EXTENSIONS
|
||||
|
|
|
@ -173,6 +173,18 @@ static void data_buf_add_le16_offset(struct net_buf_simple *buf,
|
|||
}
|
||||
}
|
||||
|
||||
static void data_buf_add_mem_offset(struct net_buf_simple *buf, uint8_t *data, size_t len,
|
||||
size_t *offset)
|
||||
{
|
||||
if (*offset >= len) {
|
||||
*offset -= len;
|
||||
return;
|
||||
}
|
||||
|
||||
net_buf_simple_add_mem(buf, data + *offset, len - *offset);
|
||||
*offset = 0;
|
||||
}
|
||||
|
||||
static void comp_add_model(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
||||
bool vnd, void *user_data)
|
||||
{
|
||||
|
@ -187,20 +199,6 @@ static void comp_add_model(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
if (*offset >= len) {
|
||||
*offset -= len;
|
||||
return;
|
||||
} else if (*offset > 0) {
|
||||
net_buf_simple_add_mem(buf, ((uint8_t *)mem), (len - *offset));
|
||||
|
||||
} else {
|
||||
net_buf_simple_add_mem(buf, mem, len);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t metadata_model_size(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_elem *elem, bool vnd)
|
||||
|
@ -366,23 +364,6 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset)
|
|||
}
|
||||
#endif
|
||||
|
||||
size_t bt_mesh_comp_page_0_size(void)
|
||||
{
|
||||
const struct bt_mesh_comp *comp;
|
||||
const struct bt_mesh_elem *elem;
|
||||
size_t size = 10;
|
||||
int i;
|
||||
|
||||
comp = bt_mesh_comp_get();
|
||||
|
||||
for (i = 0; i < comp->elem_count; i++) {
|
||||
elem = &comp->elem[i];
|
||||
size += bt_mesh_comp_elem_size(elem);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem,
|
||||
size_t *offset)
|
||||
{
|
||||
|
@ -398,7 +379,7 @@ static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (net_buf_simple_tailroom(buf) < (elem_size + BT_MESH_MIC_SHORT)) {
|
||||
if (net_buf_simple_tailroom(buf) < ((elem_size - *offset) + 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,
|
||||
|
@ -516,8 +497,8 @@ static bool is_cor_present(struct bt_mesh_model *mod, uint8_t *cor_id)
|
|||
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)
|
||||
static void prep_model_item_header(struct bt_mesh_model *mod, uint8_t *cor_id, uint8_t *mod_cnt,
|
||||
struct net_buf_simple *buf, size_t *offset)
|
||||
{
|
||||
uint8_t ext_mod_cnt;
|
||||
bool cor_present;
|
||||
|
@ -536,41 +517,41 @@ static void prep_model_item_header(struct bt_mesh_model *mod, uint8_t *cor_id,
|
|||
if (cor_present) {
|
||||
mod_elem_info |= BIT(0);
|
||||
}
|
||||
net_buf_simple_add_u8(buf, mod_elem_info);
|
||||
data_buf_add_u8_offset(buf, mod_elem_info, offset);
|
||||
|
||||
if (cor_present) {
|
||||
net_buf_simple_add_u8(buf, *cor_id);
|
||||
data_buf_add_u8_offset(buf, *cor_id, offset);
|
||||
}
|
||||
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)
|
||||
uint8_t ext_mod_cnt, size_t *offset)
|
||||
{
|
||||
int i, offset;
|
||||
int i, elem_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;
|
||||
elem_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) {
|
||||
elem_offset < 4 &&
|
||||
elem_offset > -5) {
|
||||
/* short format */
|
||||
if (offset < 0) {
|
||||
offset += 8;
|
||||
if (elem_offset < 0) {
|
||||
elem_offset += 8;
|
||||
}
|
||||
|
||||
offset |= mod_idx << 3;
|
||||
net_buf_simple_add_u8(buf, offset);
|
||||
elem_offset |= mod_idx << 3;
|
||||
data_buf_add_u8_offset(buf, elem_offset, offset);
|
||||
} else {
|
||||
/* long format */
|
||||
if (offset < 0) {
|
||||
offset += 256;
|
||||
if (elem_offset < 0) {
|
||||
elem_offset += 256;
|
||||
}
|
||||
net_buf_simple_add_u8(buf, offset);
|
||||
net_buf_simple_add_u8(buf, mod_idx);
|
||||
data_buf_add_u8_offset(buf, elem_offset, offset);
|
||||
data_buf_add_u8_offset(buf, mod_idx, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -613,7 +594,7 @@ static size_t page1_elem_size(struct bt_mesh_elem *elem)
|
|||
return temp_size;
|
||||
}
|
||||
|
||||
static 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, size_t offset)
|
||||
{
|
||||
const struct bt_mesh_comp *comp;
|
||||
uint8_t cor_id = 0;
|
||||
|
@ -623,8 +604,14 @@ static int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf)
|
|||
comp = bt_mesh_comp_get();
|
||||
|
||||
for (i = 0; i < comp->elem_count; i++) {
|
||||
if (net_buf_simple_tailroom(buf) <
|
||||
(page1_elem_size(&comp->elem[i]) + BT_MESH_MIC_SHORT)) {
|
||||
size_t elem_size = page1_elem_size(&comp->elem[i]);
|
||||
|
||||
if (offset >= elem_size) {
|
||||
offset -= elem_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (net_buf_simple_tailroom(buf) < ((elem_size - offset) + 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,
|
||||
|
@ -639,49 +626,53 @@ static int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf)
|
|||
return -E2BIG;
|
||||
}
|
||||
|
||||
net_buf_simple_add_u8(buf, comp->elem[i].model_count);
|
||||
net_buf_simple_add_u8(buf, comp->elem[i].vnd_model_count);
|
||||
data_buf_add_u8_offset(buf, comp->elem[i].model_count, &offset);
|
||||
data_buf_add_u8_offset(buf, comp->elem[i].vnd_model_count, &offset);
|
||||
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);
|
||||
prep_model_item_header(&comp->elem[i].models[j], &cor_id, &ext_mod_cnt, buf,
|
||||
&offset);
|
||||
if (ext_mod_cnt != 0) {
|
||||
add_items_to_page(buf,
|
||||
&comp->elem[i].models[j],
|
||||
ext_mod_cnt);
|
||||
add_items_to_page(buf, &comp->elem[i].models[j], ext_mod_cnt,
|
||||
&offset);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
prep_model_item_header(&comp->elem[i].vnd_models[j], &cor_id, &ext_mod_cnt,
|
||||
buf, &offset);
|
||||
if (ext_mod_cnt != 0) {
|
||||
add_items_to_page(buf,
|
||||
&comp->elem[i].vnd_models[j],
|
||||
ext_mod_cnt);
|
||||
add_items_to_page(buf, &comp->elem[i].vnd_models[j], ext_mod_cnt,
|
||||
&offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt_mesh_comp_data_get_page_2(struct net_buf_simple *buf)
|
||||
static int bt_mesh_comp_data_get_page_2(struct net_buf_simple *buf, size_t offset)
|
||||
{
|
||||
if (!dev_comp2) {
|
||||
LOG_ERR("Composition data P2 not registered");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
size_t elem_size;
|
||||
|
||||
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)) {
|
||||
elem_size =
|
||||
8 + dev_comp2->record[i].elem_offset_cnt + dev_comp2->record[i].data_len;
|
||||
if (offset >= elem_size) {
|
||||
offset -= elem_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (net_buf_simple_tailroom(buf) < ((elem_size - offset) + 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);
|
||||
LOG_DBG("Record 0x%04x didn't fit in the Data field", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -689,20 +680,20 @@ static int bt_mesh_comp_data_get_page_2(struct net_buf_simple *buf)
|
|||
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);
|
||||
data_buf_add_le16_offset(buf, dev_comp2->record[i].id, &offset);
|
||||
data_buf_add_u8_offset(buf, dev_comp2->record[i].version.x, &offset);
|
||||
data_buf_add_u8_offset(buf, dev_comp2->record[i].version.y, &offset);
|
||||
data_buf_add_u8_offset(buf, dev_comp2->record[i].version.z, &offset);
|
||||
data_buf_add_u8_offset(buf, dev_comp2->record[i].elem_offset_cnt, &offset);
|
||||
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);
|
||||
data_buf_add_mem_offset(buf, (uint8_t *)dev_comp2->record[i].elem_offset,
|
||||
dev_comp2->record[i].elem_offset_cnt, &offset);
|
||||
}
|
||||
|
||||
net_buf_simple_add_le16(buf, dev_comp2->record[i].data_len);
|
||||
data_buf_add_le16_offset(buf, dev_comp2->record[i].data_len, &offset);
|
||||
if (dev_comp2->record[i].data_len) {
|
||||
net_buf_simple_add_mem(buf, dev_comp2->record[i].data,
|
||||
dev_comp2->record[i].data_len);
|
||||
data_buf_add_mem_offset(buf, (uint8_t *)dev_comp2->record[i].data,
|
||||
dev_comp2->record[i].data_len, &offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2212,20 +2203,89 @@ 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 (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) && (page == 1 || page == 129)) {
|
||||
return bt_mesh_comp_data_get_page_1(buf);
|
||||
return bt_mesh_comp_data_get_page_1(buf, offset);
|
||||
} else if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2) && (page == 2 || page == 130)) {
|
||||
return bt_mesh_comp_data_get_page_2(buf);
|
||||
return bt_mesh_comp_data_get_page_2(buf, offset);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_t comp_page_0_size(void)
|
||||
{
|
||||
const struct bt_mesh_comp *comp;
|
||||
const struct bt_mesh_elem *elem;
|
||||
size_t size = 10; /* Non-variable length params of comp page 0. */
|
||||
|
||||
comp = bt_mesh_comp_get();
|
||||
|
||||
for (int i = 0; i < comp->elem_count; i++) {
|
||||
elem = &comp->elem[i];
|
||||
size += bt_mesh_comp_elem_size(elem);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t comp_page_1_size(void)
|
||||
{
|
||||
const struct bt_mesh_comp *comp;
|
||||
size_t size = 0;
|
||||
|
||||
comp = bt_mesh_comp_get();
|
||||
|
||||
for (int i = 0; i < comp->elem_count; i++) {
|
||||
|
||||
size += page1_elem_size(&comp->elem[i]);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t comp_page_2_size(void)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
if (!dev_comp2) {
|
||||
LOG_ERR("Composition data P2 not registered");
|
||||
return size;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dev_comp2->record_cnt; i++) {
|
||||
size += 8 + dev_comp2->record[i].elem_offset_cnt + dev_comp2->record[i].data_len;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t bt_mesh_comp_page_size(uint8_t page)
|
||||
{
|
||||
if (page == 0 || page == 128) {
|
||||
return comp_page_0_size();
|
||||
} else if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1) && (page == 1 || page == 129)) {
|
||||
return comp_page_1_size();
|
||||
} else if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_2) && (page == 2 || page == 130)) {
|
||||
return comp_page_2_size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_mesh_comp_store(void)
|
||||
{
|
||||
NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX);
|
||||
#if IS_ENABLED(CONFIG_BT_MESH_V1d1)
|
||||
NET_BUF_SIMPLE_DEFINE(buf, CONFIG_BT_MESH_COMP_PST_BUF_SIZE);
|
||||
int err;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(comp_data_pages); i++) {
|
||||
size_t page_size = bt_mesh_comp_page_size(i);
|
||||
|
||||
if (page_size > CONFIG_BT_MESH_COMP_PST_BUF_SIZE) {
|
||||
LOG_WRN("CDP%d is larger than the CDP persistence buffer. "
|
||||
"Please increase the CDP persistence buffer size "
|
||||
"to the required size (%d bytes)",
|
||||
i, page_size);
|
||||
}
|
||||
|
||||
net_buf_simple_reset(&buf);
|
||||
|
||||
err = bt_mesh_comp_data_get_page(&buf, comp_data_pages[i].page, 0);
|
||||
|
@ -2242,7 +2302,7 @@ int bt_mesh_comp_store(void)
|
|||
|
||||
LOG_DBG("Stored CDP%d", comp_data_pages[i].page);
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ enum {
|
|||
void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count);
|
||||
|
||||
uint8_t bt_mesh_elem_count(void);
|
||||
size_t bt_mesh_comp_page_0_size(void);
|
||||
size_t bt_mesh_comp_page_size(uint8_t page);
|
||||
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);
|
||||
|
|
|
@ -59,24 +59,59 @@ static int handle_large_comp_data_get(struct bt_mesh_model *model, struct bt_mes
|
|||
LOG_DBG("page %u offset %u", page, offset);
|
||||
|
||||
bt_mesh_model_msg_init(&rsp, OP_LARGE_COMP_DATA_STATUS);
|
||||
|
||||
if (page != 0U) {
|
||||
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) {
|
||||
LOG_DBG("Composition page %u not available", page);
|
||||
page = 0U;
|
||||
}
|
||||
|
||||
net_buf_simple_add_u8(&rsp, page);
|
||||
|
||||
total_size = bt_mesh_comp_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_comp_data_get_page_0(&rsp, offset);
|
||||
if (err && err != -E2BIG) {
|
||||
LOG_ERR("comp_get_page_0 returned error");
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) && page < 128) {
|
||||
size_t msg_space;
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE(temp_buf, CONFIG_BT_MESH_COMP_PST_BUF_SIZE);
|
||||
err = bt_mesh_comp_read(&temp_buf, page);
|
||||
if (err) {
|
||||
LOG_ERR("Could not read comp data p%d, err: %d", page, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
net_buf_simple_add_le16(&rsp, temp_buf.len);
|
||||
if (offset > temp_buf.len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg_space = net_buf_simple_tailroom(&rsp) - BT_MESH_MIC_SHORT;
|
||||
net_buf_simple_add_mem(
|
||||
&rsp, temp_buf.data + offset,
|
||||
(msg_space < (temp_buf.len - offset)) ? msg_space : temp_buf.len - offset);
|
||||
} else {
|
||||
total_size = bt_mesh_comp_page_size(page);
|
||||
net_buf_simple_add_le16(&rsp, total_size);
|
||||
|
||||
if (offset < total_size) {
|
||||
err = bt_mesh_comp_data_get_page(&rsp, page, offset);
|
||||
if (err && err != -E2BIG) {
|
||||
LOG_ERR("Could not read comp data p%d, err: %d", page, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue