Bluetooth: Mesh: Persistent storage of Virtual Addresses
The 16-bit format group addresses will be stored, but we don't store (or restore) the virtual label UUIDs, i.e. after a power cycle the 16-bit group addresses would be meaningless. Fixes #19342 Signed-off-by: Lingao Meng <mengabc1086@gmail.com>
This commit is contained in:
parent
0f06c7d8e4
commit
101ad56d43
5 changed files with 176 additions and 21 deletions
|
@ -41,11 +41,7 @@
|
|||
|
||||
static struct bt_mesh_cfg_srv *conf;
|
||||
|
||||
static struct label {
|
||||
u16_t ref;
|
||||
u16_t addr;
|
||||
u8_t uuid[16];
|
||||
} labels[CONFIG_BT_MESH_LABEL_COUNT];
|
||||
static struct label labels[CONFIG_BT_MESH_LABEL_COUNT];
|
||||
|
||||
static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem,
|
||||
bool primary)
|
||||
|
@ -1090,25 +1086,61 @@ send_status:
|
|||
status, mod_id);
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
|
||||
struct label *get_label(u16_t index)
|
||||
{
|
||||
struct label *free_slot = NULL;
|
||||
if (index >= ARRAY_SIZE(labels)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &labels[index];
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
static inline void va_store(struct label *store)
|
||||
{
|
||||
atomic_set_bit(store->flags, BT_MESH_VA_CHANGED);
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_label();
|
||||
}
|
||||
}
|
||||
|
||||
static struct label *va_find(const u8_t *label_uuid,
|
||||
struct label **free_slot)
|
||||
{
|
||||
struct label *match = NULL;
|
||||
int i;
|
||||
|
||||
if (free_slot != NULL) {
|
||||
*free_slot = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(labels); i++) {
|
||||
if (!labels[i].ref) {
|
||||
free_slot = &labels[i];
|
||||
if (labels[i].ref == 0) {
|
||||
if (free_slot != NULL) {
|
||||
*free_slot = &labels[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
|
||||
*addr = labels[i].addr;
|
||||
labels[i].ref++;
|
||||
return STATUS_SUCCESS;
|
||||
match = &labels[i];
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
|
||||
{
|
||||
struct label *update, *free_slot = NULL;
|
||||
|
||||
update = va_find(label_uuid, &free_slot);
|
||||
if (update) {
|
||||
update->ref++;
|
||||
va_store(update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
return STATUS_INSUFF_RESOURCES;
|
||||
}
|
||||
|
@ -1120,23 +1152,24 @@ static u8_t va_add(u8_t *label_uuid, u16_t *addr)
|
|||
free_slot->ref = 1U;
|
||||
free_slot->addr = *addr;
|
||||
memcpy(free_slot->uuid, label_uuid, 16);
|
||||
va_store(free_slot);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static u8_t va_del(u8_t *label_uuid, u16_t *addr)
|
||||
{
|
||||
int i;
|
||||
struct label *update;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(labels); i++) {
|
||||
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
|
||||
if (addr) {
|
||||
*addr = labels[i].addr;
|
||||
}
|
||||
update = va_find(label_uuid, NULL);
|
||||
if (update) {
|
||||
update->ref--;
|
||||
|
||||
labels[i].ref--;
|
||||
return STATUS_SUCCESS;
|
||||
if (addr) {
|
||||
*addr = update->addr;
|
||||
}
|
||||
|
||||
va_store(update);
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
|
|
|
@ -112,12 +112,25 @@
|
|||
#define STATUS_UNSPECIFIED 0x10
|
||||
#define STATUS_INVALID_BINDING 0x11
|
||||
|
||||
enum {
|
||||
BT_MESH_VA_CHANGED, /* Label information changed */
|
||||
};
|
||||
|
||||
struct label {
|
||||
u16_t ref;
|
||||
u16_t addr;
|
||||
u8_t uuid[16];
|
||||
atomic_t flags[1];
|
||||
};
|
||||
|
||||
void bt_mesh_cfg_reset(void);
|
||||
|
||||
void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat);
|
||||
|
||||
void bt_mesh_attention(struct bt_mesh_model *model, u8_t time);
|
||||
|
||||
struct label *get_label(u16_t index);
|
||||
|
||||
u8_t *bt_mesh_label_uuid_get(u16_t addr);
|
||||
|
||||
struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void);
|
||||
|
|
|
@ -215,6 +215,7 @@ enum {
|
|||
BT_MESH_HB_PUB_PENDING,
|
||||
BT_MESH_CFG_PENDING,
|
||||
BT_MESH_MOD_PENDING,
|
||||
BT_MESH_VA_PENDING,
|
||||
|
||||
/* Don't touch - intentionally last */
|
||||
BT_MESH_FLAG_COUNT,
|
||||
|
|
|
@ -116,6 +116,13 @@ struct mod_pub_val {
|
|||
cred:1;
|
||||
};
|
||||
|
||||
/* Virtual Address information */
|
||||
struct va_val {
|
||||
u16_t ref;
|
||||
u16_t addr;
|
||||
u8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
/* We need this so we don't overwrite app-hardcoded values in case FCB
|
||||
* contains a history of changes but then has a NULL at the end.
|
||||
*/
|
||||
|
@ -684,6 +691,55 @@ static int vnd_mod_set(const char *name, size_t len_rd,
|
|||
return mod_set(true, name, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
static int va_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct va_val va;
|
||||
struct label *lab;
|
||||
u16_t index;
|
||||
int err;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
index = strtol(name, NULL, 16);
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_WARN("Mesh Virtual Address length = 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = mesh_x_set(read_cb, cb_arg, &va, sizeof(va));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'virtual address\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (va.ref == 0) {
|
||||
BT_WARN("Ignore Mesh Virtual Address ref = 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lab = get_label(index);
|
||||
if (lab == NULL) {
|
||||
BT_WARN("Out of labels buffers");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(lab->uuid, va.uuid, 16);
|
||||
lab->addr = va.addr;
|
||||
lab->ref = va.ref;
|
||||
|
||||
BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x",
|
||||
lab->addr, lab->ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct mesh_setting {
|
||||
const char *name;
|
||||
int (*func)(const char *name, size_t len_rd,
|
||||
|
@ -699,6 +755,9 @@ const struct mesh_setting {
|
|||
{ "Cfg", cfg_set },
|
||||
{ "s", sig_mod_set },
|
||||
{ "v", vnd_mod_set },
|
||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
{ "Va", va_set },
|
||||
#endif
|
||||
};
|
||||
|
||||
static int mesh_set(const char *name, size_t len_rd,
|
||||
|
@ -1354,6 +1413,45 @@ static void store_pending_mod(struct bt_mesh_model *mod,
|
|||
}
|
||||
}
|
||||
|
||||
#define IS_VA_DEL(_label) ((_label)->ref == 0)
|
||||
static void store_pending_va(void)
|
||||
{
|
||||
struct label *lab;
|
||||
struct va_val va;
|
||||
char path[18];
|
||||
u16_t i;
|
||||
int err;
|
||||
|
||||
for (i = 0; (lab = get_label(i)) != NULL; i++) {
|
||||
if (!atomic_test_and_clear_bit(lab->flags,
|
||||
BT_MESH_VA_CHANGED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/Va/%x", i);
|
||||
|
||||
if (IS_VA_DEL(lab)) {
|
||||
err = settings_delete(path);
|
||||
} else {
|
||||
va.ref = lab->ref;
|
||||
va.addr = lab->addr;
|
||||
memcpy(va.uuid, lab->uuid, 16);
|
||||
|
||||
err = settings_save_one(path, &va, sizeof(va));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to %s %s value (err %d)",
|
||||
IS_VA_DEL(lab) ? "delete" : "store",
|
||||
log_strdup(path), err);
|
||||
} else {
|
||||
BT_DBG("%s %s value",
|
||||
IS_VA_DEL(lab) ? "Deleted" : "Stored",
|
||||
log_strdup(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending(struct k_work *work)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
@ -1405,6 +1503,10 @@ static void store_pending(struct k_work *work)
|
|||
if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) {
|
||||
bt_mesh_model_foreach(store_pending_mod, NULL);
|
||||
}
|
||||
|
||||
if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) {
|
||||
store_pending_va();
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
|
||||
|
@ -1586,6 +1688,11 @@ void bt_mesh_store_mod_pub(struct bt_mesh_model *mod)
|
|||
schedule_store(BT_MESH_MOD_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_store_label(void)
|
||||
{
|
||||
schedule_store(BT_MESH_VA_PENDING);
|
||||
}
|
||||
|
||||
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
|
||||
const void *data, size_t data_len)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ void bt_mesh_store_cfg(void);
|
|||
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_store_mod_pub(struct bt_mesh_model *mod);
|
||||
void bt_mesh_store_label(void);
|
||||
|
||||
void bt_mesh_clear_net(void);
|
||||
void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue