diff --git a/subsys/bluetooth/host/mesh/access.h b/subsys/bluetooth/host/mesh/access.h index 38721d64ea1..9d7720ac15d 100644 --- a/subsys/bluetooth/host/mesh/access.h +++ b/subsys/bluetooth/host/mesh/access.h @@ -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); diff --git a/subsys/bluetooth/host/mesh/cfg_srv.c b/subsys/bluetooth/host/mesh/cfg_srv.c index 2f863aa9e76..8d543e06c04 100644 --- a/subsys/bluetooth/host/mesh/cfg_srv.c +++ b/subsys/bluetooth/host/mesh/cfg_srv.c @@ -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)); } diff --git a/subsys/bluetooth/host/mesh/settings.c b/subsys/bluetooth/host/mesh/settings.c index 8f7570e6ba9..6ac7deb76f3 100644 --- a/subsys/bluetooth/host/mesh/settings.c +++ b/subsys/bluetooth/host/mesh/settings.c @@ -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); diff --git a/subsys/bluetooth/host/mesh/settings.h b/subsys/bluetooth/host/mesh/settings.h index e821ffce109..cfb38d1bd68 100644 --- a/subsys/bluetooth/host/mesh/settings.h +++ b/subsys/bluetooth/host/mesh/settings.h @@ -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);