Bluetooth: Mesh: Op agg mdl coex

Refactors the implementation of the Opcode Aggregator
models to allow them to coexist on the same device.

Signed-off-by: Anders Storrø <anders.storro@nordicsemi.no>
This commit is contained in:
Anders Storrø 2023-10-18 17:43:13 +02:00 committed by Carles Cufí
commit 0a25a61c7d
5 changed files with 141 additions and 157 deletions

View file

@ -1506,8 +1506,10 @@ 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)
{
if (IS_ENABLED(CONFIG_BT_MESH_OP_AGG) && bt_mesh_op_agg_accept(ctx)) {
return bt_mesh_op_agg_send(model, ctx, msg, cb);
if (IS_ENABLED(CONFIG_BT_MESH_OP_AGG_SRV) && bt_mesh_op_agg_srv_accept(ctx, msg)) {
return bt_mesh_op_agg_srv_send(model, msg);
} else if (IS_ENABLED(CONFIG_BT_MESH_OP_AGG_CLI) && bt_mesh_op_agg_cli_accept(ctx, msg)) {
return bt_mesh_op_agg_cli_send(model, msg);
}
if (!bt_mesh_model_has_key(model, ctx->app_idx)) {

View file

@ -16,83 +16,22 @@ LOG_MODULE_REGISTER(bt_mesh_op_agg);
#define IS_LENGTH_LONG(buf) ((buf)->data[0] & 1)
#define LENGTH_SHORT_MAX BIT_MASK(7)
NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_TX_SDU_MAX);
NET_BUF_SIMPLE_DEFINE_STATIC(srcs, BT_MESH_TX_SDU_MAX);
static struct op_agg_ctx agg_ctx = {
.sdu = &sdu,
#if IS_ENABLED(CONFIG_BT_MESH_OP_AGG_CLI)
.srcs = &srcs,
#endif
};
struct op_agg_ctx *bt_mesh_op_agg_ctx_get(void)
{
return &agg_ctx;
}
static bool ctx_match(struct bt_mesh_msg_ctx *ctx)
{
return (ctx->net_idx == agg_ctx.net_idx) && (ctx->addr == agg_ctx.addr) &&
(ctx->app_idx == agg_ctx.app_idx);
}
int bt_mesh_op_agg_accept(struct bt_mesh_msg_ctx *msg_ctx)
{
return agg_ctx.initialized && ctx_match(msg_ctx);
}
void bt_mesh_op_agg_ctx_reinit(void)
{
agg_ctx.initialized = true;
}
int bt_mesh_op_agg_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg,
const struct bt_mesh_send_cb *cb)
{
int err;
/* Model responded so mark this message as acknowledged */
agg_ctx.ack = true;
if (IS_ENABLED(CONFIG_BT_MESH_OP_AGG_CLI)) {
/* Store source address so that Opcodes Aggregator Client can
* match response with source model
*/
uint16_t src = bt_mesh_model_elem(model)->addr;
if (net_buf_simple_tailroom(&srcs) < 2) {
return -ENOMEM;
}
net_buf_simple_add_le16(&srcs, src);
}
err = bt_mesh_op_agg_encode_msg(msg);
if (err) {
agg_ctx.rsp_err = ACCESS_STATUS_RESPONSE_OVERFLOW;
}
return err;
}
int bt_mesh_op_agg_encode_msg(struct net_buf_simple *msg)
int bt_mesh_op_agg_encode_msg(struct net_buf_simple *msg, struct net_buf_simple *buf)
{
if (msg->len > LENGTH_SHORT_MAX) {
if (net_buf_simple_tailroom(agg_ctx.sdu) < (msg->len + 2)) {
if (net_buf_simple_tailroom(buf) < (msg->len + 2)) {
return -ENOMEM;
}
net_buf_simple_add_le16(agg_ctx.sdu, (msg->len << 1) | 1);
net_buf_simple_add_le16(buf, (msg->len << 1) | 1);
} else {
if (net_buf_simple_tailroom(agg_ctx.sdu) < (msg->len + 1)) {
if (net_buf_simple_tailroom(buf) < (msg->len + 1)) {
return -ENOMEM;
}
net_buf_simple_add_u8(agg_ctx.sdu, msg->len << 1);
net_buf_simple_add_u8(buf, msg->len << 1);
}
net_buf_simple_add_mem(agg_ctx.sdu, msg->data, msg->len);
net_buf_simple_add_mem(buf, msg->data, msg->len);
return 0;
}
@ -124,3 +63,21 @@ int bt_mesh_op_agg_decode_msg(struct net_buf_simple *msg,
return 0;
}
bool bt_mesh_op_agg_is_op_agg_msg(struct net_buf_simple *buf)
{
if (buf->len >= 2 && (buf->data[0] >> 6) == 2) {
uint16_t opcode;
struct net_buf_simple_state state;
net_buf_simple_save(buf, &state);
opcode = net_buf_simple_pull_be16(buf);
net_buf_simple_restore(buf, &state);
if ((opcode == OP_OPCODES_AGGREGATOR_STATUS) ||
(opcode == OP_OPCODES_AGGREGATOR_SEQUENCE)) {
return true;
}
}
return false;
}

View file

@ -7,45 +7,20 @@
struct op_agg_ctx {
/** Context is initialized. */
bool initialized;
/** NetKey Index of the subnet to send the message on. */
uint16_t net_idx;
/** AppKey Index to encrypt the message with. */
uint16_t app_idx;
/** Remote element address. */
uint16_t addr;
/** List of source element addresses.
* Used by Client to match aggregated responses
* with local source client models.
*/
struct net_buf_simple *srcs;
/** Response error code. */
int rsp_err;
/** Aggregated message buffer. */
struct net_buf_simple *sdu;
/** Used only by the Opcodes Aggregator Server.
*
* Indicates that the received aggregated message
* was acknowledged by local server model.
*/
bool ack;
};
struct op_agg_ctx *bt_mesh_op_agg_ctx_get(void);
void bt_mesh_op_agg_ctx_reinit(void);
int bt_mesh_op_agg_encode_msg(struct net_buf_simple *msg);
int bt_mesh_op_agg_decode_msg(struct net_buf_simple *msg,
struct net_buf_simple *buf);
int bt_mesh_op_agg_accept(struct bt_mesh_msg_ctx *ctx);
int bt_mesh_op_agg_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg,
const struct bt_mesh_send_cb *cb);
int bt_mesh_op_agg_encode_msg(struct net_buf_simple *msg, struct net_buf_simple *buf);
int bt_mesh_op_agg_decode_msg(struct net_buf_simple *msg, struct net_buf_simple *buf);
int bt_mesh_op_agg_cli_send(struct bt_mesh_model *model, struct net_buf_simple *msg);
int bt_mesh_op_agg_cli_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf);
int bt_mesh_op_agg_srv_send(struct bt_mesh_model *model, struct net_buf_simple *msg);
int bt_mesh_op_agg_srv_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf);
bool bt_mesh_op_agg_is_op_agg_msg(struct net_buf_simple *buf);

