Bluetooth: Mesh: Model extension concept
Adds the model extension concept to the access layer, as described in the Mesh Profile Specification, Section 2.3.6. Extensions are implemented as a tree, using two pointers in each model: The extends pointer points to the first extended model, and the next pointer points to the next sibling or (if the NEXT_IS_PARENT flag is set) the parent model in the tree, forming a cyclical "Left-child right-sibling" (LCRS) tree. The tree root can be obtained by calling bt_mesh_model_root_get(), and the extended models can be walked by calling bt_mesh_model_tree_walk(). According to the Mesh Profile Specification Section 4.2.3, all models in the same extension tree share one subscription list per element. This is implemented by walking the model's extension tree, and pooling the subscription lists of all models in the same element into one. If the config server adds a subscription to a model, it may be stored in any of the model tree's models' subscription lists. No two models in the same extension tree and element will have duplicate groups listed. This allows us to increase extended models' capacity for subscriptions significantly. Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no>
This commit is contained in:
parent
0b27cacabd
commit
0151d6dc33
8 changed files with 302 additions and 124 deletions
|
@ -1378,8 +1378,8 @@ static void mod_sub_add(struct bt_mesh_model *model,
|
|||
struct bt_mesh_elem *elem;
|
||||
u8_t *mod_id;
|
||||
u8_t status;
|
||||
u16_t *entry;
|
||||
bool vnd;
|
||||
int i;
|
||||
|
||||
elem_addr = net_buf_simple_pull_le16(buf);
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
|
||||
|
@ -1412,34 +1412,31 @@ static void mod_sub_add(struct bt_mesh_model *model,
|
|||
goto send_status;
|
||||
}
|
||||
|
||||
if (bt_mesh_model_find_group(mod, sub_addr)) {
|
||||
if (bt_mesh_model_find_group(&mod, sub_addr)) {
|
||||
/* Tried to add existing subscription */
|
||||
BT_DBG("found existing subscription");
|
||||
status = STATUS_SUCCESS;
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
|
||||
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
|
||||
mod->groups[i] = sub_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(mod->groups)) {
|
||||
entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED);
|
||||
if (!entry) {
|
||||
status = STATUS_INSUFF_RESOURCES;
|
||||
} else {
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_add(sub_addr);
|
||||
}
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
*entry = sub_addr;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_add(sub_addr);
|
||||
}
|
||||
|
||||
|
||||
send_status:
|
||||
send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
||||
mod_id, vnd);
|
||||
|
@ -1497,7 +1494,7 @@ static void mod_sub_del(struct bt_mesh_model *model,
|
|||
bt_mesh_lpn_group_del(&sub_addr, 1);
|
||||
}
|
||||
|
||||
match = bt_mesh_model_find_group(mod, sub_addr);
|
||||
match = bt_mesh_model_find_group(&mod, sub_addr);
|
||||
if (match) {
|
||||
*match = BT_MESH_ADDR_UNASSIGNED;
|
||||
|
||||
|
@ -1511,6 +1508,18 @@ send_status:
|
|||
mod_id, vnd);
|
||||
}
|
||||
|
||||
static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod,
|
||||
u32_t depth, void *user_data)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
|
||||
}
|
||||
|
||||
mod_sub_list_clear(mod);
|
||||
|
||||
return BT_MESH_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
static void mod_sub_overwrite(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
|
@ -1553,13 +1562,11 @@ static void mod_sub_overwrite(struct bt_mesh_model *model,
|
|||
goto send_status;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
|
||||
}
|
||||
|
||||
mod_sub_list_clear(mod);
|
||||
|
||||
if (ARRAY_SIZE(mod->groups) > 0) {
|
||||
bt_mesh_model_tree_walk(bt_mesh_model_root(mod),
|
||||
mod_sub_clear_visitor, NULL);
|
||||
|
||||
mod->groups[0] = sub_addr;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
|
@ -1615,11 +1622,8 @@ static void mod_sub_del_all(struct bt_mesh_model *model,
|
|||
goto send_status;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
|
||||
}
|
||||
|
||||
mod_sub_list_clear(mod);
|
||||
bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_clear_visitor,
|
||||
NULL);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
|
@ -1632,16 +1636,52 @@ send_status:
|
|||
BT_MESH_ADDR_UNASSIGNED, mod_id, vnd);
|
||||
}
|
||||
|
||||
struct mod_sub_list_ctx {
|
||||
u16_t elem_idx;
|
||||
struct net_buf_simple *msg;
|
||||
};
|
||||
|
||||
static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod,
|
||||
u32_t depth, void *ctx)
|
||||
{
|
||||
struct mod_sub_list_ctx *visit = ctx;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
if (mod->elem_idx != visit->elem_idx) {
|
||||
return BT_MESH_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
|
||||
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (net_buf_simple_tailroom(visit->msg) <
|
||||
2 + BT_MESH_MIC_SHORT) {
|
||||
BT_WARN("No room for all groups");
|
||||
return BT_MESH_WALK_STOP;
|
||||
}
|
||||
|
||||
net_buf_simple_add_le16(visit->msg, mod->groups[i]);
|
||||
count++;
|
||||
}
|
||||
|
||||
BT_DBG("sublist: model %u:%x: %u groups", mod->elem_idx, mod->id,
|
||||
count);
|
||||
|
||||
return BT_MESH_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
static void mod_sub_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_SUB_LIST,
|
||||
5 + CONFIG_BT_MESH_MODEL_GROUP_COUNT * 2);
|
||||
NET_BUF_SIMPLE_DEFINE(msg, BT_MESH_TX_SDU_MAX);
|
||||
struct mod_sub_list_ctx visit_ctx;
|
||||
struct bt_mesh_model *mod;
|
||||
struct bt_mesh_elem *elem;
|
||||
u16_t addr, id;
|
||||
int i;
|
||||
|
||||
addr = net_buf_simple_pull_le16(buf);
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
|
||||
|
@ -1676,11 +1716,10 @@ static void mod_sub_get(struct bt_mesh_model *model,
|
|||
net_buf_simple_add_le16(&msg, addr);
|
||||
net_buf_simple_add_le16(&msg, id);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
|
||||
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
||||
net_buf_simple_add_le16(&msg, mod->groups[i]);
|
||||
}
|
||||
}
|
||||
visit_ctx.msg = &msg;
|
||||
visit_ctx.elem_idx = mod->elem_idx;
|
||||
bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor,
|
||||
&visit_ctx);
|
||||
|
||||
send_list:
|
||||
if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
|
||||
|
@ -1692,12 +1731,10 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model,
|
|||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_SUB_LIST_VND,
|
||||
7 + CONFIG_BT_MESH_MODEL_GROUP_COUNT * 2);
|
||||
NET_BUF_SIMPLE_DEFINE(msg, BT_MESH_TX_SDU_MAX);
|
||||
struct bt_mesh_model *mod;
|
||||
struct bt_mesh_elem *elem;
|
||||
u16_t company, addr, id;
|
||||
int i;
|
||||
|
||||
addr = net_buf_simple_pull_le16(buf);
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
|
||||
|
@ -1736,11 +1773,8 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model,
|
|||
net_buf_simple_add_le16(&msg, company);
|
||||
net_buf_simple_add_le16(&msg, id);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
|
||||
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
||||
net_buf_simple_add_le16(&msg, mod->groups[i]);
|
||||
}
|
||||
}
|
||||
bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor,
|
||||
&msg);
|
||||
|
||||
send_list:
|
||||
if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
|
||||
|
@ -1758,9 +1792,9 @@ static void mod_sub_va_add(struct bt_mesh_model *model,
|
|||
struct bt_mesh_elem *elem;
|
||||
u8_t *label_uuid;
|
||||
u8_t *mod_id;
|
||||
u16_t *entry;
|
||||
u8_t status;
|
||||
bool vnd;
|
||||
int i;
|
||||
|
||||
elem_addr = net_buf_simple_pull_le16(buf);
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
|
||||
|
@ -1794,33 +1828,31 @@ static void mod_sub_va_add(struct bt_mesh_model *model,
|
|||
goto send_status;
|
||||
}
|
||||
|
||||
if (bt_mesh_model_find_group(mod, sub_addr)) {
|
||||
if (bt_mesh_model_find_group(&mod, sub_addr)) {
|
||||
/* Tried to add existing subscription */
|
||||
status = STATUS_SUCCESS;
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
|
||||
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
|
||||
mod->groups[i] = sub_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(mod->groups)) {
|
||||
entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED);
|
||||
if (!entry) {
|
||||
status = STATUS_INSUFF_RESOURCES;
|
||||
} else {
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_add(sub_addr);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
*entry = sub_addr;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_add(sub_addr);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
send_status:
|
||||
send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
||||
mod_id, vnd);
|
||||
|
@ -1876,7 +1908,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model,
|
|||
bt_mesh_lpn_group_del(&sub_addr, 1);
|
||||
}
|
||||
|
||||
match = bt_mesh_model_find_group(mod, sub_addr);
|
||||
match = bt_mesh_model_find_group(&mod, sub_addr);
|
||||
if (match) {
|
||||
*match = BT_MESH_ADDR_UNASSIGNED;
|
||||
|
||||
|
@ -1932,13 +1964,11 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model,
|
|||
goto send_status;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
|
||||
}
|
||||
|
||||
mod_sub_list_clear(mod);
|
||||
|
||||
if (ARRAY_SIZE(mod->groups) > 0) {
|
||||
bt_mesh_model_tree_walk(bt_mesh_model_root(mod),
|
||||
mod_sub_clear_visitor, NULL);
|
||||
|
||||
status = va_add(label_uuid, &sub_addr);
|
||||
if (status == STATUS_SUCCESS) {
|
||||
mod->groups[0] = sub_addr;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue