diff --git a/components/bt/esp_ble_mesh/mesh_core/cfg_srv.c b/components/bt/esp_ble_mesh/mesh_core/cfg_srv.c index a17c3fd93..e02da1d5e 100644 --- a/components/bt/esp_ble_mesh/mesh_core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/mesh_core/cfg_srv.c @@ -47,11 +47,7 @@ static struct bt_mesh_cfg_srv *conf; -static struct label { - u16_t ref; - u16_t addr; - u8_t uuid[16]; -} labels[CONFIG_BLE_MESH_LABEL_COUNT]; +static struct label labels[CONFIG_BLE_MESH_LABEL_COUNT]; static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, bool primary) @@ -1152,25 +1148,61 @@ send_status: } } -#if CONFIG_BLE_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_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; + 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; } @@ -1182,23 +1214,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) { diff --git a/components/bt/esp_ble_mesh/mesh_core/foundation.h b/components/bt/esp_ble_mesh/mesh_core/foundation.h index d1ccd31ae..19bc96dd7 100644 --- a/components/bt/esp_ble_mesh/mesh_core/foundation.h +++ b/components/bt/esp_ble_mesh/mesh_core/foundation.h @@ -117,6 +117,17 @@ #define STATUS_UNSPECIFIED 0x10 #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_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); +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); diff --git a/components/bt/esp_ble_mesh/mesh_core/net.h b/components/bt/esp_ble_mesh/mesh_core/net.h index 200cf7982..47657f495 100644 --- a/components/bt/esp_ble_mesh/mesh_core/net.h +++ b/components/bt/esp_ble_mesh/mesh_core/net.h @@ -224,6 +224,7 @@ enum { BLE_MESH_HB_PUB_PENDING, BLE_MESH_CFG_PENDING, BLE_MESH_MOD_PENDING, + BLE_MESH_VA_PENDING, /* Don't touch - intentionally last */ BLE_MESH_FLAG_COUNT, diff --git a/components/bt/esp_ble_mesh/mesh_core/settings.c b/components/bt/esp_ble_mesh/mesh_core/settings.c index 8705b1c9a..57393b903 100644 --- a/components/bt/esp_ble_mesh/mesh_core/settings.c +++ b/components/bt/esp_ble_mesh/mesh_core/settings.c @@ -55,6 +55,8 @@ * 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/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 @@ -142,6 +144,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. */ @@ -695,6 +704,66 @@ static int vnd_mod_set(const char *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 char *name; int (*func)(const char *name); @@ -709,6 +778,9 @@ const struct bt_mesh_setting { { "mesh/cfg", cfg_set }, { "mesh/sig", sig_mod_set }, { "mesh/vnd", vnd_mod_set }, +#if CONFIG_BLE_MESH_LABEL_COUNT > 0 + { "mesh/vaddr", va_set }, +#endif }; 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) { 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); } } + + 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) @@ -1570,6 +1692,11 @@ void bt_mesh_store_mod_pub(struct bt_mesh_model *model) schedule_store(BLE_MESH_MOD_PENDING); } +void bt_mesh_store_label(void) +{ + schedule_store(BLE_MESH_VA_PENDING); +} + int settings_core_init(void) { BT_DBG("%s", __func__); diff --git a/components/bt/esp_ble_mesh/mesh_core/settings.h b/components/bt/esp_ble_mesh/mesh_core/settings.h index 84b5e182b..3b1c4c696 100644 --- a/components/bt/esp_ble_mesh/mesh_core/settings.h +++ b/components/bt/esp_ble_mesh/mesh_core/settings.h @@ -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_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);