View file

@ -18,14 +18,24 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_mesh_op_agg_cli);
NET_BUF_SIMPLE_DEFINE_STATIC(srcs, BT_MESH_TX_SDU_MAX);
NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_TX_SDU_MAX);
/** Mesh Opcodes Aggregator Client Model Context */
static struct bt_mesh_op_agg_cli {
/** Composition data model entry pointer. */
struct bt_mesh_model *model;
/* Internal parameters for tracking message responses. */
/** Acknowledge context. */
struct bt_mesh_msg_ack_ctx ack_ctx;
} cli;
/** List of source element addresses.
* Used by Client to match aggregated responses
* with local source client models.
*/
struct net_buf_simple *srcs;
/** Aggregator context. */
struct op_agg_ctx ctx;
} cli = {.srcs = &srcs, .ctx.sdu = &sdu};
static int32_t msg_timeout;
@ -33,7 +43,6 @@ static int handle_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
struct net_buf_simple msg;
uint8_t status;
uint16_t elem_addr, addr;
@ -57,17 +66,17 @@ static int handle_status(struct bt_mesh_model *model,
err = bt_mesh_op_agg_decode_msg(&msg, buf);
if (err) {
LOG_ERR("Cannot decode aggregated message %d", err);
bt_mesh_op_agg_ctx_reinit();
cli.ctx.initialized = true;
return -EINVAL;
}
if (agg->srcs->len < 2) {
if (cli.srcs->len < 2) {
LOG_ERR("Mismatch in sources address buffer");
bt_mesh_op_agg_ctx_reinit();
cli.ctx.initialized = true;
return -ENOENT;
}
addr = net_buf_simple_pull_le16(agg->srcs);
addr = net_buf_simple_pull_le16(cli.srcs);
/* Empty item means unacked msg. */
if (!msg.len) {
@ -78,7 +87,7 @@ static int handle_status(struct bt_mesh_model *model,
err = bt_mesh_model_recv(ctx, &msg);
if (err) {
LOG_ERR("Opcodes Aggregator receive error %d", err);
bt_mesh_op_agg_ctx_reinit();
cli.ctx.initialized = true;
return err;
}
}
@ -115,56 +124,51 @@ static int op_agg_cli_init(struct bt_mesh_model *model)
int bt_mesh_op_agg_cli_seq_start(uint16_t net_idx, uint16_t app_idx, uint16_t dst,
uint16_t elem_addr)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
LOG_ERR("Element address shall be a unicast address");
return -EINVAL;
}
if (agg->initialized) {
if (cli.ctx.initialized) {
LOG_ERR("Opcodes Aggregator is already configured");
return -EALREADY;
}
agg->net_idx = net_idx;
agg->app_idx = app_idx;
agg->addr = dst;
agg->ack = false;
agg->rsp_err = 0;
agg->initialized = true;
cli.ctx.net_idx = net_idx;
cli.ctx.app_idx = app_idx;
cli.ctx.addr = dst;
cli.ctx.initialized = true;
net_buf_simple_init(agg->srcs, 0);
bt_mesh_model_msg_init(agg->sdu, OP_OPCODES_AGGREGATOR_SEQUENCE);
net_buf_simple_add_le16(agg->sdu, elem_addr);
net_buf_simple_init(cli.srcs, 0);
bt_mesh_model_msg_init(cli.ctx.sdu, OP_OPCODES_AGGREGATOR_SEQUENCE);
net_buf_simple_add_le16(cli.ctx.sdu, elem_addr);
return 0;
}
int bt_mesh_op_agg_cli_seq_send(void)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
struct bt_mesh_msg_ctx ctx = {
.net_idx = agg->net_idx,
.app_idx = agg->app_idx,
.addr = agg->addr,
.net_idx = cli.ctx.net_idx,
.app_idx = cli.ctx.app_idx,
.addr = cli.ctx.addr,
};
int err;
if (!agg->initialized) {
if (!cli.ctx.initialized) {
LOG_ERR("Opcodes Aggregator not initialized");
return -EINVAL;
}
err = bt_mesh_msg_ack_ctx_prepare(&cli.ack_ctx, OP_OPCODES_AGGREGATOR_STATUS, agg->addr,
NULL);
err = bt_mesh_msg_ack_ctx_prepare(&cli.ack_ctx, OP_OPCODES_AGGREGATOR_STATUS,
cli.ctx.addr, NULL);
if (err) {
return err;
}
agg->initialized = false;
cli.ctx.initialized = false;
err = bt_mesh_model_send(cli.model, &ctx, agg->sdu, NULL, NULL);
err = bt_mesh_model_send(cli.model, &ctx, cli.ctx.sdu, NULL, NULL);
if (err) {
LOG_ERR("model_send() failed (err %d)", err);
bt_mesh_msg_ack_ctx_clear(&cli.ack_ctx);
@ -176,23 +180,17 @@ int bt_mesh_op_agg_cli_seq_send(void)
void bt_mesh_op_agg_cli_seq_abort(void)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
agg->initialized = false;
cli.ctx.initialized = false;
}
bool bt_mesh_op_agg_cli_seq_is_started(void)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
return agg->initialized;
return cli.ctx.initialized;
}
size_t bt_mesh_op_agg_cli_seq_tailroom(void)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
return net_buf_simple_tailroom(agg->sdu);
return net_buf_simple_tailroom(cli.ctx.sdu);
}
int32_t bt_mesh_op_agg_cli_timeout_get(void)
@ -205,6 +203,26 @@ void bt_mesh_op_agg_cli_timeout_set(int32_t timeout)
msg_timeout = timeout;
}
int bt_mesh_op_agg_cli_send(struct bt_mesh_model *model, struct net_buf_simple *msg)
{
uint16_t src = bt_mesh_model_elem(model)->addr;
if (net_buf_simple_tailroom(&srcs) < 2) {
return -ENOMEM;
}
net_buf_simple_add_le16(&srcs, src);
return bt_mesh_op_agg_encode_msg(msg, cli.ctx.sdu);
}
int bt_mesh_op_agg_cli_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf)
{
return cli.ctx.initialized && (ctx->net_idx == cli.ctx.net_idx) &&
(ctx->addr == cli.ctx.addr) && (ctx->app_idx == cli.ctx.app_idx) &&
!bt_mesh_op_agg_is_op_agg_msg(buf);
}
const struct bt_mesh_model_cb _bt_mesh_op_agg_cli_cb = {
.init = op_agg_cli_init,
};

