/*
|
* Copyright (c) 2017 Intel Corporation
|
*
|
* SPDX-License-Identifier: Apache-2.0
|
*/
|
|
#include "nimble_syscfg.h"
|
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
|
|
#include "mesh/mesh.h"
|
#include "mesh/model_cli.h"
|
#include "mesh_priv.h"
|
|
static int32_t msg_timeout = K_SECONDS(5);
|
|
static struct bt_mesh_gen_model_cli *gen_onoff_cli;
|
static struct bt_mesh_gen_model_cli *gen_level_cli;
|
|
static uint8_t transaction_id = 0;
|
|
struct gen_onoff_param {
|
uint8_t *state;
|
};
|
|
struct gen_level_param {
|
int16_t *level;
|
};
|
|
static int gen_onoff_status(struct bt_mesh_model *model,
|
struct bt_mesh_msg_ctx *ctx,
|
struct os_mbuf *buf)
|
{
|
struct bt_mesh_gen_model_cli *cli = model->user_data;
|
struct gen_onoff_param *param;
|
uint8_t state;
|
|
|
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
|
ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
|
bt_hex(buf->om_data, buf->om_len));
|
|
if (cli->op_pending != OP_GEN_ONOFF_STATUS) {
|
BT_WARN("Unexpected Generic OnOff Status message");
|
return -ENOENT;
|
}
|
|
param = cli->op_param;
|
|
state = net_buf_simple_pull_u8(buf);
|
if (param->state) {
|
*param->state = state;
|
}
|
|
BT_DBG("state: %d", state);
|
|
k_sem_give(&cli->op_sync);
|
|
return 0;
|
}
|
|
static int gen_level_status(struct bt_mesh_model *model,
|
struct bt_mesh_msg_ctx *ctx,
|
struct os_mbuf *buf)
|
{
|
struct bt_mesh_gen_model_cli *cli = model->user_data;
|
struct gen_level_param *param;
|
int16_t level;
|
|
|
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
|
ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
|
bt_hex(buf->om_data, buf->om_len));
|
|
if (cli->op_pending != OP_GEN_LEVEL_STATUS) {
|
BT_WARN("Unexpected Generic LEVEL Status message");
|
return -EINVAL;
|
}
|
|
param = cli->op_param;
|
|
level = net_buf_simple_pull_le16(buf);
|
if (param->level) {
|
*param->level = level;
|
}
|
|
BT_DBG("level: %d", level);
|
|
k_sem_give(&cli->op_sync);
|
|
return 0;
|
}
|
|
const struct bt_mesh_model_op gen_onoff_cli_op[] = {
|
{ OP_GEN_ONOFF_STATUS, 1, gen_onoff_status },
|
BT_MESH_MODEL_OP_END,
|
};
|
|
static int onoff_cli_init(struct bt_mesh_model *model)
|
{
|
BT_DBG("");
|
|
if (!model->user_data) {
|
BT_ERR("No Generic OnOff Client context provided");
|
return -EINVAL;
|
}
|
|
gen_onoff_cli = model->user_data;
|
gen_onoff_cli->model = model;
|
|
k_sem_init(&gen_onoff_cli->op_sync, 0, 1);
|
|
return 0;
|
}
|
|
const struct bt_mesh_model_cb bt_mesh_gen_onoff_cli_cb = {
|
.init = onoff_cli_init,
|
};
|
|
const struct bt_mesh_model_op gen_level_cli_op[] = {
|
{ OP_GEN_LEVEL_STATUS, 2, gen_level_status },
|
BT_MESH_MODEL_OP_END,
|
};
|
|
static int level_cli_init(struct bt_mesh_model *model)
|
{
|
BT_DBG("");
|
|
if (!model->user_data) {
|
BT_ERR("No Generic Level Client context provided");
|
return -EINVAL;
|
}
|
|
gen_level_cli = model->user_data;
|
gen_level_cli->model = model;
|
|
k_sem_init(&gen_level_cli->op_sync, 0, 1);
|
|
return 0;
|
}
|
|
const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb = {
|
.init = level_cli_init,
|
};
|
|
static int cli_wait(struct bt_mesh_gen_model_cli *cli, void *param, uint32_t op)
|
{
|
int err;
|
|
BT_DBG("");
|
|
cli->op_param = param;
|
cli->op_pending = op;
|
|
err = k_sem_take(&cli->op_sync, msg_timeout);
|
|
cli->op_pending = 0;
|
cli->op_param = NULL;
|
|
return err;
|
}
|
|
int bt_mesh_gen_onoff_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
|
uint8_t *state)
|
{
|
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
|
struct bt_mesh_msg_ctx ctx = {
|
.net_idx = net_idx,
|
.app_idx = app_idx,
|
.addr = addr,
|
.send_ttl = BT_MESH_TTL_DEFAULT,
|
};
|
struct gen_onoff_param param = {
|
.state = state,
|
};
|
int err;
|
|
bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_GET);
|
|
err = bt_mesh_model_send(gen_onoff_cli->model, &ctx, msg, NULL, NULL);
|
if (err) {
|
BT_ERR("model_send() failed (err %d)", err);
|
goto done;
|
}
|
|
err = cli_wait(gen_onoff_cli, ¶m, OP_GEN_ONOFF_STATUS);
|
done:
|
os_mbuf_free_chain(msg);
|
return err;
|
}
|
|
int bt_mesh_gen_onoff_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
|
uint8_t val, uint8_t *state)
|
{
|
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
|
struct bt_mesh_msg_ctx ctx = {
|
.net_idx = net_idx,
|
.app_idx = app_idx,
|
.addr = addr,
|
.send_ttl = BT_MESH_TTL_DEFAULT,
|
};
|
struct gen_onoff_param param = {
|
.state = state,
|
};
|
int err;
|
|
if (state) {
|
bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_SET);
|
} else {
|
bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_SET_UNACK);
|
}
|
|
net_buf_simple_add_u8(msg, val);
|
net_buf_simple_add_u8(msg, transaction_id);
|
|
err = bt_mesh_model_send(gen_onoff_cli->model, &ctx, msg, NULL, NULL);
|
if (err) {
|
BT_ERR("model_send() failed (err %d)", err);
|
goto done;
|
}
|
|
if (!state) {
|
goto done;
|
}
|
|
err = cli_wait(gen_onoff_cli, ¶m, OP_GEN_ONOFF_STATUS);
|
done:
|
if (err == 0) {
|
transaction_id++;
|
}
|
os_mbuf_free_chain(msg);
|
return err;
|
}
|
|
int bt_mesh_gen_level_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
|
int16_t *level)
|
{
|
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
|
struct bt_mesh_msg_ctx ctx = {
|
.net_idx = net_idx,
|
.app_idx = app_idx,
|
.addr = addr,
|
.send_ttl = BT_MESH_TTL_DEFAULT,
|
};
|
struct gen_level_param param = {
|
.level = level,
|
};
|
int err;
|
|
bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_GET);
|
|
err = bt_mesh_model_send(gen_level_cli->model, &ctx, msg, NULL, NULL);
|
if (err) {
|
BT_ERR("model_send() failed (err %d)", err);
|
goto done;
|
}
|
|
err = cli_wait(gen_level_cli, ¶m, OP_GEN_LEVEL_STATUS);
|
done:
|
os_mbuf_free_chain(msg);
|
return err;
|
}
|
|
int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
|
int16_t val, int16_t *state)
|
{
|
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
|
struct bt_mesh_msg_ctx ctx = {
|
.net_idx = net_idx,
|
.app_idx = app_idx,
|
.addr = addr,
|
.send_ttl = BT_MESH_TTL_DEFAULT,
|
};
|
struct gen_level_param param = {
|
.level = state,
|
};
|
int err;
|
|
if (state) {
|
bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_SET);
|
} else {
|
bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_SET_UNACK);
|
}
|
|
net_buf_simple_add_le16(msg, val);
|
net_buf_simple_add_u8(msg, transaction_id);
|
|
err = bt_mesh_model_send(gen_level_cli->model, &ctx, msg, NULL, NULL);
|
if (err) {
|
BT_ERR("model_send() failed (err %d)", err);
|
goto done;
|
}
|
|
if (!state) {
|
goto done;
|
}
|
|
err = cli_wait(gen_level_cli, ¶m, OP_GEN_LEVEL_STATUS);
|
done:
|
if (err == 0) {
|
transaction_id++;
|
}
|
os_mbuf_free_chain(msg);
|
return err;
|
}
|