385 lines
14 KiB
C
385 lines
14 KiB
C
|
/*
|
||
|
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||
|
*
|
||
|
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||
|
*/
|
||
|
#include "api/lightness_cli.h"
|
||
|
#include "model_utils.h"
|
||
|
#include "api/lightness_internal.h"
|
||
|
#include "msg.h"
|
||
|
|
||
|
#define LOG_TAG "[Mesh-lightness_cli]"
|
||
|
#define LOG_ERROR_ENABLE
|
||
|
#define LOG_DEBUG_ENABLE
|
||
|
#define LOG_INFO_ENABLE
|
||
|
/* #define LOG_DUMP_ENABLE */
|
||
|
#define LOG_CLI_ENABLE
|
||
|
#include "debug.h"
|
||
|
|
||
|
static int light_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf, enum light_repr repr)
|
||
|
{
|
||
|
if (buf->len != BT_MESH_LIGHTNESS_MSG_MINLEN_STATUS &&
|
||
|
buf->len != BT_MESH_LIGHTNESS_MSG_MAXLEN_STATUS) {
|
||
|
return -EMSGSIZE;
|
||
|
}
|
||
|
|
||
|
struct bt_mesh_lightness_cli *cli = model->rt->user_data;
|
||
|
struct bt_mesh_lightness_status status;
|
||
|
struct bt_mesh_lightness_status *rsp;
|
||
|
|
||
|
status.current = repr_to_light(net_buf_simple_pull_le16(buf), repr);
|
||
|
if (buf->len == 3) {
|
||
|
status.target =
|
||
|
repr_to_light(net_buf_simple_pull_le16(buf), repr);
|
||
|
status.remaining_time =
|
||
|
model_transition_decode(net_buf_simple_pull_u8(buf));
|
||
|
} else {
|
||
|
status.target = status.current;
|
||
|
status.remaining_time = 0;
|
||
|
}
|
||
|
|
||
|
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, op_get(LIGHTNESS_OP_TYPE_STATUS, repr),
|
||
|
ctx->addr, (void **)&rsp)) {
|
||
|
*rsp = status;
|
||
|
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
|
}
|
||
|
|
||
|
if (cli->handlers && cli->handlers->light_status) {
|
||
|
cli->handlers->light_status(cli, ctx, &status);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int handle_light_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
return light_status(model, ctx, buf, ACTUAL);
|
||
|
}
|
||
|
|
||
|
static int handle_light_linear_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
return light_status(model, ctx, buf, LINEAR);
|
||
|
}
|
||
|
|
||
|
static int handle_last_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_lightness_cli *cli = model->rt->user_data;
|
||
|
uint16_t last = from_actual(net_buf_simple_pull_le16(buf));
|
||
|
uint16_t *rsp;
|
||
|
|
||
|
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_LIGHTNESS_OP_LAST_STATUS, ctx->addr,
|
||
|
(void **)&rsp)) {
|
||
|
*rsp = last;
|
||
|
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
|
}
|
||
|
|
||
|
if (cli->handlers && cli->handlers->last_light_status) {
|
||
|
cli->handlers->last_light_status(cli, ctx, last);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int handle_default_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_lightness_cli *cli = model->rt->user_data;
|
||
|
uint16_t default_lvl = from_actual(net_buf_simple_pull_le16(buf));
|
||
|
uint16_t *rsp;
|
||
|
|
||
|
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_LIGHTNESS_OP_DEFAULT_STATUS,
|
||
|
ctx->addr, (void **)&rsp)) {
|
||
|
*rsp = default_lvl;
|
||
|
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
|
}
|
||
|
|
||
|
if (cli->handlers && cli->handlers->default_status) {
|
||
|
cli->handlers->default_status(cli, ctx, default_lvl);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int handle_range_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_lightness_cli *cli = model->rt->user_data;
|
||
|
struct bt_mesh_lightness_range_status status;
|
||
|
struct bt_mesh_lightness_range_status *rsp;
|
||
|
|
||
|
status.status = net_buf_simple_pull_u8(buf);
|
||
|
status.range.min = from_actual(net_buf_simple_pull_le16(buf));
|
||
|
status.range.max = from_actual(net_buf_simple_pull_le16(buf));
|
||
|
|
||
|
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_LIGHTNESS_OP_RANGE_STATUS, ctx->addr,
|
||
|
(void **)&rsp)) {
|
||
|
*rsp = status;
|
||
|
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
|
}
|
||
|
|
||
|
if (cli->handlers && cli->handlers->range_status) {
|
||
|
cli->handlers->range_status(cli, ctx, &status);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_model_op _bt_mesh_lightness_cli_op[] = {
|
||
|
{
|
||
|
BT_MESH_LIGHTNESS_OP_STATUS,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_LIGHTNESS_MSG_MINLEN_STATUS),
|
||
|
handle_light_status,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_LIGHTNESS_OP_LINEAR_STATUS,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_LIGHTNESS_MSG_MINLEN_STATUS),
|
||
|
handle_light_linear_status,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_LIGHTNESS_OP_LAST_STATUS,
|
||
|
BT_MESH_LEN_EXACT(BT_MESH_LIGHTNESS_MSG_LEN_LAST_STATUS),
|
||
|
handle_last_status,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_LIGHTNESS_OP_DEFAULT_STATUS,
|
||
|
BT_MESH_LEN_EXACT(BT_MESH_LIGHTNESS_MSG_LEN_DEFAULT_STATUS),
|
||
|
handle_default_status,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_LIGHTNESS_OP_RANGE_STATUS,
|
||
|
BT_MESH_LEN_EXACT(BT_MESH_LIGHTNESS_MSG_LEN_RANGE_STATUS),
|
||
|
handle_range_status,
|
||
|
},
|
||
|
BT_MESH_MODEL_OP_END,
|
||
|
};
|
||
|
|
||
|
static int bt_mesh_lvl_cli_init(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_lightness_cli *cli = model->rt->user_data;
|
||
|
|
||
|
cli->model = model;
|
||
|
cli->pub.msg = &cli->pub_buf;
|
||
|
net_buf_simple_init_with_data(&cli->pub_buf, cli->pub_data,
|
||
|
sizeof(cli->pub_data));
|
||
|
bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void bt_mesh_lvl_cli_reset(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_lightness_cli *cli = model->rt->user_data;
|
||
|
|
||
|
net_buf_simple_reset(model->pub->msg);
|
||
|
bt_mesh_msg_ack_ctx_reset(&cli->ack_ctx);
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_model_cb _bt_mesh_lightness_cli_cb = {
|
||
|
.init = bt_mesh_lvl_cli_init,
|
||
|
.reset = bt_mesh_lvl_cli_reset,
|
||
|
};
|
||
|
|
||
|
int lightness_cli_light_get(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx, enum light_repr repr,
|
||
|
struct bt_mesh_lightness_status *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_GET,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_GET);
|
||
|
bt_mesh_model_msg_init(&buf, op_get(LIGHTNESS_OP_TYPE_GET, repr));
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = op_get(LIGHTNESS_OP_TYPE_STATUS, repr),
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|
||
|
|
||
|
int lightness_cli_light_set(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx, enum light_repr repr,
|
||
|
const struct bt_mesh_lightness_set *set,
|
||
|
struct bt_mesh_lightness_status *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_SET,
|
||
|
BT_MESH_LIGHTNESS_MSG_MAXLEN_SET);
|
||
|
bt_mesh_model_msg_init(&buf, op_get(LIGHTNESS_OP_TYPE_SET, repr));
|
||
|
|
||
|
net_buf_simple_add_le16(&buf, set->lvl);
|
||
|
net_buf_simple_add_u8(&buf, cli->tid++);
|
||
|
if (set->transition) {
|
||
|
model_transition_buf_add(&buf, set->transition);
|
||
|
}
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = op_get(LIGHTNESS_OP_TYPE_STATUS, repr),
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|
||
|
|
||
|
int lightness_cli_light_set_unack(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
enum light_repr repr,
|
||
|
const struct bt_mesh_lightness_set *set)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_SET_UNACK,
|
||
|
BT_MESH_LIGHTNESS_MSG_MAXLEN_SET);
|
||
|
bt_mesh_model_msg_init(&buf, op_get(LIGHTNESS_OP_TYPE_SET_UNACK, repr));
|
||
|
|
||
|
net_buf_simple_add_le16(&buf, set->lvl);
|
||
|
net_buf_simple_add_u8(&buf, cli->tid++);
|
||
|
if (set->transition) {
|
||
|
model_transition_buf_add(&buf, set->transition);
|
||
|
}
|
||
|
|
||
|
return bt_mesh_msg_send(cli->model, ctx, &buf);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_light_get(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
struct bt_mesh_lightness_status *rsp)
|
||
|
{
|
||
|
return lightness_cli_light_get(cli, ctx, LIGHT_USER_REPR, rsp);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_light_set(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
const struct bt_mesh_lightness_set *set,
|
||
|
struct bt_mesh_lightness_status *rsp)
|
||
|
{
|
||
|
return lightness_cli_light_set(cli, ctx, LIGHT_USER_REPR, set, rsp);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_light_set_unack(
|
||
|
struct bt_mesh_lightness_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
|
const struct bt_mesh_lightness_set *set)
|
||
|
{
|
||
|
return lightness_cli_light_set_unack(cli, ctx, LIGHT_USER_REPR, set);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_range_get(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
struct bt_mesh_lightness_range_status *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_RANGE_GET,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_RANGE_GET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_RANGE_GET);
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = BT_MESH_LIGHTNESS_OP_RANGE_STATUS,
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_range_set(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
const struct bt_mesh_lightness_range *range,
|
||
|
struct bt_mesh_lightness_range_status *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_RANGE_SET,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_RANGE_SET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_RANGE_SET);
|
||
|
net_buf_simple_add_le16(&buf, to_actual(range->min));
|
||
|
net_buf_simple_add_le16(&buf, to_actual(range->max));
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = BT_MESH_LIGHTNESS_OP_RANGE_STATUS,
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_range_set_unack(
|
||
|
struct bt_mesh_lightness_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
|
const struct bt_mesh_lightness_range *range)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_RANGE_SET_UNACK,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_RANGE_SET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_RANGE_SET_UNACK);
|
||
|
net_buf_simple_add_le16(&buf, to_actual(range->min));
|
||
|
net_buf_simple_add_le16(&buf, to_actual(range->max));
|
||
|
|
||
|
return bt_mesh_msg_send(cli->model, ctx, &buf);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_default_get(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx, uint16_t *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_DEFAULT_GET,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_DEFAULT_GET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_DEFAULT_GET);
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = BT_MESH_LIGHTNESS_OP_DEFAULT_STATUS,
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_default_set(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
uint16_t default_light, uint16_t *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_DEFAULT_SET,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_DEFAULT_SET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_DEFAULT_SET);
|
||
|
net_buf_simple_add_le16(&buf, to_actual(default_light));
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = BT_MESH_LIGHTNESS_OP_DEFAULT_STATUS,
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_default_set_unack(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
uint16_t default_light)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_DEFAULT_SET_UNACK,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_DEFAULT_SET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_DEFAULT_SET_UNACK);
|
||
|
net_buf_simple_add_le16(&buf, to_actual(default_light));
|
||
|
|
||
|
return bt_mesh_msg_send(cli->model, ctx, &buf);
|
||
|
}
|
||
|
|
||
|
int bt_mesh_lightness_cli_last_get(struct bt_mesh_lightness_cli *cli,
|
||
|
struct bt_mesh_msg_ctx *ctx, uint16_t *rsp)
|
||
|
{
|
||
|
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_LIGHTNESS_OP_LAST_GET,
|
||
|
BT_MESH_LIGHTNESS_MSG_LEN_LAST_GET);
|
||
|
bt_mesh_model_msg_init(&buf, BT_MESH_LIGHTNESS_OP_LAST_GET);
|
||
|
|
||
|
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
|
.ack = &cli->ack_ctx,
|
||
|
.op = BT_MESH_LIGHTNESS_OP_LAST_STATUS,
|
||
|
.user_data = rsp,
|
||
|
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
|
};
|
||
|
|
||
|
return bt_mesh_msg_ackd_send(cli->model, ctx, &buf, rsp ? &rsp_ctx : NULL);
|
||
|
}
|