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:
parent
51616eacee
commit
4405560483
5 changed files with 196 additions and 21 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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__);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue