190 lines
5.1 KiB
C
190 lines
5.1 KiB
C
/*
|
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <zephyr/types.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
#include <zephyr/bluetooth/conn.h>
|
|
#include <zephyr/bluetooth/mesh.h>
|
|
|
|
#include <common/bt_str.h>
|
|
|
|
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(bt_mesh_large_comp_data_srv);
|
|
|
|
#include "access.h"
|
|
#include "cfg.h"
|
|
#include "foundation.h"
|
|
#include "net.h"
|
|
#include "mesh.h"
|
|
#include "transport.h"
|
|
|
|
#define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff)
|
|
#define BT_MESH_MODEL_PAYLOAD_MAX \
|
|
(BT_MESH_TX_SDU_MAX - BT_MESH_MODEL_OP_LEN(DUMMY_2_BYTE_OP) - \
|
|
BT_MESH_MIC_SHORT)
|
|
|
|
/** Mesh Large Composition Data Server Model Context */
|
|
static struct bt_mesh_large_comp_data_srv {
|
|
/** Composition data model entry pointer. */
|
|
const struct bt_mesh_model *model;
|
|
} srv;
|
|
|
|
static int handle_large_comp_data_get(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
BT_MESH_MODEL_BUF_DEFINE(rsp, OP_LARGE_COMP_DATA_STATUS,
|
|
BT_MESH_MODEL_PAYLOAD_MAX);
|
|
uint8_t page;
|
|
size_t offset, total_size;
|
|
int err;
|
|
|
|
LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
|
|
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
|
|
bt_hex(buf->data, buf->len));
|
|
|
|
page = bt_mesh_comp_parse_page(buf);
|
|
offset = net_buf_simple_pull_le16(buf);
|
|
|
|
LOG_DBG("page %u offset %u", page, offset);
|
|
|
|
bt_mesh_model_msg_init(&rsp, OP_LARGE_COMP_DATA_STATUS);
|
|
net_buf_simple_add_u8(&rsp, page);
|
|
net_buf_simple_add_le16(&rsp, offset);
|
|
|
|
if (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) && page < 128) {
|
|
size_t msg_space;
|
|
|
|
NET_BUF_SIMPLE_DEFINE(temp_buf, CONFIG_BT_MESH_COMP_PST_BUF_SIZE);
|
|
err = bt_mesh_comp_read(&temp_buf, page);
|
|
if (err) {
|
|
LOG_ERR("Could not read comp data p%d, err: %d", page, err);
|
|
return err;
|
|
}
|
|
|
|
net_buf_simple_add_le16(&rsp, temp_buf.len);
|
|
if (offset > temp_buf.len) {
|
|
return 0;
|
|
}
|
|
|
|
msg_space = net_buf_simple_tailroom(&rsp) - BT_MESH_MIC_SHORT;
|
|
net_buf_simple_add_mem(
|
|
&rsp, temp_buf.data + offset,
|
|
(msg_space < (temp_buf.len - offset)) ? msg_space : temp_buf.len - offset);
|
|
} else {
|
|
total_size = bt_mesh_comp_page_size(page);
|
|
net_buf_simple_add_le16(&rsp, total_size);
|
|
|
|
if (offset < total_size) {
|
|
err = bt_mesh_comp_data_get_page(&rsp, page, offset);
|
|
if (err && err != -E2BIG) {
|
|
LOG_ERR("Could not read comp data p%d, err: %d", page, err);
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
|
|
LOG_ERR("Unable to send Large Composition Data Status");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_models_metadata_get(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
BT_MESH_MODEL_BUF_DEFINE(rsp, OP_MODELS_METADATA_STATUS,
|
|
BT_MESH_MODEL_PAYLOAD_MAX);
|
|
size_t offset, total_size;
|
|
uint8_t page;
|
|
int err;
|
|
|
|
LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
|
|
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
|
|
bt_hex(buf->data, buf->len));
|
|
|
|
page = net_buf_simple_pull_u8(buf);
|
|
offset = net_buf_simple_pull_le16(buf);
|
|
|
|
LOG_DBG("page %u offset %u", page, offset);
|
|
|
|
if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY)) {
|
|
LOG_DBG("Models Metadata Page 128");
|
|
page = 128U;
|
|
} else if (page != 0U) {
|
|
LOG_DBG("Models Metadata Page %u not available", page);
|
|
page = 0U;
|
|
}
|
|
|
|
bt_mesh_model_msg_init(&rsp, OP_MODELS_METADATA_STATUS);
|
|
net_buf_simple_add_u8(&rsp, page);
|
|
net_buf_simple_add_le16(&rsp, offset);
|
|
|
|
if (atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY) == (page == 0U)) {
|
|
rsp.size -= BT_MESH_MIC_SHORT;
|
|
err = bt_mesh_models_metadata_read(&rsp, offset);
|
|
if (err) {
|
|
LOG_ERR("Unable to get stored models metadata");
|
|
return err;
|
|
}
|
|
|
|
rsp.size += BT_MESH_MIC_SHORT;
|
|
} else {
|
|
total_size = bt_mesh_metadata_page_0_size();
|
|
net_buf_simple_add_le16(&rsp, total_size);
|
|
|
|
if (offset < total_size) {
|
|
err = bt_mesh_metadata_get_page_0(&rsp, offset);
|
|
if (err && err != -E2BIG) {
|
|
LOG_ERR("Failed to get Models Metadata Page 0: %d", err);
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
|
|
LOG_ERR("Unable to send Models Metadata Status");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct bt_mesh_model_op _bt_mesh_large_comp_data_srv_op[] = {
|
|
{ OP_LARGE_COMP_DATA_GET, BT_MESH_LEN_EXACT(3), handle_large_comp_data_get },
|
|
{ OP_MODELS_METADATA_GET, BT_MESH_LEN_EXACT(3), handle_models_metadata_get },
|
|
BT_MESH_MODEL_OP_END,
|
|
};
|
|
|
|
static int large_comp_data_srv_init(const struct bt_mesh_model *model)
|
|
{
|
|
if (!bt_mesh_model_in_primary(model)) {
|
|
LOG_ERR("Large Composition Data Server only allowed in primary element");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Large Composition Data Server model shall use the device key */
|
|
model->keys[0] = BT_MESH_KEY_DEV;
|
|
model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY;
|
|
|
|
srv.model = model;
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct bt_mesh_model_cb _bt_mesh_large_comp_data_srv_cb = {
|
|
.init = large_comp_data_srv_init,
|
|
};
|