View file

@ -17,17 +17,26 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_mesh_op_agg_srv);
NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_TX_SDU_MAX);
/** Mesh Opcodes Aggragator Server Model Context */
static struct bt_mesh_op_agg_srv {
/** Composition data model entry pointer. */
struct bt_mesh_model *model;
} srv;
/** Response error code. */
int rsp_err;
/** Indicates that the received aggregated message
* was acknowledged by local server model.
*/
bool ack;
/** Aggregator context. */
struct op_agg_ctx ctx;
} srv = {.ctx.sdu = &sdu};
static int handle_sequence(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct op_agg_ctx *agg = bt_mesh_op_agg_ctx_get();
struct net_buf_simple_state state;
struct net_buf_simple msg;
uint16_t elem;
@ -37,14 +46,14 @@ static int handle_sequence(struct bt_mesh_model *model,
elem = net_buf_simple_pull_le16(buf);
ctx->recv_dst = elem;
bt_mesh_model_msg_init(agg->sdu, OP_OPCODES_AGGREGATOR_STATUS);
status = net_buf_simple_add_u8(agg->sdu, 0);
net_buf_simple_add_le16(agg->sdu, elem);
bt_mesh_model_msg_init(srv.ctx.sdu, OP_OPCODES_AGGREGATOR_STATUS);
status = net_buf_simple_add_u8(srv.ctx.sdu, 0);
net_buf_simple_add_le16(srv.ctx.sdu, elem);
agg->net_idx = ctx->net_idx;
agg->app_idx = ctx->app_idx;
agg->addr = ctx->addr;
agg->initialized = true;
srv.ctx.net_idx = ctx->net_idx;
srv.ctx.app_idx = ctx->app_idx;
srv.ctx.addr = ctx->addr;
srv.ctx.initialized = true;
if (!BT_MESH_ADDR_IS_UNICAST(elem)) {
LOG_WRN("Address is not unicast, ignoring.");
@ -70,12 +79,12 @@ static int handle_sequence(struct bt_mesh_model *model,
while (buf->len > 0) {
(void) bt_mesh_op_agg_decode_msg(&msg, buf);
agg->ack = false;
agg->rsp_err = 0;
srv.ack = false;
srv.rsp_err = 0;
err = bt_mesh_model_recv(ctx, &msg);
if (agg->rsp_err) {
*status = agg->rsp_err;
if (srv.rsp_err) {
*status = srv.rsp_err;
break;
}
@ -84,14 +93,14 @@ static int handle_sequence(struct bt_mesh_model *model,
break;
}
if (!agg->ack) {
net_buf_simple_add_u8(agg->sdu, 0);
if (!srv.ack) {
net_buf_simple_add_u8(srv.ctx.sdu, 0);
}
}
send:
agg->initialized = false;
err = bt_mesh_model_send(model, ctx, agg->sdu, NULL, NULL);
srv.ctx.initialized = false;
err = bt_mesh_model_send(model, ctx, srv.ctx.sdu, NULL, NULL);
if (err) {
LOG_ERR("Unable to send Opcodes Aggregator Status");
return err;
@ -122,6 +131,29 @@ static int op_agg_srv_init(struct bt_mesh_model *model)
return 0;
}
int bt_mesh_op_agg_srv_send(struct bt_mesh_model *model, struct net_buf_simple *msg)
{
int err;
/* Model responded so mark this message as acknowledged */
srv.ack = true;
err = bt_mesh_op_agg_encode_msg(msg, srv.ctx.sdu);
if (err) {
srv.rsp_err = ACCESS_STATUS_RESPONSE_OVERFLOW;
}
return err;
}
int bt_mesh_op_agg_srv_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf)
{
return srv.ctx.initialized && (ctx->net_idx == srv.ctx.net_idx) &&
(ctx->addr == srv.ctx.addr) && (ctx->app_idx == srv.ctx.app_idx) &&
!bt_mesh_op_agg_is_op_agg_msg(buf);
}
const struct bt_mesh_model_cb _bt_mesh_op_agg_srv_cb = {
.init = op_agg_srv_init,
};