/* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include "syscfg/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 void 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; } 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); } static void 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; } 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); } 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; }