1203 lines
34 KiB
C
1203 lines
34 KiB
C
|
/*
|
||
|
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||
|
*
|
||
|
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||
|
*/
|
||
|
|
||
|
#include "adaptation.h"
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "net.h"
|
||
|
#include "transport.h"
|
||
|
#include "api/sensor_srv.h"
|
||
|
#include "api/sensor.h"
|
||
|
#include "api/properties.h"
|
||
|
#include <access.h>
|
||
|
|
||
|
#if (CONFIG_BT_MESH_SENSOR_SRV)
|
||
|
|
||
|
#define LOG_TAG "[Mesh-sensor_srv]"
|
||
|
#define LOG_ERROR_ENABLE
|
||
|
#define LOG_DEBUG_ENABLE
|
||
|
#define LOG_INFO_ENABLE
|
||
|
/* #define LOG_DUMP_ENABLE */
|
||
|
#define LOG_CLI_ENABLE
|
||
|
#include "debug.h"
|
||
|
|
||
|
#define SENSOR_FOR_EACH(_list, _node) \
|
||
|
SYS_SLIST_FOR_EACH_CONTAINER(_list, _node, state.node)
|
||
|
|
||
|
static struct bt_mesh_sensor *sensor_get(struct bt_mesh_sensor_srv *srv,
|
||
|
uint16_t id)
|
||
|
{
|
||
|
struct bt_mesh_sensor *sensor;
|
||
|
|
||
|
SENSOR_FOR_EACH(&srv->sensors, sensor) {
|
||
|
if (sensor->type->id == id) {
|
||
|
return sensor;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#if CONFIG_BT_SETTINGS
|
||
|
static void sensor_srv_pending_store(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
|
||
|
/* Cadence is stored as a sequence of cadence status messages */
|
||
|
NET_BUF_SIMPLE_DEFINE(buf, (CONFIG_BT_MESH_SENSOR_SRV_SENSORS_MAX *
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_CADENCE_STATUS));
|
||
|
|
||
|
for (int i = 0; i < srv->sensor_count; ++i) {
|
||
|
const struct bt_mesh_sensor *s = srv->sensor_array[i];
|
||
|
int err;
|
||
|
|
||
|
if (!s->state.configured) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
net_buf_simple_add_le16(&buf, s->type->id);
|
||
|
err = sensor_cadence_encode(&buf, s->type, s->state.pub_div,
|
||
|
s->state.min_int,
|
||
|
&s->state.threshold);
|
||
|
if (err) {
|
||
|
log_error("Failed encode data: %d", err);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
(void)bt_mesh_model_data_store(srv->model, false, NULL, buf.data,
|
||
|
buf.len);
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void cadence_store(struct bt_mesh_sensor_srv *srv)
|
||
|
{
|
||
|
#if CONFIG_BT_SETTINGS
|
||
|
bt_mesh_model_data_store_schedule(srv->model);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static int value_get(struct bt_mesh_sensor_srv *srv,
|
||
|
struct bt_mesh_sensor *sensor,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
struct sensor_value *value)
|
||
|
{
|
||
|
int err;
|
||
|
if (!sensor->get) {
|
||
|
return -ENOTSUP;
|
||
|
}
|
||
|
|
||
|
err = sensor->get(srv, sensor, ctx, value);
|
||
|
if (err) {
|
||
|
log_error("Value get for 0x%04x: %d", sensor->type->id, err);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
sensor_cadence_update(sensor, value);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int buf_status_add(struct bt_mesh_sensor_srv *srv,
|
||
|
struct bt_mesh_sensor *sensor,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
|
||
|
struct sensor_value value[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX] = {};
|
||
|
struct net_buf_simple_state state;
|
||
|
int err;
|
||
|
|
||
|
|
||
|
err = value_get(srv, sensor, ctx, value);
|
||
|
|
||
|
if (err) {
|
||
|
log_error("Unable to get value for 0x%04x: %d", sensor->type->id, err);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
net_buf_simple_save(buf, &state);
|
||
|
|
||
|
err = sensor_status_encode(buf, sensor, value);
|
||
|
|
||
|
if (err) {
|
||
|
log_error("Sensor value encode for 0x%04x: %d", sensor->type->id, err);
|
||
|
/* sensor_status_encode() could have encoded a part of Marshaled Sensor Data into
|
||
|
* buf, for example, Marshaled Property ID, but not the Raw Value. Restore the
|
||
|
* buf's state to not send corrupted data.
|
||
|
*/
|
||
|
net_buf_simple_restore(buf, &state);
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
static int handle_descriptor_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
|
||
|
if (buf->len != BT_MESH_SENSOR_MSG_MINLEN_DESCRIPTOR_GET &&
|
||
|
buf->len != BT_MESH_SENSOR_MSG_MAXLEN_DESCRIPTOR_GET) {
|
||
|
return -EMSGSIZE;
|
||
|
}
|
||
|
|
||
|
NET_BUF_SIMPLE_DEFINE(rsp, BT_MESH_TX_SDU_MAX);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_DESCRIPTOR_STATUS);
|
||
|
|
||
|
struct bt_mesh_sensor *sensor;
|
||
|
|
||
|
if (buf->len == 2) {
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
sensor = sensor_get(srv, id);
|
||
|
if (sensor) {
|
||
|
sensor_descriptor_encode(&rsp, sensor);
|
||
|
} else {
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
}
|
||
|
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
SENSOR_FOR_EACH(&srv->sensors, sensor) {
|
||
|
log_debug("Reporting ID 0x%04x", sensor->type->id);
|
||
|
|
||
|
if (net_buf_simple_tailroom(&rsp) < (8 + BT_MESH_MIC_SHORT)) {
|
||
|
log_error("Not enough room for all descriptors");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
sensor_descriptor_encode(&rsp, sensor);
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int handle_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
|
||
|
if (buf->len != BT_MESH_SENSOR_MSG_MINLEN_GET &&
|
||
|
buf->len != BT_MESH_SENSOR_MSG_MAXLEN_GET) {
|
||
|
return -EMSGSIZE;
|
||
|
}
|
||
|
|
||
|
NET_BUF_SIMPLE_DEFINE(rsp, BT_MESH_TX_SDU_MAX);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_STATUS);
|
||
|
|
||
|
struct bt_mesh_sensor *sensor;
|
||
|
if (buf->len == 2) {
|
||
|
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
|
||
|
sensor = sensor_get(srv, id);
|
||
|
if (sensor) {
|
||
|
buf_status_add(srv, sensor, ctx, &rsp);
|
||
|
} else {
|
||
|
log_debug("Unknown sensor ID 0x%04x", id);
|
||
|
sensor_status_id_encode(&rsp, 0, id);
|
||
|
}
|
||
|
goto respond;
|
||
|
}
|
||
|
SENSOR_FOR_EACH(&srv->sensors, sensor) {
|
||
|
buf_status_add(srv, sensor, ctx, &rsp);
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct bt_mesh_sensor_column *
|
||
|
column_get(const struct bt_mesh_sensor_series *series,
|
||
|
const struct sensor_value *val)
|
||
|
{
|
||
|
for (uint32_t i = 0; i < series->column_count; ++i) {
|
||
|
if (series->columns[i].start.val1 == val->val1 &&
|
||
|
series->columns[i].start.val2 == val->val2) {
|
||
|
return &series->columns[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static int handle_column_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
int err;
|
||
|
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
struct bt_mesh_sensor *sensor = sensor_get(srv, id);
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_SENSOR_OP_COLUMN_STATUS,
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_COLUMN_STATUS);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_COLUMN_STATUS);
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
|
||
|
if (!sensor || !sensor->series.get) {
|
||
|
log_debug("No series support in 0x%04x", id);
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
if (sensor->type->channel_count < 3) {
|
||
|
/* For sensors with one or two channels, pull the column index
|
||
|
* directly from the message
|
||
|
*/
|
||
|
uint32_t col_index = net_buf_simple_pull_le16(buf);
|
||
|
|
||
|
if (col_index >= sensor->series.column_count) {
|
||
|
log_error("Column out of range in 0x%04x",
|
||
|
sensor->type->id);
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
err = sensor_column_value_encode(&rsp, srv, sensor, ctx,
|
||
|
col_index);
|
||
|
if (err) {
|
||
|
log_error("Failed encoding sensor column: %d", err);
|
||
|
return err;
|
||
|
}
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
if (!sensor->series.columns) {
|
||
|
log_debug("No series support in 0x%04x", sensor->type->id);
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_sensor_format *col_format;
|
||
|
const struct bt_mesh_sensor_column *col;
|
||
|
struct sensor_value col_x;
|
||
|
|
||
|
col_format = bt_mesh_sensor_column_format_get(sensor->type);
|
||
|
|
||
|
if (col_format == NULL) {
|
||
|
return -ENOTSUP;
|
||
|
}
|
||
|
|
||
|
err = sensor_ch_decode(buf, col_format, &col_x);
|
||
|
if (err) {
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
log_debug("Column %s", bt_mesh_sensor_ch_str(&col_x));
|
||
|
|
||
|
col = column_get(&sensor->series, &col_x);
|
||
|
if (!col) {
|
||
|
log_error("Unknown column");
|
||
|
(void) sensor_ch_encode(&rsp, col_format, &col_x);
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
err = sensor_column_encode(&rsp, srv, sensor, ctx, col);
|
||
|
if (err) {
|
||
|
log_error("Failed encoding sensor column: %d", err);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static uint16_t max_column_count(const struct bt_mesh_sensor_type *sensor)
|
||
|
{
|
||
|
uint16_t column_size = 0;
|
||
|
|
||
|
for (int i = 0; i < sensor->channel_count; i++) {
|
||
|
column_size += sensor->channels[i].format->size;
|
||
|
}
|
||
|
|
||
|
if (column_size) {
|
||
|
return (BT_MESH_TX_SDU_MAX - BT_MESH_MIC_SHORT - 3) / column_size;
|
||
|
} else {
|
||
|
return (BT_MESH_TX_SDU_MAX - BT_MESH_MIC_SHORT - 3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int handle_series_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
const struct bt_mesh_sensor_format *col_format;
|
||
|
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
struct bt_mesh_sensor *sensor = sensor_get(srv, id);
|
||
|
|
||
|
NET_BUF_SIMPLE_DEFINE(rsp, BT_MESH_TX_SDU_MAX);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_SERIES_STATUS);
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
|
||
|
if (!sensor || !sensor->series.get) {
|
||
|
log_debug("No series support in 0x%04x", id);
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
if (sensor->type->channel_count < 3) {
|
||
|
uint16_t start = 0;
|
||
|
uint16_t end = sensor->series.column_count - 1;
|
||
|
|
||
|
if (buf->len == sizeof(uint16_t) * 2) {
|
||
|
start = net_buf_simple_pull_le16(buf);
|
||
|
end = net_buf_simple_pull_le16(buf);
|
||
|
if (start >= sensor->series.column_count ||
|
||
|
end >= sensor->series.column_count ||
|
||
|
start > end) {
|
||
|
log_error("Invalid range");
|
||
|
goto respond;
|
||
|
}
|
||
|
} else if (buf->len != 0) {
|
||
|
log_error("Invalid length (%u)", buf->len);
|
||
|
return -EMSGSIZE;
|
||
|
}
|
||
|
|
||
|
uint16_t max_columns = max_column_count(sensor->type);
|
||
|
|
||
|
if (end - start + 1 > max_columns) {
|
||
|
end = start + max_columns - 1;
|
||
|
}
|
||
|
|
||
|
for (uint32_t i = start; i <= end; i++) {
|
||
|
int err = sensor_column_value_encode(&rsp, srv, sensor,
|
||
|
ctx, i);
|
||
|
|
||
|
if (err) {
|
||
|
log_error("Column encode failed");
|
||
|
return err;
|
||
|
}
|
||
|
}
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
col_format = bt_mesh_sensor_column_format_get(sensor->type);
|
||
|
if (!col_format || !sensor->series.columns) {
|
||
|
log_debug("No series support in 0x%04x", sensor->type->id);
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
/* Check buf->len different from 0, before decoding buf to range and buf->len changes. */
|
||
|
bool ranged = (buf->len != 0);
|
||
|
struct bt_mesh_sensor_column range;
|
||
|
|
||
|
if (buf->len == col_format->size * 2) {
|
||
|
int err;
|
||
|
|
||
|
err = sensor_ch_decode(buf, col_format, &range.start);
|
||
|
if (err) {
|
||
|
log_error("Range start decode failed: %d", err);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
err = sensor_ch_decode(buf, col_format, &range.end);
|
||
|
if (err) {
|
||
|
log_error("Range end decode failed: %d", err);
|
||
|
return err;
|
||
|
}
|
||
|
} else if (buf->len != 0) {
|
||
|
/* invalid length */
|
||
|
log_error("Invalid length (%u)", buf->len);
|
||
|
return -EMSGSIZE;
|
||
|
}
|
||
|
|
||
|
for (uint32_t i = 0; i < sensor->series.column_count; ++i) {
|
||
|
const struct bt_mesh_sensor_column *col =
|
||
|
&sensor->series.columns[i];
|
||
|
|
||
|
if (ranged &&
|
||
|
!bt_mesh_sensor_value_in_column(&col->start, &range)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
log_debug("Column #%u", i);
|
||
|
|
||
|
int err = sensor_column_encode(&rsp, srv, sensor, ctx, col);
|
||
|
|
||
|
if (err) {
|
||
|
log_error("Failed encoding: %d", err);
|
||
|
return err;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_model_op _bt_mesh_sensor_srv_op[] = {
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_DESCRIPTOR_GET,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_DESCRIPTOR_GET),
|
||
|
handle_descriptor_get,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_GET,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_GET),
|
||
|
handle_get,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_COLUMN_GET,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_COLUMN_GET),
|
||
|
handle_column_get,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_SERIES_GET,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_SERIES_GET),
|
||
|
handle_series_get,
|
||
|
},
|
||
|
BT_MESH_MODEL_OP_END,
|
||
|
};
|
||
|
|
||
|
static int handle_cadence_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
struct bt_mesh_sensor *sensor;
|
||
|
uint16_t id;
|
||
|
int err;
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_SENSOR_OP_CADENCE_STATUS,
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_CADENCE_STATUS);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_CADENCE_STATUS);
|
||
|
|
||
|
id = net_buf_simple_pull_le16(buf);
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
|
||
|
sensor = sensor_get(srv, id);
|
||
|
if (!sensor || sensor->type->channel_count != 1 || !sensor->state.configured) {
|
||
|
log_error("Cadence not supported or not configured");
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
err = sensor_cadence_encode(&rsp, sensor->type, sensor->state.pub_div,
|
||
|
sensor->state.min_int,
|
||
|
&sensor->state.threshold);
|
||
|
if (err) {
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
bt_mesh_model_send(srv->model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cadence_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf, bool ack)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
struct bt_mesh_sensor *sensor;
|
||
|
uint16_t id;
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_SENSOR_OP_CADENCE_STATUS,
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_CADENCE_STATUS);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_CADENCE_STATUS);
|
||
|
|
||
|
id = net_buf_simple_pull_le16(buf);
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
|
||
|
sensor = sensor_get(srv, id);
|
||
|
if (!sensor || sensor->type->channel_count != 1) {
|
||
|
log_error("Cadence not supported");
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
struct bt_mesh_sensor_threshold threshold;
|
||
|
uint8_t period_div, min_int;
|
||
|
int err;
|
||
|
|
||
|
err = sensor_cadence_decode(buf, sensor->type, &period_div, &min_int,
|
||
|
&threshold);
|
||
|
if (err) {
|
||
|
log_error("Invalid cadence");
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
if (IS_ENABLED(CONFIG_BT_MESH_MODEL_LOG_LEVEL_DBG)) {
|
||
|
char delta_down_str[BT_MESH_SENSOR_CH_STR_LEN];
|
||
|
char delta_up_str[BT_MESH_SENSOR_CH_STR_LEN];
|
||
|
char range_low_str[BT_MESH_SENSOR_CH_STR_LEN];
|
||
|
char range_high_str[BT_MESH_SENSOR_CH_STR_LEN];
|
||
|
|
||
|
strcpy(delta_down_str, bt_mesh_sensor_ch_str(&threshold.delta.down));
|
||
|
strcpy(delta_up_str, bt_mesh_sensor_ch_str(&threshold.delta.up));
|
||
|
strcpy(range_low_str, bt_mesh_sensor_ch_str(&threshold.range.low));
|
||
|
strcpy(range_high_str, bt_mesh_sensor_ch_str(&threshold.range.high));
|
||
|
|
||
|
log_debug("Min int: %u div: %u delta: %s to %s range: %s to %s (%s)", min_int,
|
||
|
period_div, delta_down_str, delta_up_str, range_low_str, range_high_str,
|
||
|
(threshold.range.cadence == BT_MESH_SENSOR_CADENCE_FAST ? "fast" : "slow"));
|
||
|
}
|
||
|
|
||
|
sensor->state.min_int = min_int;
|
||
|
sensor->state.pub_div = period_div;
|
||
|
sensor->state.threshold = threshold;
|
||
|
sensor->state.configured = true;
|
||
|
|
||
|
/** Reschedule publication timer if the cadence increased. */
|
||
|
if (period_div > srv->pub.period_div) {
|
||
|
int period_ms;
|
||
|
|
||
|
srv->pub.period_div = period_div;
|
||
|
period_ms = bt_mesh_model_pub_period_get(srv->model);
|
||
|
|
||
|
if (period_ms > 0) {
|
||
|
log_debug("New publication interval: %u", period_ms);
|
||
|
k_work_reschedule(&srv->model->pub->timer, K_MSEC(period_ms));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cadence_store(srv);
|
||
|
|
||
|
err = sensor_cadence_encode(&rsp, sensor->type, sensor->state.pub_div,
|
||
|
sensor->state.min_int,
|
||
|
&sensor->state.threshold);
|
||
|
if (err) {
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
bt_mesh_msg_send(model, NULL, &rsp);
|
||
|
|
||
|
respond:
|
||
|
if (ack) {
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int handle_cadence_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
return cadence_set(model, ctx, buf, true);
|
||
|
}
|
||
|
|
||
|
static int handle_cadence_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
return cadence_set(model, ctx, buf, false);
|
||
|
}
|
||
|
|
||
|
static int handle_settings_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
log_debug("0x%04x", id);
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(
|
||
|
rsp, BT_MESH_SENSOR_OP_SETTINGS_STATUS,
|
||
|
2 + 2 * CONFIG_BT_MESH_SENSOR_SRV_SETTINGS_MAX);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_SETTINGS_STATUS);
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
|
||
|
struct bt_mesh_sensor *sensor = sensor_get(srv, id);
|
||
|
|
||
|
if (!sensor) {
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
for (uint32_t i = 0; i < MIN(CONFIG_BT_MESH_SENSOR_SRV_SETTINGS_MAX,
|
||
|
sensor->settings.count);
|
||
|
++i) {
|
||
|
net_buf_simple_add_le16(&rsp,
|
||
|
sensor->settings.list[i].type->id);
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct bt_mesh_sensor_setting *
|
||
|
setting_get(struct bt_mesh_sensor *sensor, uint16_t setting_id)
|
||
|
{
|
||
|
for (uint32_t i = 0; i < sensor->settings.count; i++) {
|
||
|
if (sensor->settings.list[i].type->id == setting_id) {
|
||
|
return &sensor->settings.list[i];
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static int handle_setting_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
uint16_t setting_id = net_buf_simple_pull_le16(buf);
|
||
|
int err;
|
||
|
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED ||
|
||
|
setting_id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_SENSOR_OP_SETTING_STATUS,
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_SETTING_STATUS);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_SETTING_STATUS);
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
net_buf_simple_add_le16(&rsp, setting_id);
|
||
|
|
||
|
const struct bt_mesh_sensor_setting *setting;
|
||
|
struct bt_mesh_sensor *sensor = sensor_get(srv, id);
|
||
|
|
||
|
if (!sensor) {
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
setting = setting_get(sensor, setting_id);
|
||
|
if (!setting || !setting->get) {
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
uint8_t minlen = rsp.len;
|
||
|
|
||
|
net_buf_simple_add_u8(&rsp, setting->set ? 0x03 : 0x01);
|
||
|
|
||
|
struct sensor_value values[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX] = { 0 };
|
||
|
|
||
|
setting->get(srv, sensor, setting, ctx, values);
|
||
|
|
||
|
err = sensor_value_encode(&rsp, setting->type, values);
|
||
|
if (err) {
|
||
|
log_error("Failed encoding sensor setting 0x%04x: %d",
|
||
|
setting->type->id, err);
|
||
|
|
||
|
/* Undo the access field */
|
||
|
rsp.len = minlen;
|
||
|
}
|
||
|
|
||
|
respond:
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int setting_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf, bool ack)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
uint16_t setting_id = net_buf_simple_pull_le16(buf);
|
||
|
int err;
|
||
|
|
||
|
if (id == BT_MESH_PROP_ID_PROHIBITED ||
|
||
|
setting_id == BT_MESH_PROP_ID_PROHIBITED) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_SENSOR_OP_SETTING_STATUS,
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_SETTING_STATUS);
|
||
|
bt_mesh_model_msg_init(&rsp, BT_MESH_SENSOR_OP_SETTING_STATUS);
|
||
|
net_buf_simple_add_le16(&rsp, id);
|
||
|
net_buf_simple_add_le16(&rsp, setting_id);
|
||
|
|
||
|
const struct bt_mesh_sensor_setting *setting;
|
||
|
struct bt_mesh_sensor *sensor;
|
||
|
|
||
|
sensor = sensor_get(srv, id);
|
||
|
if (!sensor) {
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
setting = setting_get(sensor, setting_id);
|
||
|
if (!setting || !setting->set) {
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
struct sensor_value values[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX];
|
||
|
|
||
|
err = sensor_value_decode(buf, setting->type, values);
|
||
|
if (err) {
|
||
|
log_error("Error decoding sensor setting 0x%04x: %d",
|
||
|
setting->type->id, err);
|
||
|
|
||
|
/* Invalid parameters: ignore this message */
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
setting->set(srv, sensor, setting, ctx, values);
|
||
|
|
||
|
uint8_t minlen = rsp.len;
|
||
|
|
||
|
net_buf_simple_add_u8(&rsp, 0x03); /* RW */
|
||
|
|
||
|
err = sensor_value_encode(&rsp, setting->type, values);
|
||
|
if (err) {
|
||
|
log_error("Error encoding sensor setting 0x%04x: %d",
|
||
|
setting->type->id, err);
|
||
|
|
||
|
/* Undo the access field */
|
||
|
rsp.len = minlen;
|
||
|
goto respond;
|
||
|
}
|
||
|
|
||
|
log_debug("0x%04x: 0x%04x", id, setting_id);
|
||
|
|
||
|
bt_mesh_msg_send(model, NULL, &rsp);
|
||
|
|
||
|
respond:
|
||
|
if (ack) {
|
||
|
bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int handle_setting_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
return setting_set(model, ctx, buf, true);
|
||
|
}
|
||
|
|
||
|
static int handle_setting_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
|
struct net_buf_simple *buf)
|
||
|
{
|
||
|
return setting_set(model, ctx, buf, false);
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_model_op _bt_mesh_sensor_setup_srv_op[] = {
|
||
|
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_CADENCE_GET,
|
||
|
BT_MESH_LEN_EXACT(BT_MESH_SENSOR_MSG_LEN_CADENCE_GET),
|
||
|
handle_cadence_get,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_CADENCE_SET,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_CADENCE_SET),
|
||
|
handle_cadence_set,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_CADENCE_SET_UNACKNOWLEDGED,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_CADENCE_SET),
|
||
|
handle_cadence_set_unack,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_SETTINGS_GET,
|
||
|
BT_MESH_LEN_EXACT(BT_MESH_SENSOR_MSG_LEN_SETTINGS_GET),
|
||
|
handle_settings_get,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_SETTING_GET,
|
||
|
BT_MESH_LEN_EXACT(BT_MESH_SENSOR_MSG_LEN_SETTING_GET),
|
||
|
handle_setting_get,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_SETTING_SET,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_SETTING_SET),
|
||
|
handle_setting_set,
|
||
|
},
|
||
|
{
|
||
|
BT_MESH_SENSOR_OP_SETTING_SET_UNACKNOWLEDGED,
|
||
|
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_SETTING_SET),
|
||
|
handle_setting_set_unack,
|
||
|
},
|
||
|
BT_MESH_MODEL_OP_END,
|
||
|
};
|
||
|
|
||
|
/** @brief Get the sensor publication interval (in number of publish messages).
|
||
|
*
|
||
|
* @param sensor Sensor instance
|
||
|
* @param period_div Server's period divisor
|
||
|
*
|
||
|
* @return The publish interval of the sensor measured in number of published
|
||
|
* messages by the server.
|
||
|
*/
|
||
|
static uint16_t pub_int_get(const struct bt_mesh_sensor *sensor,
|
||
|
uint8_t period_div)
|
||
|
{
|
||
|
uint8_t div = (sensor->state.pub_div * sensor->state.fast_pub);
|
||
|
|
||
|
return (1U << MAX(0, period_div - div));
|
||
|
}
|
||
|
|
||
|
/** @brief Get the sensor minimum interval (in number of publish messages).
|
||
|
*
|
||
|
* @param sensor Sensor instance
|
||
|
* @param period_div Server's period divisor
|
||
|
* @param base_period Server's base period
|
||
|
*
|
||
|
* @return The minimum interval of the sensor measured in number of published
|
||
|
* messages by the server.
|
||
|
*/
|
||
|
static uint16_t min_int_get(const struct bt_mesh_sensor *sensor,
|
||
|
uint8_t period_div, uint32_t base_period)
|
||
|
{
|
||
|
uint32_t pub_int = (base_period >> period_div);
|
||
|
uint32_t min_int = (1 << sensor->state.min_int);
|
||
|
|
||
|
return DIV_ROUND_UP(min_int, pub_int);
|
||
|
}
|
||
|
|
||
|
/** @brief Conditionally add a sensor value to a publication.
|
||
|
*
|
||
|
* A sensor message will be added to the publication if its minimum interval
|
||
|
* has expired and the value is outside its delta threshold or the
|
||
|
* publication interval has expired.
|
||
|
*
|
||
|
* @param srv Server sending the publication.
|
||
|
* @param s Sensor to add data of.
|
||
|
* @param period_div Server's original period divisor.
|
||
|
* @param base_period Server's original base period.
|
||
|
*/
|
||
|
static void pub_msg_add(struct bt_mesh_sensor_srv *srv,
|
||
|
struct bt_mesh_sensor *s, uint8_t period_div,
|
||
|
uint32_t base_period)
|
||
|
{
|
||
|
struct net_buf_simple_state state;
|
||
|
uint16_t min_int = min_int_get(s, period_div, base_period);
|
||
|
uint16_t delta = srv->seq - s->state.seq;
|
||
|
int err;
|
||
|
|
||
|
if (delta < min_int) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!s->state.configured &&
|
||
|
(delta < (1 << period_div))) {
|
||
|
/** Don't publish a sensor value with not configured sensor cadence state more
|
||
|
* frequently than base periodic publication.
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
struct sensor_value value[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX] = {};
|
||
|
|
||
|
err = value_get(srv, s, NULL, value);
|
||
|
if (err) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (s->state.configured) {
|
||
|
bool delta_triggered = bt_mesh_sensor_delta_threshold(s, value);
|
||
|
uint16_t interval = pub_int_get(s, period_div);
|
||
|
|
||
|
if (!delta_triggered && delta < interval) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
net_buf_simple_save(srv->pub.msg, &state);
|
||
|
err = sensor_status_encode(srv->pub.msg, s, value);
|
||
|
if (err) {
|
||
|
log_error("Pub sensor value encode for 0x%04x: %d", s->type->id, err);
|
||
|
net_buf_simple_restore(srv->pub.msg, &state);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
s->state.prev = value[0];
|
||
|
s->state.seq = srv->seq;
|
||
|
}
|
||
|
|
||
|
static int update_handler(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
struct bt_mesh_sensor *s;
|
||
|
|
||
|
bt_mesh_model_msg_init(srv->pub.msg, BT_MESH_SENSOR_OP_STATUS);
|
||
|
|
||
|
uint32_t original_len = srv->pub.msg->len;
|
||
|
uint8_t period_div = srv->pub.period_div;
|
||
|
|
||
|
log_debug("#%u Period: %u ms Divisor: %u (%s)", srv->seq,
|
||
|
bt_mesh_model_pub_period_get(model), period_div,
|
||
|
srv->pub.fast_period ? "fast" : "normal");
|
||
|
|
||
|
/** Reset the publication divisor and the fast period divisor flag to get the actual
|
||
|
* publication period.
|
||
|
*/
|
||
|
srv->pub.period_div = 0;
|
||
|
srv->pub.fast_period = 0;
|
||
|
|
||
|
uint32_t base_period = bt_mesh_model_pub_period_get(model);
|
||
|
|
||
|
srv->pub.fast_period = true;
|
||
|
|
||
|
SENSOR_FOR_EACH(&srv->sensors, s) {
|
||
|
pub_msg_add(srv, s, period_div, base_period);
|
||
|
|
||
|
/** Update the publication divisor to a new value. This is needed to take new
|
||
|
* changes in a sensor cadence state, .e.g. when the cadence decreased.
|
||
|
*/
|
||
|
srv->pub.period_div =
|
||
|
MAX(srv->pub.period_div, s->state.pub_div);
|
||
|
}
|
||
|
|
||
|
if (period_div != srv->pub.period_div) {
|
||
|
log_debug("New interval: %u",
|
||
|
bt_mesh_model_pub_period_get(srv->model));
|
||
|
}
|
||
|
|
||
|
srv->seq++;
|
||
|
|
||
|
return (srv->pub.msg->len > original_len) ? 0 : -ENOENT;
|
||
|
}
|
||
|
|
||
|
static int sensor_srv_init(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
|
||
|
sys_slist_init(&srv->sensors);
|
||
|
|
||
|
/* Establish a sorted list of sensors, as this is a requirement when
|
||
|
* sending multiple sensor values in one message.
|
||
|
*/
|
||
|
uint16_t min_id = 0;
|
||
|
|
||
|
for (int count = 0; count < srv->sensor_count; ++count) {
|
||
|
struct bt_mesh_sensor *best = NULL;
|
||
|
|
||
|
for (int j = 0; j < srv->sensor_count; ++j) {
|
||
|
if (srv->sensor_array[j]->type->id >= min_id &&
|
||
|
(!best ||
|
||
|
srv->sensor_array[j]->type->id < best->type->id)) {
|
||
|
best = srv->sensor_array[j];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!best) {
|
||
|
log_error("Duplicate sensor ID");
|
||
|
srv->sensor_count = count;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
sys_slist_append(&srv->sensors, &best->state.node);
|
||
|
log_debug("Sensor 0x%04x", best->type->id);
|
||
|
min_id = best->type->id + 1;
|
||
|
}
|
||
|
|
||
|
srv->seq = 1;
|
||
|
|
||
|
srv->model = model;
|
||
|
|
||
|
srv->pub.update = update_handler;
|
||
|
srv->pub.msg = &srv->pub_buf;
|
||
|
|
||
|
/** Always use fast period to make the server sample sensors with the fastests cadence. */
|
||
|
srv->pub.fast_period = true;
|
||
|
|
||
|
srv->setup_pub.msg = &srv->setup_pub_buf;
|
||
|
net_buf_simple_init_with_data(&srv->pub_buf, srv->pub_data,
|
||
|
sizeof(srv->pub_data));
|
||
|
net_buf_simple_init_with_data(&srv->setup_pub_buf, srv->setup_pub_data,
|
||
|
sizeof(srv->setup_pub_data));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void sensor_srv_reset(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
|
||
|
net_buf_simple_reset(srv->pub.msg);
|
||
|
net_buf_simple_reset(srv->setup_pub.msg);
|
||
|
|
||
|
for (int i = 0; i < srv->sensor_count; ++i) {
|
||
|
struct bt_mesh_sensor *s = srv->sensor_array[i];
|
||
|
|
||
|
s->state.pub_div = 0;
|
||
|
s->state.min_int = 0;
|
||
|
s->state.configured = false;
|
||
|
memset(&s->state.threshold, 0, sizeof(s->state.threshold));
|
||
|
}
|
||
|
|
||
|
srv->pub.period_div = 0;
|
||
|
|
||
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||
|
(void)bt_mesh_model_data_store(srv->model, false, NULL, NULL,
|
||
|
0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int sensor_srv_settings_set(struct bt_mesh_model *model, const char *name,
|
||
|
size_t len_rd, settings_read_cb read_cb,
|
||
|
void *cb_arg)
|
||
|
{
|
||
|
if (!read_cb) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
int err = 0;
|
||
|
|
||
|
NET_BUF_SIMPLE_DEFINE(buf, (CONFIG_BT_MESH_SENSOR_SRV_SENSORS_MAX *
|
||
|
BT_MESH_SENSOR_MSG_MAXLEN_CADENCE_STATUS));
|
||
|
|
||
|
if (name) {
|
||
|
return -ENOENT;
|
||
|
}
|
||
|
|
||
|
ssize_t len = read_cb(cb_arg, net_buf_simple_add(&buf, len_rd), len_rd);
|
||
|
|
||
|
if (len == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (len != len_rd) {
|
||
|
log_error("Failed: %d (expected length %u)", len, len_rd);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
while (buf.len) {
|
||
|
struct bt_mesh_sensor *s;
|
||
|
uint8_t pub_div;
|
||
|
uint16_t id = net_buf_simple_pull_le16(&buf);
|
||
|
|
||
|
s = sensor_get(srv, id);
|
||
|
if (!s) {
|
||
|
err = -ENODEV;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
err = sensor_cadence_decode(&buf, s->type, &pub_div,
|
||
|
&s->state.min_int,
|
||
|
&s->state.threshold);
|
||
|
if (err) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
s->state.pub_div = pub_div;
|
||
|
s->state.configured = true;
|
||
|
|
||
|
/** Update the publication divisor so that the publication timer starts with
|
||
|
* the fastest cadence after settings are loaded.
|
||
|
*/
|
||
|
srv->pub.period_div = MAX(srv->pub.period_div, s->state.pub_div);
|
||
|
}
|
||
|
|
||
|
if (err) {
|
||
|
log_error("Failed: %d", err);
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_model_cb _bt_mesh_sensor_srv_cb = {
|
||
|
.init = sensor_srv_init,
|
||
|
.reset = sensor_srv_reset,
|
||
|
.settings_set = sensor_srv_settings_set,
|
||
|
#if CONFIG_BT_SETTINGS
|
||
|
.pending_store = sensor_srv_pending_store,
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
static int sensor_setup_srv_init(struct bt_mesh_model *model)
|
||
|
{
|
||
|
struct bt_mesh_sensor_srv *srv = model->rt->user_data;
|
||
|
#if (CONFIG_BT_MESH_COMP_PAGE_1)
|
||
|
int err = bt_mesh_model_correspond(model, srv->model);
|
||
|
|
||
|
if (err) {
|
||
|
return err;
|
||
|
}
|
||
|
#endif
|
||
|
#if CONFIG_BT_MESH_MODEL_EXTENSIONS
|
||
|
return bt_mesh_model_extend(model, srv->model);
|
||
|
#else
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
const struct bt_mesh_model_cb _bt_mesh_sensor_setup_srv_cb = {
|
||
|
.init = sensor_setup_srv_init,
|
||
|
};
|
||
|
|
||
|
int bt_mesh_sensor_srv_pub(struct bt_mesh_sensor_srv *srv,
|
||
|
struct bt_mesh_msg_ctx *ctx,
|
||
|
struct bt_mesh_sensor *sensor,
|
||
|
const struct sensor_value *value)
|
||
|
{
|
||
|
int err;
|
||
|
|
||
|
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_STATUS,
|
||
|
BT_MESH_SENSOR_STATUS_MAXLEN);
|
||
|
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_STATUS);
|
||
|
err = sensor_status_encode(&msg, sensor, value);
|
||
|
if (err) {
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
sensor_cadence_update(sensor, value);
|
||
|
|
||
|
err = bt_mesh_msg_send(srv->model, ctx, &msg);
|
||
|
if (err) {
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
sensor->state.prev = value[0];
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int bt_mesh_sensor_srv_sample(struct bt_mesh_sensor_srv *srv,
|
||
|
struct bt_mesh_sensor *sensor)
|
||
|
{
|
||
|
struct sensor_value value[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX] = {};
|
||
|
int err;
|
||
|
|
||
|
err = value_get(srv, sensor, NULL, value);
|
||
|
if (err) {
|
||
|
return -EBUSY;
|
||
|
}
|
||
|
|
||
|
if (sensor->state.configured &&
|
||
|
sensor->type->channel_count == 1 &&
|
||
|
!bt_mesh_sensor_delta_threshold(sensor, value)) {
|
||
|
log_error("Outside threshold");
|
||
|
return -EALREADY;
|
||
|
}
|
||
|
|
||
|
log_debug("Publishing 0x%04x", sensor->type->id);
|
||
|
|
||
|
return bt_mesh_sensor_srv_pub(srv, NULL, sensor, value);
|
||
|
}
|
||
|
|
||
|
#endif /* CONFIG_BT_MESH_SENSOR_SRV */
|