ble_mesh: Persistent storage of Virtual Address

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.
This commit is contained in:
lly 2019-11-04 20:04:52 +08:00
parent 51616eacee
commit 4405560483
5 changed files with 196 additions and 21 deletions

View file

@ -47,11 +47,7 @@
static struct bt_mesh_cfg_srv *conf; static struct bt_mesh_cfg_srv *conf;
static struct label { static struct label labels[CONFIG_BLE_MESH_LABEL_COUNT];
u16_t ref;
u16_t addr;
u8_t uuid[16];
} labels[CONFIG_BLE_MESH_LABEL_COUNT];
static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem,
bool primary) bool primary)
@ -1152,25 +1148,61 @@ send_status:
} }
} }
#if CONFIG_BLE_MESH_LABEL_COUNT > 0 struct label *get_label(u16_t index)
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
{ {
struct label *free_slot = NULL; if (index >= ARRAY_SIZE(labels)) {
return NULL;
}
return &labels[index];
}
#if CONFIG_BLE_MESH_LABEL_COUNT > 0
static inline void va_store(struct label *store)
{
bt_mesh_atomic_set_bit(store->flags, BLE_MESH_VA_CHANGED);
if (IS_ENABLED(CONFIG_BLE_MESH_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; int i;
if (free_slot != NULL) {
*free_slot = NULL;
}
for (i = 0; i < ARRAY_SIZE(labels); i++) { for (i = 0; i < ARRAY_SIZE(labels); i++) {
if (!labels[i].ref) { if (labels[i].ref == 0) {
free_slot = &labels[i]; if (free_slot != NULL) {
*free_slot = &labels[i];
}
continue; continue;
} }
if (!memcmp(labels[i].uuid, label_uuid, 16)) { if (!memcmp(labels[i].uuid, label_uuid, 16)) {
*addr = labels[i].addr; match = &labels[i];
labels[i].ref++;
return STATUS_SUCCESS;
} }
} }
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) { if (!free_slot) {
return STATUS_INSUFF_RESOURCES; return STATUS_INSUFF_RESOURCES;
} }
@ -1182,23 +1214,24 @@ static u8_t va_add(u8_t *label_uuid, u16_t *addr)
free_slot->ref = 1U; free_slot->ref = 1U;
free_slot->addr = *addr; free_slot->addr = *addr;
memcpy(free_slot->uuid, label_uuid, 16); memcpy(free_slot->uuid, label_uuid, 16);
va_store(free_slot);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static u8_t va_del(u8_t *label_uuid, u16_t *addr) static u8_t va_del(u8_t *label_uuid, u16_t *addr)
{ {
int i; struct label *update;
update = va_find(label_uuid, NULL);
if (update) {
update->ref--;
for (i = 0; i < ARRAY_SIZE(labels); i++) {
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
if (addr) { if (addr) {
*addr = labels[i].addr; *addr = update->addr;
} }
labels[i].ref--; va_store(update);
return STATUS_SUCCESS;
}
} }
if (addr) { if (addr) {

View file

@ -117,6 +117,17 @@
#define STATUS_UNSPECIFIED 0x10 #define STATUS_UNSPECIFIED 0x10
#define STATUS_INVALID_BINDING 0x11 #define STATUS_INVALID_BINDING 0x11
enum {
BLE_MESH_VA_CHANGED, /* Label information changed */
};
struct label {
u16_t ref;
u16_t addr;
u8_t uuid[16];
bt_mesh_atomic_t flags[1];
};
int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary); int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary);
int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary); int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary);
@ -129,6 +140,8 @@ 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); 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); u8_t *bt_mesh_label_uuid_get(u16_t addr);
struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void); struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void);

View file

