zephyr/subsys/bluetooth/mesh/large_comp_data_cli.c
Michał Narajowski df65592d94 Bluetooth: Mesh: Add support for Large Composition Data models
- Adds Large Composition Data Server and Client definitions
- Adds Client API definition
- Adds Health Server Metadata definition
- Refactors Composition Data processing (as a Server) to use common
 methods with Large Comp Data Server

Co-authored-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
Co-authored-by: Stine Akredalen <stine.akredalen@nordicsemi.no>
Co-authored-by: Omkar Kulkarni <omkar.kulkarni@nordicsemi.no>
Signed-off-by: Michał Narajowski <michal.narajowski@codecoup.pl>
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2023-03-06 13:52:15 +01:00

184 lines
4.7 KiB
C

/* Bluetooth Mesh */
/*
* 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_cli);
#include "net.h"
#include "access.h"
#include "foundation.h"
/** Mesh Large Composition Data Client Model Context */
static struct bt_mesh_large_comp_data_cli {
/** Composition data model entry pointer. */
struct bt_mesh_model *model;
/* Internal parameters for tracking message responses. */
struct bt_mesh_msg_ack_ctx ack_ctx;
} cli;
static int32_t msg_timeout;
static int large_comp_data_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *comp;
size_t to_copy;
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));
if (!bt_mesh_msg_ack_ctx_match(&cli.ack_ctx, OP_LARGE_COMP_DATA_STATUS,
ctx->addr, (void **)&comp)) {
return 0;
}
to_copy = MIN(net_buf_simple_tailroom(comp), buf->len);
net_buf_simple_add_mem(comp, buf->data, to_copy);
bt_mesh_msg_ack_ctx_rx(&cli.ack_ctx);
return 0;
}
static int models_metadata_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *metadata;
size_t to_copy;
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));
if (!bt_mesh_msg_ack_ctx_match(&cli.ack_ctx, OP_MODELS_METADATA_STATUS,
ctx->addr, (void **)&metadata)) {
return 0;
}
metadata = (struct net_buf_simple *)cli.ack_ctx.user_data;
to_copy = MIN(net_buf_simple_tailroom(metadata), buf->len);
net_buf_simple_add_mem(metadata, buf->data, to_copy);
bt_mesh_msg_ack_ctx_rx(&cli.ack_ctx);
return 0;
}
const struct bt_mesh_model_op _bt_mesh_large_comp_data_cli_op[] = {
{ OP_LARGE_COMP_DATA_STATUS, BT_MESH_LEN_MIN(5), large_comp_data_status },
{ OP_MODELS_METADATA_STATUS, BT_MESH_LEN_MIN(5), models_metadata_status },
BT_MESH_MODEL_OP_END,
};
static int large_comp_data_cli_init(struct bt_mesh_model *model)
{
if (!bt_mesh_model_in_primary(model)) {
LOG_ERR("Configuration Client only allowed in primary element");
return -EINVAL;
}
model->keys[0] = BT_MESH_KEY_DEV_ANY;
model->flags |= BT_MESH_MOD_DEVKEY_ONLY;
cli.model = model;
msg_timeout = 5000;
bt_mesh_msg_ack_ctx_init(&cli.ack_ctx);
return 0;
}
const struct bt_mesh_model_cb _bt_mesh_large_comp_data_cli_cb = {
.init = large_comp_data_cli_init,
};
static int cli_prepare(void *param, uint32_t op, uint16_t addr)
{
return bt_mesh_msg_ack_ctx_prepare(&cli.ack_ctx, op, addr, param);
}
int bt_mesh_large_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page,
size_t offset, struct net_buf_simple *comp)
{
BT_MESH_MODEL_BUF_DEFINE(msg, OP_LARGE_COMP_DATA_GET, 3);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
int err;
err = cli_prepare(comp, OP_LARGE_COMP_DATA_STATUS, addr);
if (err) {
return err;
}
bt_mesh_model_msg_init(&msg, OP_LARGE_COMP_DATA_GET);
net_buf_simple_add_u8(&msg, page);
net_buf_simple_add_le16(&msg, offset);
err = bt_mesh_model_send(cli.model, &ctx, &msg, NULL, NULL);
if (err) {
LOG_ERR("model_send() failed (err %d)", err);
bt_mesh_msg_ack_ctx_clear(&cli.ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli.ack_ctx, K_MSEC(msg_timeout));
}
int bt_mesh_models_metadata_get(uint16_t net_idx, uint16_t addr, uint8_t page,
size_t offset, struct net_buf_simple *metadata)
{
BT_MESH_MODEL_BUF_DEFINE(msg, OP_MODELS_METADATA_STATUS, 3);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
int err;
err = cli_prepare(metadata, OP_MODELS_METADATA_STATUS, addr);
if (err) {
return err;
}
bt_mesh_model_msg_init(&msg, OP_MODELS_METADATA_GET);
net_buf_simple_add_u8(&msg, page);
net_buf_simple_add_le16(&msg, offset);
err = bt_mesh_model_send(cli.model, &ctx, &msg, NULL, NULL);
if (err) {
LOG_ERR("model_send() failed (err %d)", err);
bt_mesh_msg_ack_ctx_clear(&cli.ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli.ack_ctx, K_MSEC(msg_timeout));
}