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>
This commit is contained in:
parent
316d7fcd57
commit
df65592d94
14 changed files with 963 additions and 79 deletions
|
@ -34,5 +34,7 @@
|
||||||
#include <zephyr/bluetooth/mesh/cdb.h>
|
#include <zephyr/bluetooth/mesh/cdb.h>
|
||||||
#include <zephyr/bluetooth/mesh/rpr_cli.h>
|
#include <zephyr/bluetooth/mesh/rpr_cli.h>
|
||||||
#include <zephyr/bluetooth/mesh/rpr_srv.h>
|
#include <zephyr/bluetooth/mesh/rpr_srv.h>
|
||||||
|
#include <zephyr/bluetooth/mesh/large_comp_data_srv.h>
|
||||||
|
#include <zephyr/bluetooth/mesh/large_comp_data_cli.h>
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */
|
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */
|
||||||
|
|
|
@ -128,6 +128,8 @@ struct bt_mesh_elem {
|
||||||
#define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003
|
#define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003
|
||||||
#define BT_MESH_MODEL_ID_REMOTE_PROV_SRV 0x0004
|
#define BT_MESH_MODEL_ID_REMOTE_PROV_SRV 0x0004
|
||||||
#define BT_MESH_MODEL_ID_REMOTE_PROV_CLI 0x0005
|
#define BT_MESH_MODEL_ID_REMOTE_PROV_CLI 0x0005
|
||||||
|
#define BT_MESH_MODEL_ID_LARGE_COMP_DATA_SRV 0x0012
|
||||||
|
#define BT_MESH_MODEL_ID_LARGE_COMP_DATA_CLI 0x0013
|
||||||
|
|
||||||
/* Models from the Mesh Model Specification */
|
/* Models from the Mesh Model Specification */
|
||||||
#define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000
|
#define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000
|
||||||
|
@ -306,6 +308,37 @@ struct bt_mesh_model_op {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
* @brief Composition data SIG model entry with callback functions and metadata.
|
||||||
|
*
|
||||||
|
* @param _id Model ID.
|
||||||
|
* @param _op Array of model opcode handlers.
|
||||||
|
* @param _pub Model publish parameters.
|
||||||
|
* @param _user_data User data for the model.
|
||||||
|
* @param _cb Callback structure, or NULL to keep no callbacks.
|
||||||
|
* @param _metadata Metadata structure.
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV)
|
||||||
|
#define BT_MESH_MODEL_METADATA_CB(_id, _op, _pub, _user_data, _cb, _metadata) \
|
||||||
|
{ \
|
||||||
|
.id = (_id), \
|
||||||
|
.pub = _pub, \
|
||||||
|
.keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \
|
||||||
|
.keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
||||||
|
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \
|
||||||
|
.groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \
|
||||||
|
.op = _op, \
|
||||||
|
.cb = _cb, \
|
||||||
|
.user_data = _user_data, \
|
||||||
|
.metadata = _metadata, \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define BT_MESH_MODEL_METADATA_CB(_id, _op, _pub, _user_data, _cb, _metadata) \
|
||||||
|
BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, _cb)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
* @brief Composition data vendor model entry with callback functions.
|
* @brief Composition data vendor model entry with callback functions.
|
||||||
*
|
*
|
||||||
* @param _company Company ID.
|
* @param _company Company ID.
|
||||||
|
@ -320,6 +353,33 @@ struct bt_mesh_model_op {
|
||||||
CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
||||||
CONFIG_BT_MESH_MODEL_GROUP_COUNT, _cb)
|
CONFIG_BT_MESH_MODEL_GROUP_COUNT, _cb)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Composition data vendor model entry with callback functions and metadata.
|
||||||
|
*
|
||||||
|
* @param _company Company ID.
|
||||||
|
* @param _id Model ID.
|
||||||
|
* @param _op Array of model opcode handlers.
|
||||||
|
* @param _pub Model publish parameters.
|
||||||
|
* @param _user_data User data for the model.
|
||||||
|
* @param _cb Callback structure, or NULL to keep no callbacks.
|
||||||
|
* @param _metadata Metadata structure.
|
||||||
|
*/
|
||||||
|
#define BT_MESH_MODEL_VND_METADATA_CB(_company, _id, _op, _pub, _user_data, _cb, _metadata) \
|
||||||
|
{ \
|
||||||
|
.vnd.company = (_company), \
|
||||||
|
.vnd.id = (_id), \
|
||||||
|
.op = _op, \
|
||||||
|
.pub = _pub, \
|
||||||
|
.keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \
|
||||||
|
.keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
||||||
|
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \
|
||||||
|
.groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \
|
||||||
|
.user_data = _user_data, \
|
||||||
|
.cb = _cb, \
|
||||||
|
.metadata = _metadata, \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Composition data SIG model entry.
|
* @brief Composition data SIG model entry.
|
||||||
*
|
*
|
||||||
|
@ -496,6 +556,41 @@ struct bt_mesh_model_pub {
|
||||||
.update = _update, \
|
.update = _update, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Models Metadata Entry struct
|
||||||
|
*
|
||||||
|
* The struct should primarily be created using the
|
||||||
|
* BT_MESH_MODELS_METADATA_ENTRY macro.
|
||||||
|
*/
|
||||||
|
struct bt_mesh_models_metadata_entry {
|
||||||
|
/* Length of the metadata */
|
||||||
|
const uint16_t len;
|
||||||
|
|
||||||
|
/* ID of the metadata */
|
||||||
|
const uint16_t id;
|
||||||
|
|
||||||
|
/* Pointer to raw data */
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Initialize a Models Metadata entry structure in a list.
|
||||||
|
*
|
||||||
|
* @param _len Length of the metadata entry.
|
||||||
|
* @param _id ID of the Models Metadata entry.
|
||||||
|
* @param _data Pointer to a contiguous memory that contains the metadata.
|
||||||
|
*/
|
||||||
|
#define BT_MESH_MODELS_METADATA_ENTRY(_len, _id, _data) \
|
||||||
|
{ \
|
||||||
|
.len = (_len), .id = _id, .data = _data, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper to define an empty Models metadata array */
|
||||||
|
#define BT_MESH_MODELS_METADATA_NONE NULL
|
||||||
|
|
||||||
|
/** End of the Models Metadata list. Must always be present. */
|
||||||
|
#define BT_MESH_MODELS_METADATA_END { 0, 0, NULL }
|
||||||
|
|
||||||
/** Model callback functions. */
|
/** Model callback functions. */
|
||||||
struct bt_mesh_model_cb {
|
struct bt_mesh_model_cb {
|
||||||
/** @brief Set value handler of user data tied to the model.
|
/** @brief Set value handler of user data tied to the model.
|
||||||
|
@ -600,6 +695,11 @@ struct bt_mesh_model {
|
||||||
struct bt_mesh_model *next;
|
struct bt_mesh_model *next;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV
|
||||||
|
/* Pointer to the array of model metadata entries. */
|
||||||
|
struct bt_mesh_models_metadata_entry **metadata;
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Model-specific user data */
|
/** Model-specific user data */
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
|
@ -153,6 +153,11 @@ struct bt_mesh_health_srv {
|
||||||
|
|
||||||
/** Attention Timer state */
|
/** Attention Timer state */
|
||||||
struct k_work_delayable attn_timer;
|
struct k_work_delayable attn_timer;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV
|
||||||
|
/** Pointer to the array with Health Test Info Metadata */
|
||||||
|
struct bt_mesh_models_metadata_entry *metadata;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,9 +171,41 @@ struct bt_mesh_health_srv {
|
||||||
*
|
*
|
||||||
* @return New mesh model instance.
|
* @return New mesh model instance.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV
|
||||||
|
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
|
||||||
|
BT_MESH_MODEL_METADATA_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \
|
||||||
|
pub, srv, &bt_mesh_health_srv_cb, &(srv)->metadata)
|
||||||
|
#else
|
||||||
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
|
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
|
||||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \
|
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \
|
||||||
pub, srv, &bt_mesh_health_srv_cb)
|
pub, srv, &bt_mesh_health_srv_cb)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Health Test Information Metadata ID.
|
||||||
|
*/
|
||||||
|
#define BT_MESH_HEALTH_TEST_INFO_METADATA_ID 0x0001
|
||||||
|
|
||||||
|
#define BT_MESH_HEALTH_TEST_INFO_METADATA(tests) \
|
||||||
|
{ \
|
||||||
|
.len = ARRAY_SIZE(tests), \
|
||||||
|
.id = BT_MESH_HEALTH_TEST_INFO_METADATA_ID, \
|
||||||
|
.data = tests, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Define a Health Test Info Metadata array.
|
||||||
|
*
|
||||||
|
* @param cid Company ID of the Health Test suite.
|
||||||
|
* @param tests A comma separated list of tests.
|
||||||
|
*
|
||||||
|
* @return A comma separated list of values that make Health Test Info Metadata
|
||||||
|
*/
|
||||||
|
#define BT_MESH_HEALTH_TEST_INFO(cid, tests...) \
|
||||||
|
(cid & 0xff), (cid >> 8), sizeof((uint8_t[]){ tests }), tests
|
||||||
|
|
||||||
|
|
||||||
/** @brief Notify the stack that the fault array state of the given element has
|
/** @brief Notify the stack that the fault array state of the given element has
|
||||||
* changed.
|
* changed.
|
||||||
|
|
71
include/zephyr/bluetooth/mesh/large_comp_data_cli.h
Normal file
71
include/zephyr/bluetooth/mesh/large_comp_data_cli.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @defgroup bt_mesh_large_comp_data_cli Large Composition Data Client model
|
||||||
|
* @{
|
||||||
|
* @brief API for the Large Composition Data Client model.
|
||||||
|
*/
|
||||||
|
#ifndef BT_MESH_LARGE_COMP_DATA_CLI_H__
|
||||||
|
#define BT_MESH_LARGE_COMP_DATA_CLI_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Large Composition Data Client model composition data entry.
|
||||||
|
*/
|
||||||
|
#define BT_MESH_MODEL_LARGE_COMP_DATA_CLI \
|
||||||
|
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_LARGE_COMP_DATA_CLI, \
|
||||||
|
_bt_mesh_large_comp_data_cli_op, NULL, NULL, \
|
||||||
|
&_bt_mesh_large_comp_data_cli_cb)
|
||||||
|
|
||||||
|
/** @brief Send Large Composition Data Get message.
|
||||||
|
*
|
||||||
|
* This API is used to read a portion of a page of the Composition Data.
|
||||||
|
*
|
||||||
|
* @param net_idx Network index to encrypt with.
|
||||||
|
* @param addr Target node element address.
|
||||||
|
* @param page Composition Data page to read.
|
||||||
|
* @param offset Offset within the Composition Data Page.
|
||||||
|
* @param comp Output buffer for storing received Composition data.
|
||||||
|
*
|
||||||
|
* @return 0 on success, or (negative) error code on failure.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
/** @brief Send Models Metadata Get message.
|
||||||
|
*
|
||||||
|
* This API is used to read a portion of a page of the Models Metadata state.
|
||||||
|
*
|
||||||
|
* @param net_idx Network index to encrypt with.
|
||||||
|
* @param addr Target node element address.
|
||||||
|
* @param page Models Metadata page to read.
|
||||||
|
* @param offset Offset within the Models Metadata Page.
|
||||||
|
* @param metadata Output buffer for storing received Models Metadata.
|
||||||
|
*
|
||||||
|
* @return 0 on success, or (negative) error code on failure.
|
||||||
|
*/
|
||||||
|
int bt_mesh_models_metadata_get(uint16_t net_idx, uint16_t addr, uint8_t page,
|
||||||
|
size_t offset, struct net_buf_simple *metadata);
|
||||||
|
|
||||||
|
/** @cond INTERNAL_HIDDEN */
|
||||||
|
extern const struct bt_mesh_model_op _bt_mesh_large_comp_data_cli_op[];
|
||||||
|
extern const struct bt_mesh_model_cb _bt_mesh_large_comp_data_cli_cb;
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* BT_MESH_LARGE_COMP_DATA_CLI_H__ */
|
42
include/zephyr/bluetooth/mesh/large_comp_data_srv.h
Normal file
42
include/zephyr/bluetooth/mesh/large_comp_data_srv.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @defgroup bt_mesh_large_comp_data_srv Large Composition Data Server model
|
||||||
|
* @{
|
||||||
|
* @brief API for the Large Composition Data Server model.
|
||||||
|
*/
|
||||||
|
#ifndef BT_MESH_LARGE_COMP_DATA_SRV_H__
|
||||||
|
#define BT_MESH_LARGE_COMP_DATA_SRV_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Large Composition Data Server model composition data entry.
|
||||||
|
*/
|
||||||
|
#define BT_MESH_MODEL_LARGE_COMP_DATA_SRV \
|
||||||
|
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_LARGE_COMP_DATA_SRV, \
|
||||||
|
_bt_mesh_large_comp_data_srv_op, NULL, NULL, \
|
||||||
|
&_bt_mesh_large_comp_data_srv_cb)
|
||||||
|
|
||||||
|
/** @cond INTERNAL_HIDDEN */
|
||||||
|
extern const struct bt_mesh_model_op _bt_mesh_large_comp_data_srv_op[];
|
||||||
|
extern const struct bt_mesh_model_cb _bt_mesh_large_comp_data_srv_cb;
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BT_MESH_LARGE_COMP_DATA_SRV_H__ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
|
@ -58,6 +58,10 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_CFG_CLI cfg_cli.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_HEALTH_CLI health_cli.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_HEALTH_CLI health_cli.c)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV large_comp_data_srv.c)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_LARGE_COMP_DATA_CLI large_comp_data_cli.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SELF_TEST test.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SELF_TEST test.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_CDB cdb.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_CDB cdb.c)
|
||||||
|
|
|
@ -1209,6 +1209,16 @@ config BT_MESH_RPR_SRV_AD_DATA_MAX
|
||||||
extended scanning.
|
extended scanning.
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
config BT_MESH_LARGE_COMP_DATA_SRV
|
||||||
|
bool "Support for Large Composition Data Server Model"
|
||||||
|
help
|
||||||
|
Enable support for the Large Composition Data Server model.
|
||||||
|
|
||||||
|
config BT_MESH_LARGE_COMP_DATA_CLI
|
||||||
|
bool "Support for Large Composition Data Client Model"
|
||||||
|
help
|
||||||
|
Enable support for the Large Composition Data Client model.
|
||||||
|
|
||||||
endif # BT_MESH_V1d1
|
endif # BT_MESH_V1d1
|
||||||
|
|
||||||
rsource "shell/Kconfig"
|
rsource "shell/Kconfig"
|
||||||
|
|
|
@ -42,6 +42,11 @@ struct mod_pub_val {
|
||||||
cred:1;
|
cred:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct comp_foreach_model_arg {
|
||||||
|
struct net_buf_simple *buf;
|
||||||
|
size_t *offset;
|
||||||
|
};
|
||||||
|
|
||||||
static const struct bt_mesh_comp *dev_comp;
|
static const struct bt_mesh_comp *dev_comp;
|
||||||
static uint16_t dev_primary_addr;
|
static uint16_t dev_primary_addr;
|
||||||
static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf);
|
static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf);
|
||||||
|
@ -71,6 +76,343 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (vnd) {
|
||||||
|
size += sizeof(mod->vnd.company);
|
||||||
|
size += sizeof(mod->vnd.id);
|
||||||
|
} else {
|
||||||
|
size += sizeof(mod->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
size += sizeof(uint8_t);
|
||||||
|
|
||||||
|
if (!mod->metadata) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (*offset <= model_size) {
|
||||||
|
*offset -= model_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_buf_simple_tailroom(buf) < (model_size + BT_MESH_MIC_SHORT)) {
|
||||||
|
LOG_ERR("Too large metadata");
|
||||||
|
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;
|
||||||
|
uint8_t mod_count = 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
++mod_count;
|
||||||
|
err = metadata_add_model(model, elem, false, &arg);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod_count_ptr) {
|
||||||
|
*mod_count_ptr = mod_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_count = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < elem->vnd_model_count; j++) {
|
||||||
|
struct bt_mesh_model *model = &elem->vnd_models[j];
|
||||||
|
|
||||||
|
if (!model->metadata) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++mod_count;
|
||||||
|
err = metadata_add_model(model, elem, true, &arg);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vnd_count_ptr) {
|
||||||
|
*vnd_count_ptr = mod_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
|
int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
|
||||||
{
|
{
|
||||||
int32_t period;
|
int32_t period;
|
||||||
|
@ -1241,7 +1583,7 @@ int bt_mesh_comp_store(void)
|
||||||
NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX);
|
NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bt_mesh_comp_get_page_0(&buf);
|
err = bt_mesh_comp_data_get_page_0(&buf, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Failed to read composition data: %d", err);
|
LOG_ERR("Failed to read composition data: %d", err);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -22,6 +22,10 @@ enum {
|
||||||
void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count);
|
void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count);
|
||||||
|
|
||||||
uint8_t bt_mesh_elem_count(void);
|
uint8_t bt_mesh_elem_count(void);
|
||||||
|
size_t bt_mesh_comp_page_0_size(void);
|
||||||
|
int bt_mesh_comp_data_get_page_0(struct net_buf_simple *buf, size_t offset);
|
||||||
|
size_t bt_mesh_metadata_page_0_size(void);
|
||||||
|
int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset);
|
||||||
|
|
||||||
/* Find local element based on unicast address */
|
/* Find local element based on unicast address */
|
||||||
struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr);
|
struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr);
|
||||||
|
|
|
@ -47,79 +47,6 @@ static void node_reset_pending_handler(struct k_work *work)
|
||||||
|
|
||||||
static K_WORK_DEFINE(node_reset_pending, node_reset_pending_handler);
|
static K_WORK_DEFINE(node_reset_pending, node_reset_pending_handler);
|
||||||
|
|
||||||
static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem,
|
|
||||||
bool primary)
|
|
||||||
{
|
|
||||||
struct bt_mesh_model *mod;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (net_buf_simple_tailroom(buf) <
|
|
||||||
4 + (elem->model_count * 2U) + (elem->vnd_model_count * 4U)) {
|
|
||||||
LOG_ERR("Too large device composition");
|
|
||||||
return -E2BIG;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_buf_simple_add_le16(buf, elem->loc);
|
|
||||||
|
|
||||||
net_buf_simple_add_u8(buf, elem->model_count);
|
|
||||||
net_buf_simple_add_u8(buf, elem->vnd_model_count);
|
|
||||||
|
|
||||||
for (i = 0; i < elem->model_count; i++) {
|
|
||||||
mod = &elem->models[i];
|
|
||||||
net_buf_simple_add_le16(buf, mod->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < elem->vnd_model_count; i++) {
|
|
||||||
mod = &elem->vnd_models[i];
|
|
||||||
net_buf_simple_add_le16(buf, mod->vnd.company);
|
|
||||||
net_buf_simple_add_le16(buf, mod->vnd.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bt_mesh_comp_get_page_0(struct net_buf_simple *buf)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_buf_simple_add_le16(buf, comp->cid);
|
|
||||||
net_buf_simple_add_le16(buf, comp->pid);
|
|
||||||
net_buf_simple_add_le16(buf, comp->vid);
|
|
||||||
net_buf_simple_add_le16(buf, CONFIG_BT_MESH_CRPL);
|
|
||||||
net_buf_simple_add_le16(buf, feat);
|
|
||||||
|
|
||||||
for (i = 0; i < comp->elem_count; i++) {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = comp_add_elem(buf, &comp->elem[i], i == 0);
|
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_comp_data_get(struct bt_mesh_model *model,
|
static int dev_comp_data_get(struct bt_mesh_model *model,
|
||||||
struct bt_mesh_msg_ctx *ctx,
|
struct bt_mesh_msg_ctx *ctx,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
|
@ -154,7 +81,7 @@ static int dev_comp_data_get(struct bt_mesh_model *model,
|
||||||
|
|
||||||
sdu.size += BT_MESH_MIC_SHORT;
|
sdu.size += BT_MESH_MIC_SHORT;
|
||||||
} else {
|
} else {
|
||||||
err = bt_mesh_comp_get_page_0(&sdu);
|
err = bt_mesh_comp_data_get_page_0(&sdu, 0);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
LOG_ERR("Unable to get composition page 0");
|
LOG_ERR("Unable to get composition page 0");
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#include <zephyr/bluetooth/mesh.h>
|
#include <zephyr/bluetooth/mesh.h>
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "foundation.h"
|
#include "access.h"
|
||||||
|
|
||||||
int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf,
|
int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf,
|
||||||
struct bt_mesh_dfu_metadata *metadata)
|
struct bt_mesh_dfu_metadata *metadata)
|
||||||
|
@ -91,7 +91,7 @@ int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash)
|
||||||
NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX);
|
NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bt_mesh_comp_get_page_0(&buf);
|
err = bt_mesh_comp_data_get_page_0(&buf, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,11 @@
|
||||||
#define OP_VND_MOD_APP_GET BT_MESH_MODEL_OP_2(0x80, 0x4d)
|
#define OP_VND_MOD_APP_GET BT_MESH_MODEL_OP_2(0x80, 0x4d)
|
||||||
#define OP_VND_MOD_APP_LIST BT_MESH_MODEL_OP_2(0x80, 0x4e)
|
#define OP_VND_MOD_APP_LIST BT_MESH_MODEL_OP_2(0x80, 0x4e)
|
||||||
|
|
||||||
|
#define OP_LARGE_COMP_DATA_GET BT_MESH_MODEL_OP_2(0x80, 0x74)
|
||||||
|
#define OP_LARGE_COMP_DATA_STATUS BT_MESH_MODEL_OP_2(0x80, 0x75)
|
||||||
|
#define OP_MODELS_METADATA_GET BT_MESH_MODEL_OP_2(0x80, 0x76)
|
||||||
|
#define OP_MODELS_METADATA_STATUS BT_MESH_MODEL_OP_2(0x80, 0x77)
|
||||||
|
|
||||||
#define STATUS_SUCCESS 0x00
|
#define STATUS_SUCCESS 0x00
|
||||||
#define STATUS_INVALID_ADDRESS 0x01
|
#define STATUS_INVALID_ADDRESS 0x01
|
||||||
#define STATUS_INVALID_MODEL 0x02
|
#define STATUS_INVALID_MODEL 0x02
|
||||||
|
@ -116,8 +121,6 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time);
|
||||||
|
|
||||||
#include <zephyr/sys/byteorder.h>
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
|
||||||
int bt_mesh_comp_get_page_0(struct net_buf_simple *buf);
|
|
||||||
|
|
||||||
static inline void key_idx_pack(struct net_buf_simple *buf,
|
static inline void key_idx_pack(struct net_buf_simple *buf,
|
||||||
uint16_t idx1, uint16_t idx2)
|
uint16_t idx1, uint16_t idx2)
|
||||||
{
|
{
|
||||||
|
|
183
subsys/bluetooth/mesh/large_comp_data_cli.c
Normal file
183
subsys/bluetooth/mesh/large_comp_data_cli.c
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
/* 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));
|
||||||
|
}
|
159
subsys/bluetooth/mesh/large_comp_data_srv.c
Normal file
159
subsys/bluetooth/mesh/large_comp_data_srv.c
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
* 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. */
|
||||||
|
struct bt_mesh_model *model;
|
||||||
|
} srv;
|
||||||
|
|
||||||
|
static int handle_large_comp_data_get(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 = net_buf_simple_pull_u8(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);
|
||||||
|
|
||||||
|
if (page != 0U) {
|
||||||
|
LOG_DBG("Composition page %u not available", page);
|
||||||
|
page = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_simple_add_u8(&rsp, page);
|
||||||
|
|
||||||
|
total_size = bt_mesh_comp_page_0_size();
|
||||||
|
net_buf_simple_add_le16(&rsp, offset);
|
||||||
|
net_buf_simple_add_le16(&rsp, total_size);
|
||||||
|
|
||||||
|
if (offset < total_size) {
|
||||||
|
err = bt_mesh_comp_data_get_page_0(&rsp, offset);
|
||||||
|
if (err && err != -E2BIG) {
|
||||||
|
LOG_ERR("comp_get_page_0 returned error");
|
||||||
|
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(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);
|
||||||
|
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 = net_buf_simple_pull_u8(buf);
|
||||||
|
offset = net_buf_simple_pull_le16(buf);
|
||||||
|
|
||||||
|
LOG_DBG("page %u offset %u", page, offset);
|
||||||
|
|
||||||
|
bt_mesh_model_msg_init(&rsp, OP_MODELS_METADATA_STATUS);
|
||||||
|
|
||||||
|
if (page != 0U) {
|
||||||
|
LOG_DBG("Composition page %u not available", page);
|
||||||
|
page = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_simple_add_u8(&rsp, page);
|
||||||
|
|
||||||
|
total_size = bt_mesh_metadata_page_0_size();
|
||||||
|
net_buf_simple_add_le16(&rsp, offset);
|
||||||
|
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("bt_mesh_metadata_get_page_0 returned error");
|
||||||
|
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(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->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,
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue