Bluetooth: Mesh: Support for storing model subscriptions persistently

Add support for storing the subscribed group addresses for each model
persistently. The addresses are stored under the settings key
bt/mesh/s/<mod id>/sub for SIG models and bt/mesh/v/<mod id>/sub for
vendor models.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2018-05-09 21:47:01 +03:00 committed by Johan Hedberg
commit dde2db5626
4 changed files with 119 additions and 0 deletions

View file

@ -9,6 +9,7 @@
/* bt_mesh_model.flags */
enum {
BT_MESH_MOD_BIND_PENDING = BIT(0),
BT_MESH_MOD_SUB_PENDING = BIT(1),
};
void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count);

View file

@ -1377,6 +1377,10 @@ static void mod_sub_add(struct bt_mesh_model *model,
} 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);
}
@ -1437,6 +1441,10 @@ static void mod_sub_del(struct bt_mesh_model *model,
match = bt_mesh_model_find_group(mod, sub_addr);
if (match) {
*match = BT_MESH_ADDR_UNASSIGNED;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
}
send_status:
@ -1491,6 +1499,10 @@ static void mod_sub_overwrite(struct bt_mesh_model *model,
mod->groups[0] = 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);
}
@ -1541,6 +1553,10 @@ static void mod_sub_del_all(struct bt_mesh_model *model,
mod_sub_list_clear(mod);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
status = STATUS_SUCCESS;
send_status:
@ -1716,6 +1732,10 @@ static void mod_sub_va_add(struct bt_mesh_model *model,
bt_mesh_lpn_group_add(sub_addr);
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
status = STATUS_SUCCESS;
}
@ -1773,6 +1793,11 @@ static void mod_sub_va_del(struct bt_mesh_model *model,
match = bt_mesh_model_find_group(mod, sub_addr);
if (match) {
*match = BT_MESH_ADDR_UNASSIGNED;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
status = STATUS_SUCCESS;
} else {
status = STATUS_CANNOT_REMOVE;
@ -1828,6 +1853,10 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model,
if (status == STATUS_SUCCESS) {
mod->groups[0] = sub_addr;
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);
}
@ -3135,6 +3164,22 @@ int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary)
return 0;
}
static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
/* Clear model state that isn't otherwise cleared. E.g. AppKey
* binding and model publication is cleared as a consequence
* of removing all app keys, however model subscription clearing
* must be taken care of here.
*/
mod_sub_list_clear(mod);
if (IS_ENABLED(BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
}
void bt_mesh_cfg_reset(void)
{
struct bt_mesh_cfg_srv *cfg = conf;
@ -3161,6 +3206,8 @@ void bt_mesh_cfg_reset(void)
}
}
bt_mesh_model_foreach(mod_reset, NULL);
memset(labels, 0, sizeof(labels));
}

View file

@ -434,6 +434,30 @@ static int mod_set_bind(struct bt_mesh_model *mod, char *val)
return 0;
}
static int mod_set_sub(struct bt_mesh_model *mod, char *val)
{
int len, err;
/* Start with empty array regardless of cleared or set value */
memset(mod->groups, 0, sizeof(mod->groups));
if (!val) {
BT_DBG("Cleared subscriptions for model");
return 0;
}
len = sizeof(mod->groups);
err = settings_bytes_from_str(val, mod->groups, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return -EINVAL;
}
BT_DBG("Decoded %u subscribed group addresses for model",
len / sizeof(mod->groups[0]));
return 0;
}
static int mod_set(bool vnd, int argc, char **argv, char *val)
{
struct bt_mesh_model *mod;
@ -463,6 +487,10 @@ static int mod_set(bool vnd, int argc, char **argv, char *val)
return mod_set_bind(mod, val);
}
if (!strcmp(argv[1], "sub")) {
return mod_set_sub(mod, val);
}
BT_WARN("Unknown module key %s", argv[1]);
return -ENOENT;
}
@ -934,6 +962,37 @@ static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd)
settings_save_one(path, val);
}
static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
{
u16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
char buf[BT_SETTINGS_SIZE(sizeof(groups))];
char path[20];
int i, count;
char *val;
for (i = 0, count = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
groups[count++] = mod->groups[i];
}
}
if (count) {
val = settings_str_from_bytes(groups, count * sizeof(groups[0]),
buf, sizeof(buf));
if (!val) {
BT_ERR("Unable to encode model subscription as value");
return;
}
} else {
val = NULL;
}
encode_mod_path(mod, vnd, "sub", path, sizeof(path));
BT_DBG("Saving %s as %s", path, val ? val : "(null)");
settings_save_one(path, val);
}
static void store_pending_mod(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem, bool vnd,
bool primary, void *user_data)
@ -946,6 +1005,11 @@ static void store_pending_mod(struct bt_mesh_model *mod,
mod->flags &= ~BT_MESH_MOD_BIND_PENDING;
store_pending_mod_bind(mod, vnd);
}
if (mod->flags & BT_MESH_MOD_SUB_PENDING) {
mod->flags &= ~BT_MESH_MOD_SUB_PENDING;
store_pending_mod_sub(mod, vnd);
}
}
static void store_pending(struct k_work *work)
@ -1145,6 +1209,12 @@ void bt_mesh_store_mod_bind(struct bt_mesh_model *mod)
schedule_store(BT_MESH_MOD_PENDING);
}
void bt_mesh_store_mod_sub(struct bt_mesh_model *mod)
{
mod->flags |= BT_MESH_MOD_SUB_PENDING;
schedule_store(BT_MESH_MOD_PENDING);
}
void bt_mesh_settings_init(void)
{
k_delayed_work_init(&pending_store, store_pending);

View file

@ -11,6 +11,7 @@ void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl);
void bt_mesh_store_subnet(struct bt_mesh_subnet *sub);
void bt_mesh_store_app_key(struct bt_mesh_app_key *key);
void bt_mesh_store_mod_bind(struct bt_mesh_model *mod);
void bt_mesh_store_mod_sub(struct bt_mesh_model *mod);
void bt_mesh_clear_net(void);
void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub);