2017-06-16 12:30:54 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
includes: prefer <zephyr/kernel.h> over <zephyr/zephyr.h>
As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>.
This patch proposes to then include <zephyr/kernel.h> instead of
<zephyr/zephyr.h> since it is more clear that you are including the
Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a
catch-all header that may be confusing. Most applications need to
include a bunch of other things to compile, e.g. driver headers or
subsystem headers like BT, logging, etc.
The idea of a catch-all header in Zephyr is probably not feasible
anyway. Reason is that Zephyr is not a library, like it could be for
example `libpython`. Zephyr provides many utilities nowadays: a kernel,
drivers, subsystems, etc and things will likely grow. A catch-all header
would be massive, difficult to keep up-to-date. It is also likely that
an application will only build a small subset. Note that subsystem-level
headers may use a catch-all approach to make things easier, though.
NOTE: This patch is **NOT** removing the header, just removing its usage
in-tree. I'd advocate for its deprecation (add a #warning on it), but I
understand many people will have concerns.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-08-25 09:58:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2017-06-16 12:30:54 +03:00
|
|
|
#include <errno.h>
|
2021-01-06 09:56:56 +01:00
|
|
|
#include <stdlib.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/util.h>
|
|
|
|
#include <zephyr/sys/byteorder.h>
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/net/buf.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
|
|
#include <zephyr/bluetooth/mesh.h>
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-10-25 08:48:54 +02:00
|
|
|
#include "common/bt_str.h"
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-11-16 12:01:05 +01:00
|
|
|
#include "host/testing.h"
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
#include "mesh.h"
|
|
|
|
#include "adv.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "lpn.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "access.h"
|
|
|
|
#include "foundation.h"
|
2021-02-18 14:09:18 +01:00
|
|
|
#include "op_agg.h"
|
2021-01-06 09:56:56 +01:00
|
|
|
#include "settings.h"
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
#define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(bt_mesh_access);
|
|
|
|
|
2021-01-06 09:56:56 +01:00
|
|
|
/* Model publication information for persistent storage. */
|
|
|
|
struct mod_pub_val {
|
|
|
|
uint16_t addr;
|
|
|
|
uint16_t key;
|
|
|
|
uint8_t ttl;
|
|
|
|
uint8_t retransmit;
|
|
|
|
uint8_t period;
|
|
|
|
uint8_t period_div:4,
|
|
|
|
cred:1;
|
|
|
|
};
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-02-03 15:32:52 +01:00
|
|
|
struct comp_foreach_model_arg {
|
|
|
|
struct net_buf_simple *buf;
|
|
|
|
size_t *offset;
|
|
|
|
};
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
static const struct bt_mesh_comp *dev_comp;
|
2020-05-27 11:26:57 -05:00
|
|
|
static uint16_t dev_primary_addr;
|
2021-05-29 13:18:10 -06:00
|
|
|
static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-08-31 11:58:06 +02:00
|
|
|
/* Structure containing information about model extension */
|
|
|
|
struct mod_relation {
|
|
|
|
/** Element that composition data base model belongs to. */
|
|
|
|
uint8_t elem_base;
|
|
|
|
/** Index of composition data base model in its element. */
|
|
|
|
uint8_t idx_base;
|
|
|
|
/** Element that composition data extension model belongs to. */
|
|
|
|
uint8_t elem_ext;
|
|
|
|
/** Index of composition data extension model in its element. */
|
|
|
|
uint8_t idx_ext;
|
|
|
|
/** Type of relation; value in range 0x00-0xFE marks correspondence
|
|
|
|
* and equals to Correspondence ID; value 0xFF marks extension
|
|
|
|
*/
|
|
|
|
uint8_t type;
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CONFIG_BT_MESH_MODEL_EXTENSION_LIST_SIZE
|
|
|
|
#define MOD_REL_LIST_SIZE CONFIG_BT_MESH_MODEL_EXTENSION_LIST_SIZE
|
|
|
|
#else
|
|
|
|
#define MOD_REL_LIST_SIZE 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* List of all existing extension relations between models */
|
|
|
|
static struct mod_relation mod_rel_list[MOD_REL_LIST_SIZE];
|
|
|
|
|
|
|
|
#define MOD_REL_LIST_FOR_EACH(idx) \
|
|
|
|
for ((idx) = 0; \
|
2023-03-09 13:53:34 +01:00
|
|
|
(idx) < ARRAY_SIZE(mod_rel_list) && \
|
2022-08-31 11:58:06 +02:00
|
|
|
!(mod_rel_list[(idx)].elem_base == 0 && \
|
|
|
|
mod_rel_list[(idx)].idx_base == 0 && \
|
|
|
|
mod_rel_list[(idx)].elem_ext == 0 && \
|
|
|
|
mod_rel_list[(idx)].idx_ext == 0); \
|
|
|
|
(idx)++)
|
|
|
|
|
|
|
|
#define IS_MOD_BASE(mod, idx) \
|
|
|
|
(mod_rel_list[(idx)].elem_base == (mod)->elem_idx && \
|
|
|
|
mod_rel_list[(idx)].idx_base == (mod)->mod_idx && \
|
|
|
|
!(mod_rel_list[(idx)].elem_ext != (mod)->elem_idx && \
|
|
|
|
mod_rel_list[(idx)].idx_ext != (mod)->mod_idx))
|
|
|
|
|
|
|
|
#define IS_MOD_EXTENSION(mod, idx) \
|
|
|
|
(mod_rel_list[(idx)].elem_ext == (mod)->elem_idx && \
|
|
|
|
mod_rel_list[(idx)].idx_ext == (mod)->mod_idx && \
|
|
|
|
!(mod_rel_list[(idx)].elem_base != (mod)->elem_idx && \
|
|
|
|
mod_rel_list[(idx)].idx_base != (mod)->mod_idx))
|
|
|
|
|
|
|
|
#define RELATION_TYPE_EXT 0xFF
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
|
|
|
|
struct bt_mesh_elem *elem,
|
|
|
|
bool vnd, bool primary,
|
|
|
|
void *user_data),
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < dev_comp->elem_count; i++) {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[i];
|
|
|
|
|
|
|
|
for (j = 0; j < elem->model_count; j++) {
|
|
|
|
struct bt_mesh_model *model = &elem->models[j];
|
|
|
|
|
|
|
|
func(model, elem, false, i == 0, user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < elem->vnd_model_count; j++) {
|
|
|
|
struct bt_mesh_model *model = &elem->vnd_models[j];
|
|
|
|
|
|
|
|
func(model, elem, true, i == 0, user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 15:32:52 +01:00
|
|
|
static size_t bt_mesh_comp_elem_size(const struct bt_mesh_elem *elem)
|
|
|
|
{
|
|
|
|
return (4 + (elem->model_count * 2U) + (elem->vnd_model_count * 4U));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t *data_buf_add_u8_offset(struct net_buf_simple *buf,
|
|
|
|
uint8_t val, size_t *offset)
|
|
|
|
{
|
|
|
|
if (*offset >= 1) {
|
|
|
|
*offset -= 1;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return net_buf_simple_add_u8(buf, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void data_buf_add_le16_offset(struct net_buf_simple *buf,
|
|
|
|
uint16_t val, size_t *offset)
|
|
|
|
{
|
|
|
|
if (*offset >= 2) {
|
|
|
|
*offset -= 2;
|
|
|
|
return;
|
|
|
|
} else if (*offset == 1) {
|
|
|
|
*offset -= 1;
|
|
|
|
net_buf_simple_add_u8(buf, (val >> 8));
|
|
|
|
} else {
|
|
|
|
net_buf_simple_add_le16(buf, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void comp_add_model(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|
|
|
bool vnd, void *user_data)
|
|
|
|
{
|
|
|
|
struct comp_foreach_model_arg *arg = user_data;
|
|
|
|
|
|
|
|
if (vnd) {
|
|
|
|
data_buf_add_le16_offset(arg->buf, mod->vnd.company, arg->offset);
|
|
|
|
data_buf_add_le16_offset(arg->buf, mod->vnd.id, arg->offset);
|
|
|
|
} else {
|
|
|
|
data_buf_add_le16_offset(arg->buf, mod->id, arg->offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
|
2021-02-03 15:32:52 +01:00
|
|
|
static void data_buf_add_mem_offset(struct net_buf_simple *buf,
|
|
|
|
const void *mem, size_t len,
|
|
|
|
size_t *offset)
|
|
|
|
{
|
|
|
|
if (*offset >= len) {
|
|
|
|
*offset -= len;
|
|
|
|
return;
|
|
|
|
} else if (*offset > 0) {
|
|
|
|
net_buf_simple_add_mem(buf, ((uint8_t *)mem), (len - *offset));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
net_buf_simple_add_mem(buf, mem, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t metadata_model_size(struct bt_mesh_model *mod,
|
|
|
|
struct bt_mesh_elem *elem, bool vnd)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_models_metadata_entry *entry;
|
|
|
|
size_t size = 0;
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
if (!mod->metadata) {
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-02-03 15:32:52 +01:00
|
|
|
if (vnd) {
|
|
|
|
size += sizeof(mod->vnd.company);
|
|
|
|
size += sizeof(mod->vnd.id);
|
|
|
|
} else {
|
|
|
|
size += sizeof(mod->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
size += sizeof(uint8_t);
|
|
|
|
|
|
|
|
for (entry = *mod->metadata; entry && entry->len; ++entry) {
|
|
|
|
size += sizeof(entry->len) + sizeof(entry->id) + entry->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bt_mesh_metadata_page_0_size(void)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_comp *comp;
|
|
|
|
size_t size = 0;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
comp = bt_mesh_comp_get();
|
|
|
|
|
|
|
|
for (i = 0; i < dev_comp->elem_count; i++) {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[i];
|
|
|
|
|
|
|
|
size += sizeof(elem->model_count) +
|
|
|
|
sizeof(elem->vnd_model_count);
|
|
|
|
|
|
|
|
for (j = 0; j < elem->model_count; j++) {
|
|
|
|
struct bt_mesh_model *model = &elem->models[j];
|
|
|
|
|
|
|
|
size += metadata_model_size(model, elem, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < elem->vnd_model_count; j++) {
|
|
|
|
struct bt_mesh_model *model = &elem->vnd_models[j];
|
|
|
|
|
|
|
|
size += metadata_model_size(model, elem, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int metadata_add_model(struct bt_mesh_model *mod,
|
|
|
|
struct bt_mesh_elem *elem, bool vnd,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_models_metadata_entry *entry;
|
|
|
|
struct comp_foreach_model_arg *arg = user_data;
|
|
|
|
struct net_buf_simple *buf = arg->buf;
|
|
|
|
size_t *offset = arg->offset;
|
|
|
|
size_t model_size;
|
|
|
|
uint8_t count = 0;
|
|
|
|
uint8_t *count_ptr;
|
|
|
|
|
|
|
|
model_size = metadata_model_size(mod, elem, vnd);
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
if (*offset >= model_size) {
|
2021-02-03 15:32:52 +01:00
|
|
|
*offset -= model_size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_buf_simple_tailroom(buf) < (model_size + BT_MESH_MIC_SHORT)) {
|
2022-07-20 13:26:32 +02:00
|
|
|
LOG_DBG("Model metadata didn't fit in the buffer");
|
2021-02-03 15:32:52 +01:00
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
|
|
|
comp_add_model(mod, elem, vnd, user_data);
|
|
|
|
|
|
|
|
count_ptr = data_buf_add_u8_offset(buf, 0, offset);
|
|
|
|
|
|
|
|
if (mod->metadata) {
|
|
|
|
for (entry = *mod->metadata; entry && entry->data != NULL; ++entry) {
|
|
|
|
data_buf_add_le16_offset(buf, entry->len, offset);
|
|
|
|
data_buf_add_le16_offset(buf, entry->id, offset);
|
|
|
|
data_buf_add_mem_offset(buf, entry->data, entry->len, offset);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count_ptr) {
|
|
|
|
*count_ptr = count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_comp *comp;
|
|
|
|
struct comp_foreach_model_arg arg = {
|
|
|
|
.buf = buf,
|
|
|
|
.offset = &offset,
|
|
|
|
};
|
|
|
|
uint8_t *mod_count_ptr;
|
|
|
|
uint8_t *vnd_count_ptr;
|
|
|
|
int i, j, err;
|
|
|
|
|
|
|
|
comp = bt_mesh_comp_get();
|
|
|
|
|
|
|
|
for (i = 0; i < comp->elem_count; i++) {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[i];
|
|
|
|
|
|
|
|
/* Check that the buffer has available tailroom for metadata item counts */
|
|
|
|
if (net_buf_simple_tailroom(buf) < (((offset == 0) ? 2 : (offset == 1) ? 1 : 0)
|
|
|
|
+ BT_MESH_MIC_SHORT)) {
|
|
|
|
LOG_DBG("Model metadata didn't fit in the buffer");
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
mod_count_ptr = data_buf_add_u8_offset(buf, 0, &offset);
|
|
|
|
vnd_count_ptr = data_buf_add_u8_offset(buf, 0, &offset);
|
|
|
|
|
|
|
|
for (j = 0; j < elem->model_count; j++) {
|
|
|
|
struct bt_mesh_model *model = &elem->models[j];
|
|
|
|
|
|
|
|
if (!model->metadata) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = metadata_add_model(model, elem, false, &arg);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
if (mod_count_ptr) {
|
|
|
|
(*mod_count_ptr) += 1;
|
|
|
|
}
|
2021-02-03 15:32:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < elem->vnd_model_count; j++) {
|
|
|
|
struct bt_mesh_model *model = &elem->vnd_models[j];
|
|
|
|
|
|
|
|
if (!model->metadata) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = metadata_add_model(model, elem, true, &arg);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
if (vnd_count_ptr) {
|
|
|
|
(*vnd_count_ptr) += 1;
|
|
|
|
}
|
2021-02-03 15:32:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
size_t bt_mesh_comp_page_0_size(void)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_comp *comp;
|
|
|
|
const struct bt_mesh_elem *elem;
|
|
|
|
size_t size = 10;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
comp = bt_mesh_comp_get();
|
|
|
|
|
|
|
|
for (i = 0; i < comp->elem_count; i++) {
|
|
|
|
elem = &comp->elem[i];
|
|
|
|
size += bt_mesh_comp_elem_size(elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem,
|
|
|
|
size_t *offset)
|
|
|
|
{
|
|
|
|
struct comp_foreach_model_arg arg = {
|
|
|
|
.buf = buf,
|
|
|
|
.offset = offset,
|
|
|
|
};
|
|
|
|
const size_t elem_size = bt_mesh_comp_elem_size(elem);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (*offset >= elem_size) {
|
|
|
|
*offset -= elem_size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_buf_simple_tailroom(buf) < (elem_size + BT_MESH_MIC_SHORT)) {
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)) {
|
|
|
|
/* Mesh Profile 1.1 Section 4.4.1.2.2:
|
|
|
|
* If the complete list of models does not fit in the Data field,
|
|
|
|
* the element shall not be reported.
|
|
|
|
*/
|
|
|
|
LOG_DBG("Element 0x%04x didn't fit in the Data field",
|
|
|
|
elem->addr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_ERR("Too large device composition");
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
|
|
|
data_buf_add_le16_offset(buf, elem->loc, offset);
|
|
|
|
|
|
|
|
data_buf_add_u8_offset(buf, elem->model_count, offset);
|
|
|
|
data_buf_add_u8_offset(buf, elem->vnd_model_count, offset);
|
|
|
|
|
|
|
|
for (i = 0; i < elem->model_count; i++) {
|
|
|
|
struct bt_mesh_model *model = &elem->models[i];
|
|
|
|
|
|
|
|
comp_add_model(model, elem, false, &arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < elem->vnd_model_count; i++) {
|
|
|
|
struct bt_mesh_model *model = &elem->vnd_models[i];
|
|
|
|
|
|
|
|
comp_add_model(model, elem, true, &arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_comp_data_get_page_0(struct net_buf_simple *buf, size_t offset)
|
|
|
|
{
|
|
|
|
uint16_t feat = 0U;
|
|
|
|
const struct bt_mesh_comp *comp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
comp = bt_mesh_comp_get();
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_RELAY)) {
|
|
|
|
feat |= BT_MESH_FEAT_RELAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
|
|
|
|
feat |= BT_MESH_FEAT_PROXY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
|
|
|
|
feat |= BT_MESH_FEAT_FRIEND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
|
|
|
feat |= BT_MESH_FEAT_LOW_POWER;
|
|
|
|
}
|
|
|
|
|
|
|
|
data_buf_add_le16_offset(buf, comp->cid, &offset);
|
|
|
|
data_buf_add_le16_offset(buf, comp->pid, &offset);
|
|
|
|
data_buf_add_le16_offset(buf, comp->vid, &offset);
|
|
|
|
data_buf_add_le16_offset(buf, CONFIG_BT_MESH_CRPL, &offset);
|
|
|
|
data_buf_add_le16_offset(buf, feat, &offset);
|
|
|
|
|
|
|
|
for (i = 0; i < comp->elem_count; i++) {
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = comp_add_elem(buf, &comp->elem[i], &offset);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-31 11:58:06 +02:00
|
|
|
static uint8_t count_mod_ext(struct bt_mesh_model *mod, uint8_t *max_offset)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint8_t extensions = 0;
|
|
|
|
int8_t offset, offset_record = 0;
|
|
|
|
|
|
|
|
MOD_REL_LIST_FOR_EACH(i) {
|
|
|
|
if (IS_MOD_EXTENSION(mod, i) &&
|
|
|
|
mod_rel_list[i].type == RELATION_TYPE_EXT) {
|
|
|
|
extensions++;
|
|
|
|
offset = mod_rel_list[i].elem_ext -
|
|
|
|
mod_rel_list[i].elem_base;
|
|
|
|
if (abs(offset) > abs(offset_record)) {
|
|
|
|
offset_record = offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(max_offset, &offset_record, sizeof(uint8_t));
|
|
|
|
return extensions;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_cor_present(struct bt_mesh_model *mod, uint8_t *cor_id)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
MOD_REL_LIST_FOR_EACH(i) {
|
|
|
|
if ((IS_MOD_BASE(mod, i) ||
|
|
|
|
IS_MOD_EXTENSION(mod, i)) &&
|
|
|
|
mod_rel_list[i].type < RELATION_TYPE_EXT) {
|
|
|
|
memcpy(cor_id, &mod_rel_list[i].type, sizeof(uint8_t));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prep_model_item_header(struct bt_mesh_model *mod, uint8_t *cor_id,
|
|
|
|
uint8_t *mod_cnt, struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
uint8_t ext_mod_cnt;
|
|
|
|
bool cor_present;
|
|
|
|
uint8_t mod_elem_info = 0;
|
|
|
|
int8_t max_offset;
|
|
|
|
|
|
|
|
ext_mod_cnt = count_mod_ext(mod, &max_offset);
|
|
|
|
cor_present = is_cor_present(mod, cor_id);
|
|
|
|
|
|
|
|
mod_elem_info = ext_mod_cnt << 2;
|
|
|
|
if (ext_mod_cnt > 31 ||
|
|
|
|
max_offset > 3 ||
|
|
|
|
max_offset < -4) {
|
|
|
|
mod_elem_info |= BIT(1);
|
|
|
|
}
|
|
|
|
if (cor_present) {
|
|
|
|
mod_elem_info |= BIT(0);
|
|
|
|
}
|
|
|
|
net_buf_simple_add_u8(buf, mod_elem_info);
|
|
|
|
|
|
|
|
if (cor_present) {
|
|
|
|
net_buf_simple_add_u8(buf, *cor_id);
|
|
|
|
}
|
|
|
|
memset(mod_cnt, ext_mod_cnt, sizeof(uint8_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_items_to_page(struct net_buf_simple *buf, struct bt_mesh_model *mod,
|
|
|
|
uint8_t ext_mod_cnt)
|
|
|
|
{
|
|
|
|
int i, offset;
|
|
|
|
uint8_t mod_idx;
|
|
|
|
|
|
|
|
MOD_REL_LIST_FOR_EACH(i) {
|
|
|
|
if (IS_MOD_EXTENSION(mod, i)) {
|
|
|
|
offset = mod->elem_idx - mod_rel_list[i].elem_base;
|
|
|
|
mod_idx = mod_rel_list[i].idx_base;
|
|
|
|
if (ext_mod_cnt < 32 &&
|
|
|
|
offset < 4 &&
|
|
|
|
offset > -5) {
|
|
|
|
/* short format */
|
|
|
|
if (offset < 0) {
|
|
|
|
offset += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset |= mod_idx << 3;
|
|
|
|
net_buf_simple_add_u8(buf, offset);
|
|
|
|
} else {
|
|
|
|
/* long format */
|
|
|
|
if (offset < 0) {
|
|
|
|
offset += 256;
|
|
|
|
}
|
|
|
|
net_buf_simple_add_u8(buf, offset);
|
|
|
|
net_buf_simple_add_u8(buf, mod_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
const struct bt_mesh_comp *comp;
|
|
|
|
uint8_t cor_id = 0;
|
|
|
|
uint8_t ext_mod_cnt = 0;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
comp = bt_mesh_comp_get();
|
|
|
|
|
|
|
|
for (i = 0; i < comp->elem_count; i++) {
|
|
|
|
net_buf_simple_add_u8(buf, comp->elem[i].model_count);
|
|
|
|
net_buf_simple_add_u8(buf, comp->elem[i].vnd_model_count);
|
|
|
|
for (j = 0; j < comp->elem[i].model_count; j++) {
|
|
|
|
prep_model_item_header(&comp->elem[i].models[j],
|
|
|
|
&cor_id, &ext_mod_cnt, buf);
|
|
|
|
if (ext_mod_cnt != 0) {
|
|
|
|
add_items_to_page(buf,
|
|
|
|
&comp->elem[i].models[j],
|
|
|
|
ext_mod_cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < comp->elem[i].vnd_model_count; j++) {
|
|
|
|
prep_model_item_header(&comp->elem[i].vnd_models[j],
|
|
|
|
&cor_id, &ext_mod_cnt, buf);
|
|
|
|
if (ext_mod_cnt != 0) {
|
|
|
|
add_items_to_page(buf,
|
|
|
|
&comp->elem[i].vnd_models[j],
|
|
|
|
ext_mod_cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
int32_t period;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
if (!mod->pub) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mod->pub->period >> 6) {
|
|
|
|
case 0x00:
|
|
|
|
/* 1 step is 100 ms */
|
2020-04-06 13:56:14 +02:00
|
|
|
period = (mod->pub->period & BIT_MASK(6)) * 100U;
|
2017-06-16 12:30:54 +03:00
|
|
|
break;
|
|
|
|
case 0x01:
|
|
|
|
/* 1 step is 1 second */
|
2020-04-06 13:56:14 +02:00
|
|
|
period = (mod->pub->period & BIT_MASK(6)) * MSEC_PER_SEC;
|
2017-06-16 12:30:54 +03:00
|
|
|
break;
|
|
|
|
case 0x02:
|
|
|
|
/* 1 step is 10 seconds */
|
2020-04-06 13:56:14 +02:00
|
|
|
period = (mod->pub->period & BIT_MASK(6)) * 10U * MSEC_PER_SEC;
|
2017-06-16 12:30:54 +03:00
|
|
|
break;
|
|
|
|
case 0x03:
|
|
|
|
/* 1 step is 10 minutes */
|
2020-04-06 13:56:14 +02:00
|
|
|
period = (mod->pub->period & BIT_MASK(6)) * 600U * MSEC_PER_SEC;
|
2017-06-16 12:30:54 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CODE_UNREACHABLE;
|
|
|
|
}
|
|
|
|
|
2019-04-11 17:38:30 +03:00
|
|
|
if (mod->pub->fast_period) {
|
2020-08-06 11:52:08 +02:00
|
|
|
if (!period) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MAX(period >> mod->pub->period_div, 100);
|
2019-04-11 17:38:30 +03:00
|
|
|
} else {
|
|
|
|
return period;
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static int32_t next_period(struct bt_mesh_model *mod)
|
2017-11-20 20:17:31 +02:00
|
|
|
{
|
|
|
|
struct bt_mesh_model_pub *pub = mod->pub;
|
2021-12-15 09:58:53 +01:00
|
|
|
uint32_t period = 0;
|
|
|
|
uint32_t elapsed;
|
2021-12-15 09:58:53 +01:00
|
|
|
|
2021-12-20 22:28:28 +01:00
|
|
|
elapsed = k_uptime_get_32() - pub->period_start;
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Publishing took %ums", elapsed);
|
2021-12-20 22:28:28 +01:00
|
|
|
|
2021-12-15 09:58:53 +01:00
|
|
|
if (mod->pub->count) {
|
|
|
|
/* If a message is to be retransmitted, period should include time since the first
|
|
|
|
* publication until the last publication.
|
|
|
|
*/
|
|
|
|
period = BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit);
|
|
|
|
period *= BT_MESH_PUB_MSG_NUM(mod->pub);
|
|
|
|
|
|
|
|
if (period && elapsed >= period) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Retransmission interval is too short");
|
2021-12-15 09:58:53 +01:00
|
|
|
/* Return smallest positive number since 0 means disabled */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!period) {
|
|
|
|
period = bt_mesh_model_pub_period_get(mod);
|
|
|
|
if (!period) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-11 20:00:45 +01:00
|
|
|
if (elapsed >= period) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Publication sending took longer than the period");
|
2017-11-20 20:17:31 +02:00
|
|
|
/* Return smallest positive number since 0 means disabled */
|
2020-04-06 13:56:14 +02:00
|
|
|
return 1;
|
2017-11-20 20:17:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return period - elapsed;
|
|
|
|
}
|
|
|
|
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
static void publish_sent(int err, void *user_data)
|
|
|
|
{
|
|
|
|
struct bt_mesh_model *mod = user_data;
|
2020-05-27 11:26:57 -05:00
|
|
|
int32_t delay;
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("err %d, time %u", err, k_uptime_get_32());
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
|
2021-12-15 09:58:53 +01:00
|
|
|
delay = next_period(mod);
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
|
2017-11-20 17:13:44 +02:00
|
|
|
if (delay) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Publishing next time in %dms", delay);
|
2021-04-15 12:28:20 +02:00
|
|
|
/* Using schedule() in case the application has already called
|
|
|
|
* bt_mesh_publish, and a publication is pending.
|
|
|
|
*/
|
|
|
|
k_work_schedule(&mod->pub->timer, K_MSEC(delay));
|
2017-11-20 17:13:44 +02:00
|
|
|
}
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static void publish_start(uint16_t duration, int err, void *user_data)
|
2019-08-22 14:40:55 +03:00
|
|
|
{
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to publish: err %d", err);
|
2021-04-15 12:28:20 +02:00
|
|
|
publish_sent(err, user_data);
|
2019-08-22 14:40:55 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
static const struct bt_mesh_send_cb pub_sent_cb = {
|
2019-08-22 14:40:55 +03:00
|
|
|
.start = publish_start,
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
.end = publish_sent,
|
|
|
|
};
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
static int publish_transmit(struct bt_mesh_model *mod)
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
{
|
2018-02-10 10:32:58 +02:00
|
|
|
NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX);
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
struct bt_mesh_model_pub *pub = mod->pub;
|
2022-12-02 14:44:34 +01:00
|
|
|
struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_PUB(pub);
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
struct bt_mesh_net_tx tx = {
|
|
|
|
.ctx = &ctx,
|
2018-05-08 21:18:55 +03:00
|
|
|
.src = bt_mesh_model_elem(mod)->addr,
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
.friend_cred = pub->cred,
|
|
|
|
};
|
|
|
|
|
2018-02-10 10:32:58 +02:00
|
|
|
net_buf_simple_add_mem(&sdu, pub->msg->data, pub->msg->len);
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
|
2018-02-10 10:32:58 +02:00
|
|
|
return bt_mesh_trans_send(&tx, &sdu, &pub_sent_cb, mod);
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
}
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
static int pub_period_start(struct bt_mesh_model_pub *pub)
|
2020-01-15 16:45:11 +01:00
|
|
|
{
|
2021-04-15 12:28:20 +02:00
|
|
|
int err;
|
|
|
|
|
|
|
|
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
|
|
|
|
|
|
|
|
if (!pub->update) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = pub->update(pub->mod);
|
2021-12-15 09:58:53 +01:00
|
|
|
|
|
|
|
pub->period_start = k_uptime_get_32();
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
if (err) {
|
|
|
|
/* Skip this publish attempt. */
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Update failed, skipping publish (err: %d)", err);
|
2021-04-15 12:28:20 +02:00
|
|
|
pub->count = 0;
|
2021-05-14 16:01:53 +02:00
|
|
|
publish_sent(err, pub->mod);
|
2021-04-15 12:28:20 +02:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-01-15 16:45:11 +01:00
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
static void mod_publish(struct k_work *work)
|
|
|
|
{
|
2021-04-15 12:28:20 +02:00
|
|
|
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
|
|
|
struct bt_mesh_model_pub *pub = CONTAINER_OF(dwork,
|
2017-06-16 12:30:54 +03:00
|
|
|
struct bt_mesh_model_pub,
|
2021-04-15 12:28:20 +02:00
|
|
|
timer);
|
2017-11-20 17:13:44 +02:00
|
|
|
int err;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
if (pub->addr == BT_MESH_ADDR_UNASSIGNED ||
|
|
|
|
atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
|
|
|
|
/* Publication is no longer active, but the cancellation of the
|
|
|
|
* delayed work failed. Abandon recurring timer.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("%u", k_uptime_get_32());
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
|
|
|
|
if (pub->count) {
|
2021-04-15 12:28:20 +02:00
|
|
|
pub->count--;
|
2021-11-05 16:25:51 +01:00
|
|
|
|
|
|
|
if (pub->retr_update && pub->update &&
|
|
|
|
bt_mesh_model_pub_is_retransmission(pub->mod)) {
|
|
|
|
err = pub->update(pub->mod);
|
|
|
|
if (err) {
|
|
|
|
publish_sent(err, pub->mod);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-04-15 12:28:20 +02:00
|
|
|
} else {
|
|
|
|
/* First publication in this period */
|
|
|
|
err = pub_period_start(pub);
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
if (err) {
|
2021-04-15 12:28:20 +02:00
|
|
|
return;
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
err = publish_transmit(pub->mod);
|
2017-11-20 17:13:44 +02:00
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to publish (err %d)", err);
|
2021-04-15 12:28:20 +02:00
|
|
|
publish_sent(err, pub->mod);
|
2017-11-20 17:13:44 +02:00
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2018-05-08 21:18:55 +03:00
|
|
|
struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod)
|
|
|
|
{
|
|
|
|
return &dev_comp->elem[mod->elem_idx];
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx)
|
2018-05-08 21:18:55 +03:00
|
|
|
{
|
|
|
|
struct bt_mesh_elem *elem;
|
|
|
|
|
|
|
|
if (elem_idx >= dev_comp->elem_count) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Invalid element index %u", elem_idx);
|
2018-05-08 21:18:55 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
elem = &dev_comp->elem[elem_idx];
|
|
|
|
|
|
|
|
if (vnd) {
|
|
|
|
if (mod_idx >= elem->vnd_model_count) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Invalid vendor model index %u", mod_idx);
|
2018-05-08 21:18:55 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &elem->vnd_models[mod_idx];
|
|
|
|
} else {
|
|
|
|
if (mod_idx >= elem->model_count) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Invalid SIG model index %u", mod_idx);
|
2018-05-08 21:18:55 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &elem->models[mod_idx];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-08 02:49:54 -07:00
|
|
|
#if defined(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE)
|
|
|
|
static int bt_mesh_vnd_mod_msg_cid_check(struct bt_mesh_model *mod)
|
|
|
|
{
|
|
|
|
uint16_t cid;
|
|
|
|
const struct bt_mesh_model_op *op;
|
|
|
|
|
|
|
|
for (op = mod->op; op->func; op++) {
|
|
|
|
cid = (uint16_t)(op->opcode & 0xffff);
|
|
|
|
|
|
|
|
if (cid == mod->vnd.company) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Invalid vendor model(company:0x%04x"
|
2021-05-08 02:49:54 -07:00
|
|
|
" id:0x%04x) message opcode 0x%08x",
|
|
|
|
mod->vnd.company, mod->vnd.id, op->opcode);
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|
|
|
bool vnd, bool primary, void *user_data)
|
|
|
|
{
|
|
|
|
int i;
|
2020-05-15 15:06:35 +02:00
|
|
|
int *err = user_data;
|
|
|
|
|
|
|
|
if (*err) {
|
|
|
|
return;
|
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
if (mod->pub) {
|
|
|
|
mod->pub->mod = mod;
|
2021-04-15 12:28:20 +02:00
|
|
|
k_work_init_delayable(&mod->pub->timer, mod_publish);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
for (i = 0; i < mod->keys_cnt; i++) {
|
2017-06-16 12:30:54 +03:00
|
|
|
mod->keys[i] = BT_MESH_KEY_UNUSED;
|
|
|
|
}
|
|
|
|
|
2018-05-08 21:18:55 +03:00
|
|
|
mod->elem_idx = elem - dev_comp->elem;
|
|
|
|
if (vnd) {
|
|
|
|
mod->mod_idx = mod - elem->vnd_models;
|
2021-05-08 02:49:54 -07:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE)) {
|
|
|
|
*err = bt_mesh_vnd_mod_msg_cid_check(mod);
|
|
|
|
if (*err) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 21:18:55 +03:00
|
|
|
} else {
|
|
|
|
mod->mod_idx = mod - elem->models;
|
|
|
|
}
|
|
|
|
|
2019-08-19 10:05:36 +02:00
|
|
|
if (mod->cb && mod->cb->init) {
|
2020-05-15 15:06:35 +02:00
|
|
|
*err = mod->cb->init(mod);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
|
|
|
|
{
|
2020-05-15 15:06:35 +02:00
|
|
|
int err;
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
/* There must be at least one element */
|
2021-06-16 16:29:08 +08:00
|
|
|
if (!comp || !comp->elem_count) {
|
2017-06-16 12:30:54 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_comp = comp;
|
|
|
|
|
2020-05-15 15:06:35 +02:00
|
|
|
err = 0;
|
2022-08-31 11:58:06 +02:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) {
|
|
|
|
memset(mod_rel_list, 0, sizeof(mod_rel_list));
|
|
|
|
}
|
|
|
|
|
2020-05-15 15:06:35 +02:00
|
|
|
bt_mesh_model_foreach(mod_init, &err);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2022-08-31 11:58:06 +02:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
MOD_REL_LIST_FOR_EACH(i) {
|
|
|
|
LOG_DBG("registered %s",
|
|
|
|
mod_rel_list[i].type < RELATION_TYPE_EXT ?
|
|
|
|
"correspondence" : "extension");
|
|
|
|
LOG_DBG("\tbase: elem %u idx %u",
|
|
|
|
mod_rel_list[i].elem_base,
|
|
|
|
mod_rel_list[i].idx_base);
|
|
|
|
LOG_DBG("\text: elem %u idx %u",
|
|
|
|
mod_rel_list[i].elem_ext,
|
|
|
|
mod_rel_list[i].idx_ext);
|
|
|
|
}
|
|
|
|
if (i < MOD_REL_LIST_SIZE) {
|
|
|
|
LOG_WRN("Unused space in relation list: %d",
|
|
|
|
MOD_REL_LIST_SIZE - i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 15:06:35 +02:00
|
|
|
return err;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
void bt_mesh_comp_provision(uint16_t addr)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dev_primary_addr = addr;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("addr 0x%04x elem_count %zu", addr, dev_comp->elem_count);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
for (i = 0; i < dev_comp->elem_count; i++) {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[i];
|
|
|
|
|
|
|
|
elem->addr = addr++;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", elem->addr, elem->model_count,
|
|
|
|
elem->vnd_model_count);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_comp_unprovision(void)
|
|
|
|
{
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("");
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
dev_primary_addr = BT_MESH_ADDR_UNASSIGNED;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t bt_mesh_primary_addr(void)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
return dev_primary_addr;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static uint16_t *model_group_get(struct bt_mesh_model *mod, uint16_t addr)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
for (i = 0; i < mod->groups_cnt; i++) {
|
2017-06-16 12:30:54 +03:00
|
|
|
if (mod->groups[i] == addr) {
|
|
|
|
return &mod->groups[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-10-18 13:23:06 +02:00
|
|
|
struct find_group_visitor_ctx {
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t *entry;
|
2019-10-18 13:23:06 +02:00
|
|
|
struct bt_mesh_model *mod;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t addr;
|
2019-10-18 13:23:06 +02:00
|
|
|
};
|
|
|
|
|
2021-07-26 16:16:01 +02:00
|
|
|
static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, void *user_data)
|
2019-10-18 13:23:06 +02:00
|
|
|
{
|
|
|
|
struct find_group_visitor_ctx *ctx = user_data;
|
|
|
|
|
|
|
|
if (mod->elem_idx != ctx->mod->elem_idx) {
|
|
|
|
return BT_MESH_WALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->entry = model_group_get(mod, ctx->addr);
|
|
|
|
if (ctx->entry) {
|
|
|
|
ctx->mod = mod;
|
|
|
|
return BT_MESH_WALK_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return BT_MESH_WALK_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr)
|
2019-10-18 13:23:06 +02:00
|
|
|
{
|
|
|
|
struct find_group_visitor_ctx ctx = {
|
|
|
|
.mod = *mod,
|
|
|
|
.entry = NULL,
|
|
|
|
.addr = addr,
|
|
|
|
};
|
|
|
|
|
2021-07-26 16:16:01 +02:00
|
|
|
bt_mesh_model_extensions_walk(*mod, find_group_mod_visitor, &ctx);
|
2019-10-18 13:23:06 +02:00
|
|
|
|
|
|
|
*mod = ctx.mod;
|
|
|
|
return ctx.entry;
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t group_addr)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
struct bt_mesh_model *model;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t *match;
|
2017-06-16 12:30:54 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < elem->model_count; i++) {
|
|
|
|
model = &elem->models[i];
|
|
|
|
|
2019-10-18 13:23:06 +02:00
|
|
|
match = model_group_get(model, group_addr);
|
2017-06-16 12:30:54 +03:00
|
|
|
if (match) {
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < elem->vnd_model_count; i++) {
|
|
|
|
model = &elem->vnd_models[i];
|
|
|
|
|
2019-10-18 13:23:06 +02:00
|
|
|
match = model_group_get(model, group_addr);
|
2017-06-16 12:30:54 +03:00
|
|
|
if (match) {
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t index;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-05-29 13:18:10 -06:00
|
|
|
if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
index = addr - dev_comp->elem[0].addr;
|
|
|
|
if (index >= dev_comp->elem_count) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &dev_comp->elem[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool bt_mesh_has_addr(uint16_t addr)
|
|
|
|
{
|
|
|
|
uint16_t index;
|
|
|
|
|
2019-08-28 15:24:41 +02:00
|
|
|
if (BT_MESH_ADDR_IS_UNICAST(addr)) {
|
2021-05-29 13:18:10 -06:00
|
|
|
return bt_mesh_elem_find(addr) != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_ACCESS_LAYER_MSG) && msg_cb) {
|
|
|
|
return true;
|
2019-08-28 15:24:41 +02:00
|
|
|
}
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2019-08-28 15:24:41 +02:00
|
|
|
for (index = 0; index < dev_comp->elem_count; index++) {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
|
|
|
|
|
|
|
if (bt_mesh_elem_find_group(elem, addr)) {
|
2021-05-29 13:18:10 -06:00
|
|
|
return true;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-29 13:18:10 -06:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_MESH_ACCESS_LAYER_MSG)
|
|
|
|
void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx,
|
|
|
|
struct net_buf_simple *buf))
|
|
|
|
{
|
|
|
|
msg_cb = cb;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-10-07 13:56:35 +02:00
|
|
|
int bt_mesh_access_send(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t src_addr,
|
|
|
|
const struct bt_mesh_send_cb *cb, void *cb_data)
|
2021-05-29 13:18:10 -06:00
|
|
|
{
|
|
|
|
struct bt_mesh_net_tx tx = {
|
|
|
|
.ctx = ctx,
|
|
|
|
.src = src_addr,
|
|
|
|
};
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx.ctx->net_idx, tx.ctx->app_idx,
|
|
|
|
tx.ctx->addr);
|
|
|
|
LOG_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));
|
2021-05-29 13:18:10 -06:00
|
|
|
|
|
|
|
if (!bt_mesh_is_provisioned()) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Local node is not yet provisioned");
|
2021-05-29 13:18:10 -06:00
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_mesh_trans_send(&tx, buf, cb, cb_data);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t bt_mesh_elem_count(void)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
return dev_comp->elem_count;
|
|
|
|
}
|
|
|
|
|
2021-09-07 13:14:48 +02:00
|
|
|
bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
for (i = 0; i < mod->keys_cnt; i++) {
|
2019-07-12 15:57:58 +02:00
|
|
|
if (mod->keys[i] == key ||
|
|
|
|
(mod->keys[i] == BT_MESH_KEY_DEV_ANY &&
|
|
|
|
BT_MESH_IS_DEV_KEY(key))) {
|
2017-06-16 12:30:54 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst)
|
2019-10-18 13:23:06 +02:00
|
|
|
{
|
|
|
|
if (BT_MESH_ADDR_IS_UNICAST(dst)) {
|
|
|
|
return (dev_comp->elem[mod->elem_idx].addr == dst);
|
2022-04-20 10:35:44 +02:00
|
|
|
} else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst) ||
|
|
|
|
(BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->elem_idx != 0)) {
|
2020-05-25 21:49:50 +08:00
|
|
|
return !!bt_mesh_model_find_group(&mod, dst);
|
2019-10-18 13:23:06 +02:00
|
|
|
}
|
|
|
|
|
2020-08-18 13:36:38 +02:00
|
|
|
/* If a message with a fixed group address is sent to the access layer,
|
|
|
|
* the lower layers have already confirmed that we are subscribing to
|
|
|
|
* it. All models on the primary element should receive the message.
|
|
|
|
*/
|
|
|
|
return mod->elem_idx == 0;
|
2019-10-18 13:23:06 +02:00
|
|
|
}
|
|
|
|
|
2021-05-08 02:49:54 -07:00
|
|
|
static const struct bt_mesh_model_op *find_op(struct bt_mesh_elem *elem,
|
|
|
|
uint32_t opcode, struct bt_mesh_model **model)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t i;
|
2021-05-08 02:49:54 -07:00
|
|
|
uint8_t count;
|
|
|
|
/* This value shall not be used in shipping end products. */
|
|
|
|
uint32_t cid = UINT32_MAX;
|
|
|
|
struct bt_mesh_model *models;
|
|
|
|
|
|
|
|
/* SIG models cannot contain 3-byte (vendor) OpCodes, and
|
|
|
|
* vendor models cannot contain SIG (1- or 2-byte) OpCodes, so
|
|
|
|
* we only need to do the lookup in one of the model lists.
|
|
|
|
*/
|
|
|
|
if (BT_MESH_MODEL_OP_LEN(opcode) < 3) {
|
|
|
|
models = elem->models;
|
|
|
|
count = elem->model_count;
|
|
|
|
} else {
|
|
|
|
models = elem->vnd_models;
|
|
|
|
count = elem->vnd_model_count;
|
|
|
|
|
|
|
|
cid = (uint16_t)(opcode & 0xffff);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0U; i < count; i++) {
|
2017-06-16 12:30:54 +03:00
|
|
|
|
|
|
|
const struct bt_mesh_model_op *op;
|
|
|
|
|
2021-05-08 02:49:54 -07:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE) &&
|
|
|
|
cid != UINT32_MAX &&
|
|
|
|
cid != models[i].vnd.company) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
*model = &models[i];
|
|
|
|
|
|
|
|
for (op = (*model)->op; op->func; op++) {
|
|
|
|
if (op->opcode == opcode) {
|
|
|
|
return op;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*model = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
switch (buf->data[0] >> 6) {
|
|
|
|
case 0x00:
|
|
|
|
case 0x01:
|
|
|
|
if (buf->data[0] == 0x7f) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Ignoring RFU OpCode");
|
2017-06-16 12:30:54 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*opcode = net_buf_simple_pull_u8(buf);
|
|
|
|
return 0;
|
|
|
|
case 0x02:
|
|
|
|
if (buf->len < 2) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Too short payload for 2-octet OpCode");
|
2017-06-16 12:30:54 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*opcode = net_buf_simple_pull_be16(buf);
|
|
|
|
return 0;
|
|
|
|
case 0x03:
|
|
|
|
if (buf->len < 3) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Too short payload for 3-octet OpCode");
|
2017-06-16 12:30:54 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*opcode = net_buf_simple_pull_u8(buf) << 16;
|
2019-12-27 16:03:35 +01:00
|
|
|
/* Using LE for the CID since the model layer is defined as
|
|
|
|
* little-endian in the mesh spec and using BT_MESH_MODEL_OP_3
|
|
|
|
* will declare the opcode in this way.
|
|
|
|
*/
|
2017-06-16 12:30:54 +03:00
|
|
|
*opcode |= net_buf_simple_pull_le16(buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CODE_UNREACHABLE;
|
|
|
|
}
|
|
|
|
|
2021-02-18 14:09:18 +01:00
|
|
|
static int element_model_recv(struct bt_mesh_msg_ctx *ctx,
|
|
|
|
struct net_buf_simple *buf, uint16_t addr,
|
|
|
|
struct bt_mesh_elem *elem, uint32_t opcode)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
|
|
|
const struct bt_mesh_model_op *op;
|
2021-02-18 14:09:18 +01:00
|
|
|
struct bt_mesh_model *model;
|
|
|
|
struct net_buf_simple_state state;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
op = find_op(elem, opcode, &model);
|
|
|
|
if (!op) {
|
|
|
|
LOG_ERR("No OpCode 0x%08x for elem 0x%02x", opcode, elem->addr);
|
|
|
|
return ACCESS_STATUS_WRONG_OPCODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bt_mesh_model_has_key(model, ctx->app_idx)) {
|
|
|
|
LOG_ERR("Wrong key");
|
|
|
|
return ACCESS_STATUS_WRONG_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!model_has_dst(model, addr)) {
|
|
|
|
LOG_ERR("Invalid address 0x%02x", addr);
|
|
|
|
return ACCESS_STATUS_INVALID_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((op->len >= 0) && (buf->len < (size_t)op->len)) {
|
|
|
|
LOG_ERR("Too short message for OpCode 0x%08x", opcode);
|
|
|
|
return ACCESS_STATUS_MESSAGE_NOT_UNDERSTOOD;
|
|
|
|
} else if ((op->len < 0) && (buf->len != (size_t)(-op->len))) {
|
|
|
|
LOG_ERR("Invalid message size for OpCode 0x%08x", opcode);
|
|
|
|
return ACCESS_STATUS_MESSAGE_NOT_UNDERSTOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_simple_save(buf, &state);
|
|
|
|
err = op->func(model, ctx, buf);
|
|
|
|
net_buf_simple_restore(buf, &state);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
return ACCESS_STATUS_MESSAGE_NOT_UNDERSTOOD;
|
|
|
|
}
|
|
|
|
return ACCESS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
int err = ACCESS_STATUS_SUCCESS;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t opcode;
|
2021-02-18 14:09:18 +01:00
|
|
|
uint16_t index;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-12-11 14:59:39 +01:00
|
|
|
LOG_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", ctx->app_idx, ctx->addr,
|
|
|
|
ctx->recv_dst);
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2020-11-16 12:01:05 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_TESTING)) {
|
|
|
|
bt_test_mesh_model_recv(ctx->addr, ctx->recv_dst, buf->data,
|
|
|
|
buf->len);
|
|
|
|
}
|
|
|
|
|
2017-06-16 12:30:54 +03:00
|
|
|
if (get_opcode(buf, &opcode) < 0) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Unable to decode OpCode");
|
2021-02-18 14:09:18 +01:00
|
|
|
return ACCESS_STATUS_WRONG_OPCODE;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("OpCode 0x%08x", opcode);
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-02-18 14:09:18 +01:00
|
|
|
if (BT_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
|
|
|
|
index = ctx->recv_dst - dev_comp->elem[0].addr;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-02-18 14:09:18 +01:00
|
|
|
if (index >= dev_comp->elem_count) {
|
|
|
|
LOG_ERR("Invalid address 0x%02x", ctx->recv_dst);
|
|
|
|
err = ACCESS_STATUS_INVALID_ADDRESS;
|
|
|
|
} else {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-02-18 14:09:18 +01:00
|
|
|
err = element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode);
|
2019-10-18 13:23:06 +02:00
|
|
|
}
|
2021-02-18 14:09:18 +01:00
|
|
|
} else {
|
|
|
|
for (index = 0; index < dev_comp->elem_count; index++) {
|
|
|
|
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2021-02-18 14:09:18 +01:00
|
|
|
(void)element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode);
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
}
|
2021-05-29 13:18:10 -06:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_ACCESS_LAYER_MSG) && msg_cb) {
|
2020-12-11 14:59:39 +01:00
|
|
|
msg_cb(opcode, ctx, buf);
|
2021-05-29 13:18:10 -06:00
|
|
|
}
|
2021-02-18 14:09:18 +01:00
|
|
|
|
|
|
|
return err;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
int bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
|
|
|
struct net_buf_simple *msg,
|
|
|
|
const struct bt_mesh_send_cb *cb, void *cb_data)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2021-02-18 14:09:18 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_OP_AGG) && bt_mesh_op_agg_accept(ctx)) {
|
|
|
|
return bt_mesh_op_agg_send(model, ctx, msg, cb);
|
|
|
|
}
|
|
|
|
|
2021-09-07 13:14:48 +02:00
|
|
|
if (!bt_mesh_model_has_key(model, ctx->app_idx)) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Model not bound to AppKey 0x%04x", ctx->app_idx);
|
2017-06-16 12:30:54 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-10-07 13:56:35 +02:00
|
|
|
return bt_mesh_access_send(ctx, msg, bt_mesh_model_elem(model)->addr, cb, cb_data);
|
2017-11-09 20:35:19 +02:00
|
|
|
}
|
|
|
|
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
int bt_mesh_model_publish(struct bt_mesh_model *model)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
struct bt_mesh_model_pub *pub = model->pub;
|
2021-03-08 10:15:03 +01:00
|
|
|
|
|
|
|
if (!pub) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("");
|
2017-11-09 20:35:19 +02:00
|
|
|
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
if (pub->addr == BT_MESH_ADDR_UNASSIGNED) {
|
2017-06-16 12:30:54 +03:00
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
if (!pub->msg || !pub->msg->len) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("No publication message");
|
2021-04-15 12:28:20 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pub->msg->len + BT_MESH_MIC_SHORT > BT_MESH_TX_SDU_MAX) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Message does not fit maximum SDU size");
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pub->count) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Clearing publish retransmit timer");
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
}
|
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
/* Account for initial transmission */
|
2021-11-05 16:25:51 +01:00
|
|
|
pub->count = BT_MESH_PUB_MSG_TOTAL(pub);
|
2021-12-15 09:58:53 +01:00
|
|
|
pub->period_start = k_uptime_get_32();
|
2017-11-16 19:15:18 +02:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Publish Retransmit Count %u Interval %ums", pub->count,
|
|
|
|
BT_MESH_PUB_TRANSMIT_INT(pub->retransmit));
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
|
2021-04-15 12:28:20 +02:00
|
|
|
k_work_reschedule(&pub->timer, K_NO_WAIT);
|
2017-11-16 19:15:18 +02:00
|
|
|
|
Bluetooth: Mesh: Fix model publication
Model publication was broken in a couple of ways:
- The Publish Retransmit State was not taken into account at all
- Health Server used a single publish state for all elements
To implement Publish Retransmit properly, one has to use a callback to
track when the message has been sent. The problem with the transport
layer sending APIs was that giving a callback would cause the
transport layer to assume that segmentation (with acks) is desired,
which is not the case for Model Publication (unless the message itself
is too large, of course). Because of this, the message sending context
receives a new send_rel ("Send Reliable") boolean member that an app
can use to force reliable sending.
Another challenge with the Publish Retransmit state is that a buffer
is needed for storing the AppKey-encrypted SDU once it has been sent
out for the first time.To solve this, a new new net_buf_simple member
is added to the model publication context. The separate 'msg' input
parameter of the bt_mesh_model_publish() API is removed, since the
application is now expected to pre-fill pub->msg instead.
To help with the publishing API change, the Health Server model gets a
new helper macro for initializing the publishing context with a
right-sized publishing message.
The API for creating Health Server instances is also redesigned since
it was so far using a single model publishing state, which would
result in erratic behavior in case of multiple elements with the
Health Server Model. Now, the application needs to provide a unique
publishing context for each Health Server instance.
The changes are heavily intertwined, so it's not easily possible to
split them into multiple patches, hence the large(ish) patch.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-11-18 10:24:18 +02:00
|
|
|
return 0;
|
2017-06-16 12:30:54 +03:00
|
|
|
}
|
|
|
|
|
2019-08-20 10:59:42 +02:00
|
|
|
struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t company, uint16_t id)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t i;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2018-11-29 11:23:03 -08:00
|
|
|
for (i = 0U; i < elem->vnd_model_count; i++) {
|
2017-06-16 12:30:54 +03:00
|
|
|
if (elem->vnd_models[i].vnd.company == company &&
|
|
|
|
elem->vnd_models[i].vnd.id == id) {
|
|
|
|
return &elem->vnd_models[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-08-20 10:59:42 +02:00
|
|
|
struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t id)
|
2017-06-16 12:30:54 +03:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t i;
|
2017-06-16 12:30:54 +03:00
|
|
|
|
2018-11-29 11:23:03 -08:00
|
|
|
for (i = 0U; i < elem->model_count; i++) {
|
2017-06-16 12:30:54 +03:00
|
|
|
if (elem->models[i].id == id) {
|
|
|
|
return &elem->models[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct bt_mesh_comp *bt_mesh_comp_get(void)
|
|
|
|
{
|
|
|
|
return dev_comp;
|
|
|
|
}
|
2019-10-18 13:23:06 +02:00
|
|
|
|
2021-07-26 16:16:01 +02:00
|
|
|
void bt_mesh_model_extensions_walk(struct bt_mesh_model *model,
|
|
|
|
enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod,
|
|
|
|
void *user_data),
|
|
|
|
void *user_data)
|
2019-10-18 13:23:06 +02:00
|
|
|
{
|
2021-07-26 16:16:01 +02:00
|
|
|
#ifndef CONFIG_BT_MESH_MODEL_EXTENSIONS
|
|
|
|
(void)cb(model, user_data);
|
|
|
|
return;
|
|
|
|
#else
|
|
|
|
struct bt_mesh_model *it;
|
2019-10-18 13:23:06 +02:00
|
|
|
|
2021-09-30 16:32:05 +02:00
|
|
|
if (cb(model, user_data) == BT_MESH_WALK_STOP || !model->next) {
|
2021-07-26 16:16:01 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-10-18 13:23:06 +02:00
|
|
|
|
2021-09-30 16:32:05 +02:00
|
|
|
/* List is circular. Step through all models until we reach the start: */
|
|
|
|
for (it = model->next; it != model; it = it->next) {
|
2021-07-26 16:16:01 +02:00
|
|
|
if (cb(it, user_data) == BT_MESH_WALK_STOP) {
|
2019-10-18 13:23:06 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-07-26 16:16:01 +02:00
|
|
|
}
|
2019-10-18 13:23:06 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS
|
2022-08-31 11:58:06 +02:00
|
|
|
static int mod_rel_register(struct bt_mesh_model *base,
|
|
|
|
struct bt_mesh_model *ext,
|
|
|
|
uint8_t type)
|
|
|
|
{
|
|
|
|
LOG_DBG("");
|
|
|
|
struct mod_relation extension = {
|
|
|
|
base->elem_idx,
|
|
|
|
base->mod_idx,
|
|
|
|
ext->elem_idx,
|
|
|
|
ext->mod_idx,
|
|
|
|
type,
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
|
2023-03-09 13:53:34 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(mod_rel_list); i++) {
|
2022-08-31 11:58:06 +02:00
|
|
|
if (mod_rel_list[i].elem_base == 0 &&
|
|
|
|
mod_rel_list[i].idx_base == 0 &&
|
|
|
|
mod_rel_list[i].elem_ext == 0 &&
|
|
|
|
mod_rel_list[i].idx_ext == 0) {
|
|
|
|
memcpy(&mod_rel_list[i], &extension,
|
|
|
|
sizeof(extension));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG_ERR("Failed to extend");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2021-07-26 16:16:01 +02:00
|
|
|
int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod)
|
|
|
|
{
|
|
|
|
struct bt_mesh_model *a = extending_mod;
|
|
|
|
struct bt_mesh_model *b = base_mod;
|
|
|
|
struct bt_mesh_model *a_next = a->next;
|
|
|
|
struct bt_mesh_model *b_next = b->next;
|
|
|
|
struct bt_mesh_model *it;
|
|
|
|
|
|
|
|
base_mod->flags |= BT_MESH_MOD_EXTENDED;
|
|
|
|
|
|
|
|
if (a == b) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if a's list contains b */
|
|
|
|
for (it = a; (it != NULL) && (it->next != a); it = it->next) {
|
|
|
|
if (it == b) {
|
|
|
|
return 0;
|
|
|
|
}
|
2019-10-18 13:23:06 +02:00
|
|
|
}
|
|
|
|
|
2021-07-26 16:16:01 +02:00
|
|
|
/* Merge lists */
|
|
|
|
if (a_next) {
|
|
|
|
b->next = a_next;
|
2019-10-18 13:23:06 +02:00
|
|
|
} else {
|
2021-07-26 16:16:01 +02:00
|
|
|
b->next = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b_next) {
|
|
|
|
a->next = b_next;
|
|
|
|
} else {
|
|
|
|
a->next = b;
|
2019-10-18 13:23:06 +02:00
|
|
|
}
|
|
|
|
|
2022-08-31 11:58:06 +02:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) {
|
|
|
|
return mod_rel_register(base_mod, extending_mod, RELATION_TYPE_EXT);
|
|
|
|
}
|
|
|
|
|
2019-10-18 13:23:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2022-08-31 11:58:06 +02:00
|
|
|
|
|
|
|
int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod,
|
|
|
|
struct bt_mesh_model *base_mod)
|
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
uint8_t cor_id = 0;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_MESH_COMP_PAGE_1)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOD_REL_LIST_FOR_EACH(i) {
|
|
|
|
if (mod_rel_list[i].type < RELATION_TYPE_EXT &&
|
|
|
|
mod_rel_list[i].type > cor_id) {
|
|
|
|
cor_id = mod_rel_list[i].type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((IS_MOD_BASE(base_mod, i) ||
|
|
|
|
IS_MOD_EXTENSION(base_mod, i) ||
|
|
|
|
IS_MOD_BASE(corresponding_mod, i) ||
|
|
|
|
IS_MOD_EXTENSION(corresponding_mod, i)) &&
|
|
|
|
mod_rel_list[i].type < RELATION_TYPE_EXT) {
|
|
|
|
return mod_rel_register(base_mod, corresponding_mod, mod_rel_list[i].type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = mod_rel_register(base_mod, corresponding_mod, cor_id);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_MESH_MODEL_EXTENSIONS */
|
2021-01-06 09:56:56 +01:00
|
|
|
|
2021-07-26 16:16:01 +02:00
|
|
|
bool bt_mesh_model_is_extended(struct bt_mesh_model *model)
|
|
|
|
{
|
|
|
|
return model->flags & BT_MESH_MOD_EXTENDED;
|
|
|
|
}
|
|
|
|
|
2021-01-06 09:56:56 +01:00
|
|
|
static int mod_set_bind(struct bt_mesh_model *mod, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
ssize_t len;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Start with empty array regardless of cleared or set value */
|
2022-11-02 19:31:26 +08:00
|
|
|
for (i = 0; i < mod->keys_cnt; i++) {
|
2021-01-06 09:56:56 +01:00
|
|
|
mod->keys[i] = BT_MESH_KEY_UNUSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len_rd == 0) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Cleared bindings for model");
|
2021-01-06 09:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
len = read_cb(cb_arg, mod->keys, mod->keys_cnt * sizeof(mod->keys[0]));
|
2021-01-06 09:56:56 +01:00
|
|
|
if (len < 0) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to read value (err %zd)", len);
|
2021-01-06 09:56:56 +01:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2022-10-24 11:23:12 +02:00
|
|
|
LOG_HEXDUMP_DBG(mod->keys, len, "val");
|
2021-01-06 09:56:56 +01:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Decoded %zu bound keys for model", len / sizeof(mod->keys[0]));
|
2021-01-06 09:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
2022-11-02 19:31:26 +08:00
|
|
|
size_t size = mod->groups_cnt * sizeof(mod->groups[0]);
|
2021-01-06 09:56:56 +01:00
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
/* Start with empty array regardless of cleared or set value */
|
2022-11-02 19:31:26 +08:00
|
|
|
(void)memset(mod->groups, 0, size);
|
2021-01-06 09:56:56 +01:00
|
|
|
|
|
|
|
if (len_rd == 0) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Cleared subscriptions for model");
|
2021-01-06 09:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
len = read_cb(cb_arg, mod->groups, size);
|
2021-01-06 09:56:56 +01:00
|
|
|
if (len < 0) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to read value (err %zd)", len);
|
2021-01-06 09:56:56 +01:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2022-10-24 11:23:12 +02:00
|
|
|
LOG_HEXDUMP_DBG(mod->groups, len, "val");
|
2021-01-06 09:56:56 +01:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Decoded %zu subscribed group addresses for model", len / sizeof(mod->groups[0]));
|
2021-01-06 09:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct mod_pub_val pub;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!mod->pub) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Model has no publication context!");
|
2021-01-06 09:56:56 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len_rd == 0) {
|
|
|
|
mod->pub->addr = BT_MESH_ADDR_UNASSIGNED;
|
|
|
|
mod->pub->key = 0U;
|
|
|
|
mod->pub->cred = 0U;
|
|
|
|
mod->pub->ttl = 0U;
|
|
|
|
mod->pub->period = 0U;
|
|
|
|
mod->pub->retransmit = 0U;
|
|
|
|
mod->pub->count = 0U;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Cleared publication for model");
|
2021-01-06 09:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub));
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to set \'model-pub\'");
|
2021-01-06 09:56:56 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mod->pub->addr = pub.addr;
|
|
|
|
mod->pub->key = pub.key;
|
|
|
|
mod->pub->cred = pub.cred;
|
|
|
|
mod->pub->ttl = pub.ttl;
|
|
|
|
mod->pub->period = pub.period;
|
|
|
|
mod->pub->retransmit = pub.retransmit;
|
2021-03-12 10:56:12 +01:00
|
|
|
mod->pub->period_div = pub.period_div;
|
2021-01-06 09:56:56 +01:00
|
|
|
mod->pub->count = 0U;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.addr, pub.key);
|
2021-01-06 09:56:56 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mod_data_set(struct bt_mesh_model *mod,
|
|
|
|
const char *name, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
const char *next;
|
|
|
|
|
|
|
|
settings_name_next(name, &next);
|
|
|
|
|
|
|
|
if (mod->cb && mod->cb->settings_set) {
|
|
|
|
return mod->cb->settings_set(mod, next, len_rd,
|
|
|
|
read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mod_set(bool vnd, const char *name, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct bt_mesh_model *mod;
|
|
|
|
uint8_t elem_idx, mod_idx;
|
|
|
|
uint16_t mod_key;
|
|
|
|
int len;
|
|
|
|
const char *next;
|
|
|
|
|
|
|
|
if (!name) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Insufficient number of arguments");
|
2021-01-06 09:56:56 +01:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
mod_key = strtol(name, NULL, 16);
|
|
|
|
elem_idx = mod_key >> 8;
|
|
|
|
mod_idx = mod_key;
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u", mod_key, elem_idx, mod_idx);
|
2021-01-06 09:56:56 +01:00
|
|
|
|
|
|
|
mod = bt_mesh_model_get(vnd, elem_idx, mod_idx);
|
|
|
|
if (!mod) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to get model for elem_idx %u mod_idx %u", elem_idx, mod_idx);
|
2021-01-06 09:56:56 +01:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = settings_name_next(name, &next);
|
|
|
|
|
|
|
|
if (!next) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Insufficient number of arguments");
|
2021-01-06 09:56:56 +01:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(next, "bind", len)) {
|
|
|
|
return mod_set_bind(mod, len_rd, read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(next, "sub", len)) {
|
|
|
|
return mod_set_sub(mod, len_rd, read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(next, "pub", len)) {
|
|
|
|
return mod_set_pub(mod, len_rd, read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(next, "data", len)) {
|
|
|
|
return mod_data_set(mod, next, len_rd, read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Unknown module key %s", next);
|
2021-01-06 09:56:56 +01:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sig_mod_set(const char *name, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
return mod_set(false, name, len_rd, read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_MESH_SETTINGS_DEFINE(sig_mod, "s", sig_mod_set);
|
|
|
|
|
|
|
|
static int vnd_mod_set(const char *name, size_t len_rd,
|
|
|
|
settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
return mod_set(true, name, len_rd, read_cb, cb_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_MESH_SETTINGS_DEFINE(vnd_mod, "v", vnd_mod_set);
|
|
|
|
|
2020-03-13 15:58:47 +01:00
|
|
|
static int comp_set(const char *name, size_t len_rd, settings_read_cb read_cb,
|
|
|
|
void *cb_arg)
|
|
|
|
{
|
|
|
|
/* Only need to know that the entry exists. Will load the contents on
|
|
|
|
* demand.
|
|
|
|
*/
|
|
|
|
if (len_rd > 0) {
|
|
|
|
atomic_set_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
BT_MESH_SETTINGS_DEFINE(comp, "cmp", comp_set);
|
|
|
|
|
2021-01-06 09:56:56 +01:00
|
|
|
static void encode_mod_path(struct bt_mesh_model *mod, bool vnd,
|
|
|
|
const char *key, char *path, size_t path_len)
|
|
|
|
{
|
|
|
|
uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx);
|
|
|
|
|
|
|
|
if (vnd) {
|
|
|
|
snprintk(path, path_len, "bt/mesh/v/%x/%s", mod_key, key);
|
|
|
|
} else {
|
|
|
|
snprintk(path, path_len, "bt/mesh/s/%x/%s", mod_key, key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd)
|
|
|
|
{
|
|
|
|
uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
|
|
|
|
char path[20];
|
|
|
|
int i, count, err;
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
for (i = 0, count = 0; i < mod->keys_cnt; i++) {
|
2021-01-06 09:56:56 +01:00
|
|
|
if (mod->keys[i] != BT_MESH_KEY_UNUSED) {
|
|
|
|
keys[count++] = mod->keys[i];
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("model key 0x%04x", mod->keys[i]);
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
encode_mod_path(mod, vnd, "bind", path, sizeof(path));
|
|
|
|
|
|
|
|
if (count) {
|
|
|
|
err = settings_save_one(path, keys, count * sizeof(keys[0]));
|
|
|
|
} else {
|
|
|
|
err = settings_delete(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to store %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Stored %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
|
|
|
|
{
|
|
|
|
uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
|
|
|
|
char path[20];
|
|
|
|
int i, count, err;
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
for (i = 0, count = 0; i < mod->groups_cnt; i++) {
|
2021-01-06 09:56:56 +01:00
|
|
|
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
|
|
|
groups[count++] = mod->groups[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
encode_mod_path(mod, vnd, "sub", path, sizeof(path));
|
|
|
|
|
|
|
|
if (count) {
|
|
|
|
err = settings_save_one(path, groups,
|
|
|
|
count * sizeof(groups[0]));
|
|
|
|
} else {
|
|
|
|
err = settings_delete(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to store %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Stored %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
|
|
|
|
{
|
2023-02-14 16:10:58 +01:00
|
|
|
struct mod_pub_val pub = {0};
|
2021-01-06 09:56:56 +01:00
|
|
|
char path[20];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
encode_mod_path(mod, vnd, "pub", path, sizeof(path));
|
|
|
|
|
|
|
|
if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
|
|
|
|
err = settings_delete(path);
|
|
|
|
} else {
|
|
|
|
pub.addr = mod->pub->addr;
|
|
|
|
pub.key = mod->pub->key;
|
|
|
|
pub.ttl = mod->pub->ttl;
|
|
|
|
pub.retransmit = mod->pub->retransmit;
|
|
|
|
pub.period = mod->pub->period;
|
|
|
|
pub.period_div = mod->pub->period_div;
|
|
|
|
pub.cred = mod->pub->cred;
|
|
|
|
|
|
|
|
err = settings_save_one(path, &pub, sizeof(pub));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to store %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Stored %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void store_pending_mod(struct bt_mesh_model *mod,
|
|
|
|
struct bt_mesh_elem *elem, bool vnd,
|
|
|
|
bool primary, void *user_data)
|
|
|
|
{
|
|
|
|
if (!mod->flags) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mod->flags & BT_MESH_MOD_BIND_PENDING) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mod->flags & BT_MESH_MOD_PUB_PENDING) {
|
|
|
|
mod->flags &= ~BT_MESH_MOD_PUB_PENDING;
|
|
|
|
store_pending_mod_pub(mod, vnd);
|
|
|
|
}
|
2023-04-20 18:09:02 +02:00
|
|
|
|
|
|
|
if (mod->flags & BT_MESH_MOD_DATA_PENDING) {
|
|
|
|
mod->flags &= ~BT_MESH_MOD_DATA_PENDING;
|
|
|
|
mod->cb->pending_store(mod);
|
|
|
|
}
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_model_pending_store(void)
|
|
|
|
{
|
|
|
|
bt_mesh_model_foreach(store_pending_mod, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_model_bind_store(struct bt_mesh_model *mod)
|
|
|
|
{
|
|
|
|
mod->flags |= BT_MESH_MOD_BIND_PENDING;
|
|
|
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_model_sub_store(struct bt_mesh_model *mod)
|
|
|
|
{
|
|
|
|
mod->flags |= BT_MESH_MOD_SUB_PENDING;
|
|
|
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_model_pub_store(struct bt_mesh_model *mod)
|
|
|
|
{
|
|
|
|
mod->flags |= BT_MESH_MOD_PUB_PENDING;
|
|
|
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
|
|
|
}
|
|
|
|
|
2020-03-13 15:58:47 +01:00
|
|
|
int bt_mesh_comp_store(void)
|
|
|
|
{
|
|
|
|
NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX);
|
|
|
|
int err;
|
|
|
|
|
2021-02-03 15:32:52 +01:00
|
|
|
err = bt_mesh_comp_data_get_page_0(&buf, 0);
|
2020-03-13 15:58:47 +01:00
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to read composition data: %d", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = settings_save_one("bt/mesh/cmp", buf.data, buf.len);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to store composition data: %d", err);
|
|
|
|
} else {
|
|
|
|
LOG_DBG("Stored composition data");
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_comp_change_prepare(void)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bt_mesh_comp_store();
|
|
|
|
}
|
|
|
|
|
2023-04-27 09:47:34 +02:00
|
|
|
static void comp_data_clear(void)
|
2020-03-13 15:58:47 +01:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = settings_delete("bt/mesh/cmp");
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to clear composition data: %d", err);
|
|
|
|
} else {
|
|
|
|
LOG_DBG("Cleared composition data page 128");
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_clear_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_comp_cb(const char *key, size_t len, settings_read_cb read_cb,
|
|
|
|
void *cb_arg, void *param)
|
|
|
|
{
|
|
|
|
struct net_buf_simple *buf = param;
|
|
|
|
|
|
|
|
if (len > net_buf_simple_tailroom(buf)) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = read_cb(cb_arg, net_buf_simple_tail(buf), len);
|
|
|
|
if (len > 0) {
|
|
|
|
net_buf_simple_add(buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_comp_read(struct net_buf_simple *buf)
|
|
|
|
{
|
|
|
|
size_t original_len = buf->len;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = settings_load_subtree_direct("bt/mesh/cmp", read_comp_cb, buf);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed reading composition data: %d", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf->len == original_len) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-06 09:56:56 +01:00
|
|
|
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
|
|
|
|
const char *name, const void *data,
|
|
|
|
size_t data_len)
|
|
|
|
{
|
|
|
|
char path[30];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
encode_mod_path(mod, vnd, "data", path, sizeof(path));
|
|
|
|
if (name) {
|
|
|
|
strcat(path, "/");
|
2021-08-10 16:41:25 +02:00
|
|
|
strncat(path, name, SETTINGS_MAX_DIR_DEPTH);
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (data_len) {
|
|
|
|
err = settings_save_one(path, data, data_len);
|
|
|
|
} else {
|
|
|
|
err = settings_delete(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed to store %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
} else {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Stored %s value", path);
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
|
|
|
|
static int metadata_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
/* Only need to know that the entry exists. Will load the contents on
|
|
|
|
* demand.
|
|
|
|
*/
|
|
|
|
if (len_rd > 0) {
|
|
|
|
atomic_set_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
BT_MESH_SETTINGS_DEFINE(metadata, "metadata", metadata_set);
|
|
|
|
|
|
|
|
int bt_mesh_models_metadata_store(void)
|
|
|
|
{
|
|
|
|
NET_BUF_SIMPLE_DEFINE(buf, CONFIG_BT_MESH_MODELS_METADATA_PAGE_LEN);
|
|
|
|
size_t total_size;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
total_size = bt_mesh_metadata_page_0_size();
|
|
|
|
LOG_DBG("bt/mesh/metadata total %d", total_size);
|
|
|
|
|
|
|
|
net_buf_simple_init(&buf, 0);
|
|
|
|
net_buf_simple_add_le16(&buf, total_size);
|
|
|
|
|
|
|
|
err = bt_mesh_metadata_get_page_0(&buf, 0);
|
|
|
|
if (err == -E2BIG) {
|
|
|
|
LOG_ERR("Metadata too large");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to read models metadata: %d", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("bt/mesh/metadata len %d", buf.len);
|
|
|
|
|
|
|
|
err = settings_save_one("bt/mesh/metadata", buf.data, buf.len);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to store models metadata: %d", err);
|
|
|
|
} else {
|
|
|
|
LOG_DBG("Stored models metadata");
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_models_metadata_read(struct net_buf_simple *buf, size_t offset)
|
|
|
|
{
|
|
|
|
NET_BUF_SIMPLE_DEFINE(stored_buf, CONFIG_BT_MESH_MODELS_METADATA_PAGE_LEN);
|
|
|
|
size_t original_len = buf->len;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_simple_init(&stored_buf, 0);
|
|
|
|
|
|
|
|
err = settings_load_subtree_direct("bt/mesh/metadata", read_comp_cb, &stored_buf);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed reading models metadata: %d", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First two bytes are total length */
|
|
|
|
offset += 2;
|
|
|
|
|
|
|
|
net_buf_simple_add_mem(buf, &stored_buf.data, MIN(net_buf_simple_tailroom(buf), 2));
|
|
|
|
|
|
|
|
if (offset >= stored_buf.len) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_buf_simple_add_mem(buf, &stored_buf.data[offset],
|
|
|
|
MIN(net_buf_simple_tailroom(buf), stored_buf.len - offset));
|
|
|
|
|
|
|
|
LOG_DBG("metadata read %d", buf->len);
|
|
|
|
|
|
|
|
if (buf->len == original_len) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-04-27 09:47:34 +02:00
|
|
|
static void models_metadata_clear(void)
|
2022-07-20 13:26:32 +02:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = settings_delete("bt/mesh/metadata");
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to clear models metadata: %d", err);
|
|
|
|
} else {
|
|
|
|
LOG_DBG("Cleared models metadata");
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_clear_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY);
|
|
|
|
}
|
|
|
|
|
2023-04-27 09:47:34 +02:00
|
|
|
void bt_mesh_comp_data_pending_clear(void)
|
|
|
|
{
|
|
|
|
comp_data_clear();
|
|
|
|
models_metadata_clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_comp_data_clear(void)
|
|
|
|
{
|
|
|
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_COMP_PENDING);
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:26:32 +02:00
|
|
|
int bt_mesh_models_metadata_change_prepare(void)
|
|
|
|
{
|
|
|
|
#if !IS_ENABLED(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
return bt_mesh_models_metadata_store();
|
|
|
|
}
|
|
|
|
|
2021-01-06 09:56:56 +01:00
|
|
|
static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|
|
|
bool vnd, bool primary, void *user_data)
|
|
|
|
{
|
|
|
|
if (mod->pub && mod->pub->update &&
|
|
|
|
mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
|
|
|
|
int32_t ms = bt_mesh_model_pub_period_get(mod);
|
|
|
|
|
|
|
|
if (ms > 0) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Starting publish timer (period %u ms)", ms);
|
2021-04-15 12:28:20 +02:00
|
|
|
k_work_schedule(&mod->pub->timer, K_MSEC(ms));
|
2021-01-06 09:56:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-02 19:31:26 +08:00
|
|
|
for (int i = 0; i < mod->groups_cnt; i++) {
|
2021-01-06 09:56:56 +01:00
|
|
|
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
|
|
|
bt_mesh_lpn_group_add(mod->groups[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_mesh_model_settings_commit(void)
|
|
|
|
{
|
|
|
|
bt_mesh_model_foreach(commit_mod, NULL);
|
|
|
|
}
|
2023-04-20 18:09:02 +02:00
|
|
|
|
|
|
|
void bt_mesh_model_data_store_schedule(struct bt_mesh_model *mod)
|
|
|
|
{
|
|
|
|
mod->flags |= BT_MESH_MOD_DATA_PENDING;
|
|
|
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
|
|
|
}
|