@ -224,6 +224,7 @@ enum {
BLE_MESH_HB_PUB_PENDING, BLE_MESH_HB_PUB_PENDING,
BLE_MESH_CFG_PENDING, BLE_MESH_CFG_PENDING,
BLE_MESH_MOD_PENDING, BLE_MESH_MOD_PENDING,
BLE_MESH_VA_PENDING,
/* Don't touch - intentionally last */ /* Don't touch - intentionally last */
BLE_MESH_FLAG_COUNT, BLE_MESH_FLAG_COUNT,

View file

@ -55,6 +55,8 @@
* key: "mesh/v/xxxx/b" -> write/read to set/get VENDOR MODEL Bind AppKey List * key: "mesh/v/xxxx/b" -> write/read to set/get VENDOR MODEL Bind AppKey List
* key: "mesh/v/xxxx/s" -> write/read to set/get VENDOR MODEL Subscription List * key: "mesh/v/xxxx/s" -> write/read to set/get VENDOR MODEL Subscription List
* key: "mesh/v/xxxx/p" -> write/read to set/get VENDOR MODEL Publication * key: "mesh/v/xxxx/p" -> write/read to set/get VENDOR MODEL Publication
* key: "mesh/vaddr" -> write/read to set/get all virtual addresses
* key: "mesh/va/xxxx" -> write/read to set/get the "xxxx" virtual address
*/ */
#if CONFIG_BLE_MESH_SETTINGS #if CONFIG_BLE_MESH_SETTINGS
@ -142,6 +144,13 @@ struct mod_pub_val {
cred: 1; 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 /* 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. * contains a history of changes but then has a NULL at the end.
*/ */
@ -695,6 +704,66 @@ static int vnd_mod_set(const char *name)
return model_set(true, name); return model_set(true, name);
} }
#if CONFIG_BLE_MESH_LABEL_COUNT > 0
static int va_set(const char *name)
{
struct net_buf_simple *buf = NULL;
struct va_val va = {0};
char get[16] = {'\0'};
struct label *lab;
size_t length;
bool exist;
int err = 0;
u16_t i;
BT_DBG("%s", __func__);
buf = bt_mesh_get_core_settings_item(name);
if (!buf) {
return 0;
}
length = buf->len;
for (i = 0U; i < length / SETTINGS_ITEM_SIZE; i++) {
u16_t index = net_buf_simple_pull_le16(buf);
sprintf(get, "mesh/va/%04x", index);
err = bt_mesh_load_core_settings(get, (u8_t *)&va, sizeof(va), &exist);
if (err) {
BT_ERR("%s, Failed to load virtual address %s", __func__, get);
goto free;
}
if (exist == false) {
continue;
}
if (va.ref == 0) {
BT_DBG("Ignore virtual address %s with ref = 0", get);
goto free;
}
lab = get_label(index);
if (lab == NULL) {
BT_WARN("%s, Out of labels buffers", __func__);
err = -ENOBUFS;
goto free;
}
memcpy(lab->uuid, va.uuid, 16);
lab->addr = va.addr;
lab->ref = va.ref;
BT_DBG("Restore virtual address 0x%04x ref 0x%04x", index, lab->ref);
}
free:
bt_mesh_free_buf(buf);
return err;
}
#endif
const struct bt_mesh_setting { const struct bt_mesh_setting {
const char *name; const char *name;
int (*func)(const char *name); int (*func)(const char *name);
@ -709,6 +778,9 @@ const struct bt_mesh_setting {
{ "mesh/cfg", cfg_set }, { "mesh/cfg", cfg_set },
{ "mesh/sig", sig_mod_set }, { "mesh/sig", sig_mod_set },
{ "mesh/vnd", vnd_mod_set }, { "mesh/vnd", vnd_mod_set },
#if CONFIG_BLE_MESH_LABEL_COUNT > 0
{ "mesh/vaddr", va_set },
#endif
}; };
int settings_core_load(void) int settings_core_load(void)
@ -1331,6 +1403,52 @@ static void store_pending_mod(struct bt_mesh_model *model,
} }
} }
#define IS_VA_DEL(_label) ((_label)->ref == 0)
static void store_pending_va(void)
{
struct va_val va = {0};
char name[16] = {'\0'};
struct label *lab;
u16_t i;
int err;
for (i = 0U; (lab = get_label(i)) != NULL; i++) {
if (!bt_mesh_atomic_test_and_clear_bit(lab->flags,
BLE_MESH_VA_CHANGED)) {
continue;
}
sprintf(name, "mesh/va/%04x", i);
if (IS_VA_DEL(lab)) {
err = bt_mesh_save_core_settings(name, NULL, 0);
} else {
va.ref = lab->ref;
va.addr = lab->addr;
memcpy(va.uuid, lab->uuid, 16);
err = bt_mesh_save_core_settings(name, (const u8_t *)&va, sizeof(va));
}
if (err) {
BT_ERR("%s, Failed to %s virtual address %s", __func__,
IS_VA_DEL(lab) ? "delete" : "store", name);
return;
}
if (IS_VA_DEL(lab)) {
err = bt_mesh_remove_core_settings_item("mesh/vaddr", i);
} else {
err = bt_mesh_add_core_settings_item("mesh/vaddr", i);
}
if (err) {
BT_ERR("%s, Failed to %s 0x%04x in mesh/vaddr", __func__,
IS_VA_DEL(lab) ? "delete" : "store", i);
return;
}
BT_DBG("%s virtual address 0x%04x", IS_VA_DEL(lab) ? "Delete" : "Store", i);
}
}
static void store_pending(struct k_work *work) static void store_pending(struct k_work *work)
{ {
BT_DBG("%s", __func__); BT_DBG("%s", __func__);
@ -1386,6 +1504,10 @@ static void store_pending(struct k_work *work)
bt_mesh_save_core_settings("mesh/vnd", NULL, 0); bt_mesh_save_core_settings("mesh/vnd", NULL, 0);
} }
} }
if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_VA_PENDING)) {
store_pending_va();
}
} }
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
@ -1570,6 +1692,11 @@ void bt_mesh_store_mod_pub(struct bt_mesh_model *model)
schedule_store(BLE_MESH_MOD_PENDING); schedule_store(BLE_MESH_MOD_PENDING);
} }
void bt_mesh_store_label(void)
{
schedule_store(BLE_MESH_VA_PENDING);
}
int settings_core_init(void) int settings_core_init(void)
{ {
BT_DBG("%s", __func__); BT_DBG("%s", __func__);

View file

@ -28,6 +28,7 @@ void bt_mesh_store_cfg(void);
void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); 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_sub(struct bt_mesh_model *mod);
void bt_mesh_store_mod_pub(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_net(void);
void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub);