1085 lines
30 KiB
C
1085 lines
30 KiB
C
#include "adaptation.h"
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include "net.h"
|
||
#include "transport.h"
|
||
#include "api/sensor.h"
|
||
#include "api/sensor_cli.h"
|
||
#include "api/properties.h"
|
||
#include "api/sensor_types.h"
|
||
#include <access.h>
|
||
#include "msg.h"
|
||
|
||
#if (CONFIG_BT_MESH_SENSOR_CLI)
|
||
|
||
#define LOG_TAG "[Mesh-sensor_cli]"
|
||
#define LOG_ERROR_ENABLE
|
||
#define LOG_DEBUG_ENABLE
|
||
#define LOG_INFO_ENABLE
|
||
/* #define LOG_DUMP_ENABLE */
|
||
#define LOG_CLI_ENABLE
|
||
#include "debug.h"
|
||
|
||
struct list_rsp {
|
||
struct bt_mesh_sensor_info *sensors;
|
||
uint32_t count;
|
||
};
|
||
|
||
struct settings_rsp {
|
||
uint16_t id;
|
||
uint16_t *ids;
|
||
uint32_t count;
|
||
};
|
||
|
||
struct setting_rsp {
|
||
uint16_t id;
|
||
uint16_t setting_id;
|
||
struct bt_mesh_sensor_setting_status *setting;
|
||
};
|
||
|
||
struct sensor_data_list_rsp {
|
||
struct bt_mesh_sensor_data *sensors;
|
||
uint32_t count;
|
||
};
|
||
|
||
struct series_data_rsp {
|
||
struct bt_mesh_sensor_series_entry *entries;
|
||
const struct bt_mesh_sensor_column *col;
|
||
uint16_t id;
|
||
uint32_t count;
|
||
};
|
||
|
||
struct cadence_rsp {
|
||
uint16_t id;
|
||
struct bt_mesh_sensor_cadence_status *cadence;
|
||
};
|
||
|
||
const struct bt_mesh_sensor_type *bt_mesh_sensor_type_get(uint16_t id)
|
||
{
|
||
// 遍历传感器类型列表
|
||
for (size_t i = 0; i < SENSOR_TYPE_LIST_SIZE; i++) {
|
||
if (sensor_type_list[i]->id == id) {
|
||
return sensor_type_list[i];
|
||
}
|
||
}
|
||
|
||
// 如果找不到匹配的 ID,返回 NULL
|
||
return NULL;
|
||
}
|
||
|
||
|
||
static void unknown_type(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx, uint16_t id, uint32_t op)
|
||
{
|
||
if (cli->cb && cli->cb->unknown_type) {
|
||
cli->cb->unknown_type(cli, ctx, id, op);
|
||
}
|
||
}
|
||
|
||
static int handle_descriptor_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
if (buf->len != 2 && buf->len % 8) {
|
||
return -EMSGSIZE;
|
||
}
|
||
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
struct list_rsp *ack_ctx = NULL;
|
||
uint32_t count = 0;
|
||
|
||
(void)bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_DESCRIPTOR_STATUS,
|
||
ctx->addr, (void **)&ack_ctx);
|
||
|
||
/* A packet with only the sensor ID means that the given sensor doesn't
|
||
* exist on the sensor server.
|
||
*/
|
||
if (buf->len == 2) {
|
||
goto yield_ack;
|
||
}
|
||
|
||
struct bt_mesh_sensor_info sensor;
|
||
|
||
while (buf->len >= 8) {
|
||
|
||
sensor_descriptor_decode(buf, &sensor);
|
||
|
||
if (cli->cb && cli->cb->sensor) {
|
||
cli->cb->sensor(cli, ctx, &sensor);
|
||
}
|
||
|
||
if (ack_ctx && count < ack_ctx->count) {
|
||
ack_ctx->sensors[count++] = sensor;
|
||
}
|
||
}
|
||
|
||
yield_ack:
|
||
if (ack_ctx) {
|
||
ack_ctx->count = count;
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int handle_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
struct sensor_data_list_rsp *rsp = NULL;
|
||
uint32_t count = 0;
|
||
int err;
|
||
|
||
(void)bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_STATUS, ctx->addr,
|
||
(void **)&rsp);
|
||
log_debug_hexdump(buf->data, buf->len);
|
||
while (buf->len) {
|
||
const struct bt_mesh_sensor_type *type;
|
||
uint8_t length;
|
||
uint16_t id;
|
||
|
||
sensor_status_id_decode(buf, &length, &id);
|
||
|
||
if (length == 0) {
|
||
if (rsp && rsp->count == 1 && rsp->sensors[0].type &&
|
||
rsp->sensors[0].type->id == id) {
|
||
rsp->sensors[0].type = NULL;
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
rsp = NULL;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
type = bt_mesh_sensor_type_get(id);
|
||
if (!type) {
|
||
if (buf->len < length) {
|
||
log_error("Invalid length for 0x%04x: %u", id,
|
||
length);
|
||
return -EMSGSIZE;
|
||
}
|
||
net_buf_simple_pull(buf, length);
|
||
unknown_type(cli, ctx, id, BT_MESH_SENSOR_OP_STATUS);
|
||
continue;
|
||
}
|
||
|
||
uint8_t expected_len = sensor_value_len(type);
|
||
if (length != expected_len) {
|
||
log_error("Invalid length for 0x%04x: %u (expected %u)",
|
||
id, length, expected_len);
|
||
return -EMSGSIZE;
|
||
}
|
||
|
||
struct sensor_value value[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX];
|
||
err = sensor_value_decode(buf, type, value);
|
||
if (err) {
|
||
log_error("Invalid format, err=%d", err);
|
||
return err; /* Invalid format, should ignore message */
|
||
}
|
||
if (cli->cb && cli->cb->data) {
|
||
cli->cb->data(cli, ctx, type, value);
|
||
}
|
||
|
||
if (rsp && count <= rsp->count) {
|
||
memcpy(rsp->sensors[count].value, value,
|
||
sizeof(struct sensor_value) *
|
||
type->channel_count);
|
||
|
||
rsp->sensors[count].type = type;
|
||
++count;
|
||
}
|
||
}
|
||
|
||
if (rsp) {
|
||
rsp->count = count;
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int parse_series_entry(const struct bt_mesh_sensor_type *type,
|
||
const struct bt_mesh_sensor_format *col_format,
|
||
struct net_buf_simple *buf,
|
||
struct bt_mesh_sensor_series_entry *entry)
|
||
{
|
||
if (col_format == NULL) {
|
||
// Indexed column, decode only value
|
||
memset(entry, 0, sizeof(struct bt_mesh_sensor_series_entry));
|
||
return sensor_value_decode(buf, type, entry->value);
|
||
}
|
||
|
||
return sensor_column_decode(buf, type, &entry->column, entry->value);
|
||
}
|
||
|
||
static int handle_column_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
struct series_data_rsp *rsp;
|
||
const struct bt_mesh_sensor_format *col_format;
|
||
const struct bt_mesh_sensor_type *type;
|
||
int err;
|
||
|
||
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
||
type = bt_mesh_sensor_type_get(id);
|
||
if (!type) {
|
||
unknown_type(cli, ctx, id, BT_MESH_SENSOR_OP_COLUMN_STATUS);
|
||
return -ENOENT;
|
||
}
|
||
|
||
struct bt_mesh_sensor_series_entry entry;
|
||
|
||
col_format = bt_mesh_sensor_column_format_get(type);
|
||
|
||
err = parse_series_entry(type, col_format, buf, &entry);
|
||
if (err == -ENOENT) {
|
||
/* The entry doesn't exist */
|
||
goto yield_ack;
|
||
}
|
||
|
||
if (err) {
|
||
return err; /* Invalid format, should ignore message */
|
||
}
|
||
|
||
if (cli->cb && cli->cb->series_entry) {
|
||
cli->cb->series_entry(cli, ctx, type, 0, 1, &entry);
|
||
}
|
||
|
||
yield_ack:
|
||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_COLUMN_STATUS, ctx->addr,
|
||
(void **)&rsp)) {
|
||
/* If column format exists verify Raw Value A */
|
||
if (col_format &&
|
||
(rsp->col->start.val1 != entry.column.start.val1 ||
|
||
rsp->col->start.val2 != entry.column.start.val2)) {
|
||
return 0;
|
||
}
|
||
|
||
if (err) {
|
||
rsp->count = 0;
|
||
} else {
|
||
rsp->entries[0] = entry;
|
||
rsp->count = 1;
|
||
}
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int handle_series_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
const struct bt_mesh_sensor_format *col_format;
|
||
const struct bt_mesh_sensor_type *type;
|
||
struct series_data_rsp *rsp = NULL;
|
||
|
||
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
|
||
type = bt_mesh_sensor_type_get(id);
|
||
if (!type) {
|
||
unknown_type(cli, ctx, id, BT_MESH_SENSOR_OP_SERIES_STATUS);
|
||
return -ENOENT;
|
||
}
|
||
|
||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_SERIES_STATUS, ctx->addr,
|
||
(void **)&rsp)) {
|
||
if (rsp->id != id) {
|
||
rsp = NULL;
|
||
}
|
||
}
|
||
|
||
size_t val_len = sensor_value_len(type);
|
||
|
||
col_format = bt_mesh_sensor_column_format_get(type);
|
||
if (col_format != NULL) {
|
||
val_len += (col_format->size * 2);
|
||
}
|
||
|
||
if (!val_len) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
uint8_t count = buf->len / val_len;
|
||
|
||
for (uint8_t i = 0; i < count; i++) {
|
||
struct bt_mesh_sensor_series_entry entry;
|
||
int err;
|
||
|
||
err = parse_series_entry(type, col_format, buf, &entry);
|
||
if (err) {
|
||
log_error("Failed parsing column %u (err: %d)", i, err);
|
||
return err;
|
||
}
|
||
|
||
if (cli->cb && cli->cb->series_entry) {
|
||
cli->cb->series_entry(cli, ctx, type, i, count, &entry);
|
||
}
|
||
|
||
if (rsp && i < rsp->count) {
|
||
rsp->entries[i] = entry;
|
||
}
|
||
}
|
||
|
||
if (rsp) {
|
||
rsp->count = count;
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int handle_cadence_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
struct cadence_rsp *rsp;
|
||
int err;
|
||
|
||
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
const struct bt_mesh_sensor_type *type = bt_mesh_sensor_type_get(id);
|
||
|
||
if (!type) {
|
||
unknown_type(cli, ctx, id, BT_MESH_SENSOR_OP_CADENCE_STATUS);
|
||
return -ENOENT;
|
||
}
|
||
|
||
if (buf->len == 0 || type->channel_count != 1) {
|
||
log_error("Type 0x%04x doesn't support cadence", id);
|
||
err = -ENOTSUP;
|
||
goto yield_ack;
|
||
}
|
||
|
||
struct bt_mesh_sensor_cadence_status cadence;
|
||
|
||
err = sensor_cadence_decode(buf, type, &cadence.fast_period_div,
|
||
&cadence.min_int, &cadence.threshold);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
if (cli->cb && cli->cb->cadence) {
|
||
cli->cb->cadence(cli, ctx, type, &cadence);
|
||
}
|
||
|
||
yield_ack:
|
||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_CADENCE_STATUS, ctx->addr,
|
||
(void **)&rsp) &&
|
||
rsp->id == id) {
|
||
if (err) {
|
||
rsp->cadence = NULL;
|
||
} else {
|
||
*rsp->cadence = cadence;
|
||
}
|
||
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int handle_settings_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
struct settings_rsp *rsp;
|
||
|
||
if (buf->len % 2) {
|
||
return -EMSGSIZE;
|
||
}
|
||
|
||
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
const struct bt_mesh_sensor_type *type = bt_mesh_sensor_type_get(id);
|
||
|
||
if (!type) {
|
||
unknown_type(cli, ctx, id, BT_MESH_SENSOR_OP_SETTINGS_STATUS);
|
||
return -ENOENT;
|
||
}
|
||
|
||
/* The list may be unaligned: */
|
||
uint16_t ids[(BT_MESH_RX_SDU_MAX -
|
||
BT_MESH_MODEL_OP_LEN(BT_MESH_SENSOR_OP_SETTINGS_STATUS) -
|
||
2) /
|
||
sizeof(uint16_t)];
|
||
uint32_t count = buf->len / 2;
|
||
|
||
memcpy(ids, net_buf_simple_pull_mem(buf, buf->len),
|
||
count * sizeof(uint16_t));
|
||
|
||
if (cli->cb && cli->cb->settings) {
|
||
cli->cb->settings(cli, ctx, type, ids, count);
|
||
}
|
||
|
||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_SETTINGS_STATUS, ctx->addr,
|
||
(void **)&rsp) &&
|
||
rsp->id == id) {
|
||
memcpy(rsp->ids, ids, sizeof(uint16_t) * MIN(count, rsp->count));
|
||
rsp->count = count;
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int handle_setting_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||
struct net_buf_simple *buf)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
struct setting_rsp *rsp;
|
||
int err;
|
||
|
||
uint16_t id = net_buf_simple_pull_le16(buf);
|
||
uint16_t setting_id = net_buf_simple_pull_le16(buf);
|
||
struct bt_mesh_sensor_setting_status setting = { 0 };
|
||
uint8_t access;
|
||
|
||
if (buf->len == 0) {
|
||
goto yield_ack;
|
||
}
|
||
|
||
access = net_buf_simple_pull_u8(buf);
|
||
if (access != 0x01 && access != 0x03) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
const struct bt_mesh_sensor_type *type = bt_mesh_sensor_type_get(id);
|
||
|
||
if (!type) {
|
||
unknown_type(cli, ctx, id, BT_MESH_SENSOR_OP_SETTING_STATUS);
|
||
return -ENOENT;
|
||
}
|
||
|
||
|
||
setting.type = bt_mesh_sensor_type_get(setting_id);
|
||
if (!setting.type) {
|
||
unknown_type(
|
||
cli, ctx, setting_id, BT_MESH_SENSOR_OP_SETTING_STATUS);
|
||
return -ENOENT;
|
||
}
|
||
|
||
setting.writable = (access == 0x03);
|
||
|
||
/* If we attempted setting an unwritable value, the server omits the
|
||
* setting value. This is a legal response, but it should make the set()
|
||
* function return -EACCES.
|
||
*/
|
||
if (buf->len == 0 && !setting.writable) {
|
||
goto yield_ack;
|
||
}
|
||
|
||
err = sensor_value_decode(buf, setting.type, setting.value);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
if (cli->cb && cli->cb->setting_status) {
|
||
cli->cb->setting_status(cli, ctx, type, &setting);
|
||
}
|
||
|
||
yield_ack:
|
||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, BT_MESH_SENSOR_OP_SETTING_STATUS, ctx->addr,
|
||
(void **)&rsp) &&
|
||
rsp->id == id && rsp->setting_id == setting_id) {
|
||
*rsp->setting = setting;
|
||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
const struct bt_mesh_model_op _bt_mesh_sensor_cli_op[] = {
|
||
{
|
||
BT_MESH_SENSOR_OP_DESCRIPTOR_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_DESCRIPTOR_STATUS),
|
||
handle_descriptor_status,
|
||
},
|
||
{
|
||
BT_MESH_SENSOR_OP_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_STATUS),
|
||
handle_status,
|
||
},
|
||
{
|
||
BT_MESH_SENSOR_OP_COLUMN_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_COLUMN_STATUS),
|
||
handle_column_status,
|
||
},
|
||
{
|
||
BT_MESH_SENSOR_OP_SERIES_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_SERIES_STATUS),
|
||
handle_series_status,
|
||
},
|
||
{
|
||
BT_MESH_SENSOR_OP_CADENCE_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_CADENCE_STATUS),
|
||
handle_cadence_status,
|
||
},
|
||
{
|
||
BT_MESH_SENSOR_OP_SETTINGS_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_SETTINGS_STATUS),
|
||
handle_settings_status,
|
||
},
|
||
{
|
||
BT_MESH_SENSOR_OP_SETTING_STATUS,
|
||
BT_MESH_LEN_MIN(BT_MESH_SENSOR_MSG_MINLEN_SETTING_STATUS),
|
||
handle_setting_status,
|
||
},
|
||
BT_MESH_MODEL_OP_END,
|
||
};
|
||
|
||
static int sensor_cli_init(struct bt_mesh_model *model)
|
||
{
|
||
struct bt_mesh_sensor_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 sensor_cli_reset(struct bt_mesh_model *model)
|
||
{
|
||
struct bt_mesh_sensor_cli *cli = model->rt->user_data;
|
||
|
||
net_buf_simple_reset(cli->pub.msg);
|
||
bt_mesh_msg_ack_ctx_reset(&cli->ack_ctx);
|
||
}
|
||
|
||
const struct bt_mesh_model_cb _bt_mesh_sensor_cli_cb = {
|
||
.init = sensor_cli_init,
|
||
.reset = sensor_cli_reset,
|
||
};
|
||
|
||
int bt_mesh_sensor_cli_desc_all_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
struct bt_mesh_sensor_info *sensors,
|
||
uint32_t *count)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_DESCRIPTOR_GET,
|
||
BT_MESH_SENSOR_MSG_MINLEN_DESCRIPTOR_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_DESCRIPTOR_GET);
|
||
|
||
struct list_rsp list_rsp = {
|
||
.sensors = sensors,
|
||
.count = count ? *count : 0,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_DESCRIPTOR_STATUS,
|
||
.user_data = &list_rsp,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, sensors ? &rsp_ctx : NULL);
|
||
if (count && !err) {
|
||
*count = list_rsp.count;
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_desc_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
struct bt_mesh_sensor_descriptor *rsp)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_DESCRIPTOR_GET,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_DESCRIPTOR_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_DESCRIPTOR_GET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
struct bt_mesh_sensor_info info = {
|
||
sensor->id,
|
||
};
|
||
struct list_rsp list_rsp = {
|
||
.sensors = &info,
|
||
.count = 1,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_DESCRIPTOR_STATUS,
|
||
.user_data = &list_rsp,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
if (list_rsp.count == 0) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
*rsp = info.descriptor;
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_cadence_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
struct bt_mesh_sensor_cadence_status *rsp)
|
||
{
|
||
if (sensor->channel_count != 1) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_CADENCE_GET, 2);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_CADENCE_GET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
struct cadence_rsp rsp_data = {
|
||
.id = sensor->id,
|
||
.cadence = rsp,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_CADENCE_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
/* Status handler clears the cadence member if server indicates that
|
||
* cadence isn't supported.
|
||
*/
|
||
if (!rsp_data.cadence) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_cadence_set(
|
||
struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_cadence_status *cadence,
|
||
struct bt_mesh_sensor_cadence_status *rsp)
|
||
{
|
||
if (sensor->channel_count != 1) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_CADENCE_SET,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_CADENCE_SET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_CADENCE_SET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
struct cadence_rsp rsp_data = {
|
||
.id = sensor->id,
|
||
.cadence = rsp,
|
||
};
|
||
|
||
err = sensor_cadence_encode(&msg, sensor, cadence->fast_period_div,
|
||
cadence->min_int, &cadence->threshold);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_CADENCE_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
/* Status handler clears the cadence member if server indicates that
|
||
* cadence isn't supported.
|
||
*/
|
||
if (!rsp_data.cadence) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_cadence_set_unack(
|
||
struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_cadence_status *cadence)
|
||
{
|
||
if (sensor->channel_count != 1) {
|
||
return -ENOTSUP;
|
||
}
|
||
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg,
|
||
BT_MESH_SENSOR_OP_CADENCE_SET_UNACKNOWLEDGED,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_CADENCE_SET);
|
||
bt_mesh_model_msg_init(&msg,
|
||
BT_MESH_SENSOR_OP_CADENCE_SET_UNACKNOWLEDGED);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
err = sensor_cadence_encode(&msg, sensor, cadence->fast_period_div,
|
||
cadence->min_int, &cadence->threshold);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
return bt_mesh_msg_send(cli->model, ctx, &msg);
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_settings_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
uint16_t *ids, uint32_t *count)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_SETTINGS_GET,
|
||
BT_MESH_SENSOR_MSG_LEN_SETTINGS_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_SETTINGS_GET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
struct settings_rsp rsp = {
|
||
.id = sensor->id,
|
||
.ids = ids,
|
||
.count = count ? *count : 0,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_SETTINGS_STATUS,
|
||
.user_data = &rsp,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, ids ? &rsp_ctx : NULL);
|
||
if (!count || err) {
|
||
return err;
|
||
}
|
||
|
||
*count = rsp.count;
|
||
|
||
return err;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_setting_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_type *setting,
|
||
struct bt_mesh_sensor_setting_status *rsp)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_SETTING_GET,
|
||
BT_MESH_SENSOR_MSG_LEN_SETTING_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_SETTING_GET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
net_buf_simple_add_le16(&msg, setting->id);
|
||
|
||
struct setting_rsp rsp_data = {
|
||
.id = sensor->id,
|
||
.setting_id = setting->id,
|
||
.setting = rsp,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_SETTING_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
if (!rsp->type) {
|
||
return -ENOENT;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_setting_set(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_type *setting,
|
||
const struct sensor_value *value,
|
||
struct bt_mesh_sensor_setting_status *rsp)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_SETTING_SET,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_SETTING_SET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_SETTING_SET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
net_buf_simple_add_le16(&msg, setting->id);
|
||
err = sensor_value_encode(&msg, setting, value);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
struct setting_rsp rsp_data = {
|
||
.id = sensor->id,
|
||
.setting_id = setting->id,
|
||
.setting = rsp,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_SETTING_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
if (!rsp->type) {
|
||
return -ENOENT;
|
||
}
|
||
|
||
if (!rsp->writable) {
|
||
return -EACCES;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_setting_set_unack(
|
||
struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_type *setting,
|
||
const struct sensor_value *value)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_SETTING_SET_UNACKNOWLEDGED,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_SETTING_SET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_SETTING_SET_UNACKNOWLEDGED);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
net_buf_simple_add_le16(&msg, setting->id);
|
||
err = sensor_value_encode(&msg, setting, value);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
return bt_mesh_msg_send(cli->model, ctx, &msg);
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_all_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
struct bt_mesh_sensor_data *sensors,
|
||
uint32_t *count)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_GET,
|
||
BT_MESH_SENSOR_MSG_MINLEN_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_GET);
|
||
|
||
struct sensor_data_list_rsp rsp_data = { .count = count ? *count : 0,
|
||
.sensors = sensors
|
||
};
|
||
|
||
if (sensors && count) {
|
||
memset(sensors, 0, sizeof(*sensors) * (*count));
|
||
}
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, sensors ? &rsp_ctx : NULL);
|
||
if (!count || err) {
|
||
return err;
|
||
}
|
||
|
||
if (rsp_data.count == 0) {
|
||
return -ENODEV;
|
||
}
|
||
|
||
*count = rsp_data.count;
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_get(struct bt_mesh_sensor_cli *cli,
|
||
struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
struct sensor_value *rsp)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_GET,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_GET);
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
struct bt_mesh_sensor_data sensor_data = {
|
||
.type = sensor,
|
||
};
|
||
struct sensor_data_list_rsp rsp_data = { .count = 1,
|
||
.sensors = &sensor_data
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
if (!sensor_data.type) {
|
||
return -ENODEV;
|
||
}
|
||
|
||
memcpy(rsp, sensor_data.value, sizeof(struct sensor_value) * sensor->channel_count);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_series_entry_get(
|
||
struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_column *column,
|
||
struct bt_mesh_sensor_series_entry *rsp)
|
||
{
|
||
const struct bt_mesh_sensor_format *col_format;
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_COLUMN_GET,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_COLUMN_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_COLUMN_GET);
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
col_format = bt_mesh_sensor_column_format_get(sensor);
|
||
if (col_format == NULL) {
|
||
net_buf_simple_add_le16(&msg, column->start.val1);
|
||
} else {
|
||
err = sensor_ch_encode(&msg, col_format, &column->start);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
}
|
||
|
||
struct series_data_rsp rsp_data = {
|
||
.entries = rsp,
|
||
.id = sensor->id,
|
||
.count = 1,
|
||
.col = column,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_COLUMN_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!rsp || err) {
|
||
return err;
|
||
}
|
||
|
||
if (rsp_data.count == 0) {
|
||
return -ENOENT;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int bt_mesh_sensor_cli_series_entries_get(
|
||
struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
|
||
const struct bt_mesh_sensor_type *sensor,
|
||
const struct bt_mesh_sensor_column *range,
|
||
struct bt_mesh_sensor_series_entry *rsp, uint32_t *count)
|
||
{
|
||
int err;
|
||
|
||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_SENSOR_OP_SERIES_GET,
|
||
BT_MESH_SENSOR_MSG_MAXLEN_SERIES_GET);
|
||
bt_mesh_model_msg_init(&msg, BT_MESH_SENSOR_OP_SERIES_GET);
|
||
|
||
net_buf_simple_add_le16(&msg, sensor->id);
|
||
|
||
if (range) {
|
||
const struct bt_mesh_sensor_format *col_format;
|
||
|
||
col_format = bt_mesh_sensor_column_format_get(sensor);
|
||
|
||
if (!col_format) {
|
||
net_buf_simple_add_le16(&msg, range->start.val1);
|
||
net_buf_simple_add_le16(&msg, range->end.val1);
|
||
} else {
|
||
err = sensor_ch_encode(&msg, col_format, &range->start);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
|
||
err = sensor_ch_encode(&msg, col_format, &range->end);
|
||
if (err) {
|
||
return err;
|
||
}
|
||
}
|
||
}
|
||
|
||
struct series_data_rsp rsp_data = {
|
||
.entries = rsp,
|
||
.id = sensor->id,
|
||
.count = count ? *count : 0,
|
||
};
|
||
|
||
struct bt_mesh_msg_rsp_ctx rsp_ctx = {
|
||
.ack = &cli->ack_ctx,
|
||
.op = BT_MESH_SENSOR_OP_SERIES_STATUS,
|
||
.user_data = &rsp_data,
|
||
.timeout = model_ackd_timeout_get(cli->model, ctx),
|
||
};
|
||
|
||
err = bt_mesh_msg_ackd_send(cli->model, ctx, &msg, rsp ? &rsp_ctx : NULL);
|
||
if (!count || err) {
|
||
return err;
|
||
}
|
||
|
||
*count = rsp_data.count;
|
||
|
||
return 0;
|
||
}
|
||
#endif |