diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-03-28 14:32:49 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-03-28 14:32:49 +1100 |
| commit | ee29c25b29eaa4fac4e897442634b69ecc8d8125 (patch) | |
| tree | 8c5f1a140463f20f104316fa3492984e191154e9 /lib/bt/esp_ble_mesh/models/client | |
| parent | 239e6d89507a24c849385f4bfa93ac4ad58e5de5 (diff) | |
| download | tangara-fw-ee29c25b29eaa4fac4e897442634b69ecc8d8125.tar.gz | |
Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
Diffstat (limited to 'lib/bt/esp_ble_mesh/models/client')
10 files changed, 5705 insertions, 0 deletions
diff --git a/lib/bt/esp_ble_mesh/models/client/client_common.c b/lib/bt/esp_ble_mesh/models/client/client_common.c new file mode 100644 index 00000000..db878516 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/client_common.c @@ -0,0 +1,492 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> +#include <errno.h> + +#include "mesh.h" +#include "mesh/main.h" +#include "transport.h" +#include "foundation.h" +#include "mesh/client_common.h" +#include "mesh/common.h" + +#include "mesh_v1.1/utils.h" + +#define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */ + +static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16_t tx_dst) +{ + bt_mesh_client_node_t *node = NULL; + sys_snode_t *cur = NULL; + + bt_mesh_list_lock(); + if (sys_slist_is_empty(list)) { + bt_mesh_list_unlock(); + return NULL; + } + + for (cur = sys_slist_peek_head(list); + cur != NULL; cur = sys_slist_peek_next(cur)) { + node = (bt_mesh_client_node_t *)cur; + if (node->ctx.addr == tx_dst) { + bt_mesh_list_unlock(); + return node; + } + } + + bt_mesh_list_unlock(); + return NULL; +} + +bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, bool need_pub) +{ + bt_mesh_client_internal_data_t *data = NULL; + bt_mesh_client_user_data_t *cli = NULL; + bt_mesh_client_node_t *node = NULL; + + if (!model || !ctx || !buf) { + BT_ERR("%s, Invalid parameter", __func__); + return NULL; + } + + cli = (bt_mesh_client_user_data_t *)model->user_data; + if (!cli) { + BT_ERR("Invalid client user data"); + return NULL; + } + + /** If the received message address is not a unicast address, + * the address may be a group/virtual address, and we push + * this message to the application layer. + */ + if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { + BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + if (cli->publish_status && need_pub) { + cli->publish_status(ctx->recv_op, model, ctx, buf); + } + return NULL; + } + + /** If the source address of the received status message is + * different with the destination address of the sending + * message, then the message is from another element and + * push it to application layer. + */ + data = (bt_mesh_client_internal_data_t *)cli->internal_data; + if (!data) { + BT_ERR("Invalid client internal data"); + return NULL; + } + + if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) { + BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + if (cli->publish_status && need_pub) { + cli->publish_status(ctx->recv_op, model, ctx, buf); + } + return NULL; + } + + if (node->op_pending != ctx->recv_op) { + BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + if (cli->publish_status && need_pub) { + cli->publish_status(ctx->recv_op, model, ctx, buf); + } + return NULL; + } + + if (k_delayed_work_remaining_get(&node->timer) == 0) { + BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + if (cli->publish_status && need_pub) { + cli->publish_status(ctx->recv_op, model, ctx, buf); + } + return NULL; + } + + return node; +} + +static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, uint16_t tx_dst) +{ + bt_mesh_client_node_t *node = NULL; + sys_snode_t *cur = NULL; + + bt_mesh_list_lock(); + if (sys_slist_is_empty(list)) { + bt_mesh_list_unlock(); + return false; + } + + for (cur = sys_slist_peek_head(list); + cur != NULL; cur = sys_slist_peek_next(cur)) { + node = (bt_mesh_client_node_t *)cur; + if (node->ctx.addr == tx_dst) { + bt_mesh_list_unlock(); + return true; + } + } + + bt_mesh_list_unlock(); + return false; +} + +static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, + int size, uint32_t opcode) +{ + if (!op_pair || size == 0) { + return 0; + } + + const bt_mesh_client_op_pair_t *op = op_pair; + for (int i = 0; i < size; i++) { + if (op->cli_op == opcode) { + return op->status_op; + } + op++; + } + + return 0; +} + +static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) +{ + uint16_t duration = 0, adv_int = 0; + uint8_t xmit = 0; + + /* Initialize with network transmission */ + xmit = bt_mesh_net_transmit_get(); + + if (bt_mesh_tag_immutable_cred(ctx->send_tag)) { +#if CONFIG_BLE_MESH_DF_SRV + if (ctx->send_cred == BLE_MESH_DIRECTED_CRED) { + xmit = bt_mesh_direct_net_transmit_get(); /* Directed network transmission */ + } +#endif + } + + adv_int = BLE_MESH_TRANSMIT_INT(xmit); + duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + + return (int32_t)duration; +} + +static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + uint32_t opcode, int32_t timeout) +{ + int32_t seg_rtx_to = 0, duration = 0, time = 0; + uint8_t seg_count = 0, seg_rtx_num = 0; + bool need_seg = false; + uint8_t mic_size = 0; + + if (msg->len > BLE_MESH_SDU_UNSEG_MAX || + bt_mesh_tag_send_segmented(ctx->send_tag)) { + need_seg = true; /* Needs segmentation */ + } + + mic_size = (need_seg && ctx->send_szmic == BLE_MESH_SEG_SZMIC_LONG && + net_buf_simple_tailroom(msg) >= BLE_MESH_MIC_LONG) ? + BLE_MESH_MIC_LONG : BLE_MESH_MIC_SHORT; + + if (need_seg) { + /* Based on the message length, calculate how many segments are needed. + * All the messages sent from here are access messages. + */ + seg_rtx_num = bt_mesh_get_seg_rtx_num(); + seg_rtx_to = bt_mesh_get_seg_rtx_timeout(ctx->addr, ctx->send_ttl); + seg_count = (msg->len + mic_size - 1) / 12U + 1U; + + duration = bt_mesh_get_adv_duration(ctx); + + /* Currently only consider the time consumption of the same segmented + * messages, but if there are other messages between any two retrans- + * missions of the same segmented messages, then the whole time will + * be longer. + * + * Since the transport behavior has been changed, i.e. start retransmit + * timer after the last segment is sent, so we can simplify the timeout + * calculation here. And the retransmit timer will be started event if + * the attempts reaches ZERO when the dst is a unicast address. + */ + int32_t seg_duration = seg_count * (duration + HCI_TIME_FOR_START_ADV); + time = (seg_duration + seg_rtx_to) * seg_rtx_num; + + BT_INFO("Original timeout %dms, calculated timeout %dms", timeout, time); + + if (time < timeout) { + /* If the calculated time is smaller than the input timeout value, + * then use the original timeout value. + */ + time = timeout; + } + } else { + /* For unsegmented access messages, directly use the timeout + * value from the application layer. + */ + time = timeout; + } + + BT_INFO("Client message 0x%08x with timeout %dms", opcode, time); + + return time; +} + +static void msg_send_start(uint16_t duration, int err, void *cb_data) +{ + bt_mesh_client_node_t *node = cb_data; + + BT_DBG("%s, duration %ums", __func__, duration); + + if (err) { + if (!k_delayed_work_free(&node->timer)) { + bt_mesh_client_free_node(node); + } + return; + } + + k_delayed_work_submit(&node->timer, node->timeout); +} + +static const struct bt_mesh_send_cb send_cb = { + .start = msg_send_start, + .end = NULL, +}; + +int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, + struct net_buf_simple *msg, bool need_ack, + k_work_handler_t timer_handler) +{ + bt_mesh_client_internal_data_t *internal = NULL; + bt_mesh_client_user_data_t *client = NULL; + bt_mesh_client_node_t *node = NULL; + int err = 0; + + if (!param || !param->model || !msg) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_client_user_data_t *)param->model->user_data; + if (!client) { + BT_ERR("Invalid client user data"); + return -EINVAL; + } + + internal = (bt_mesh_client_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("Invalid client internal data"); + return -EINVAL; + } + + if (param->ctx.addr == BLE_MESH_ADDR_UNASSIGNED) { + BT_ERR("Invalid DST 0x%04x", param->ctx.addr); + return -EINVAL; + } + + if (need_ack == false || !BLE_MESH_ADDR_IS_UNICAST(param->ctx.addr)) { + /* 1. If this is an unacknowledged message, send it directly. + * 2. If this is an acknowledged message, but the destination + * is not a unicast address, e.g. a group/virtual address, + * then all the corresponding responses will be treated as + * publish messages, and no timeout will be used. + */ + err = bt_mesh_model_send(param->model, ¶m->ctx, msg, param->cb, param->cb_data); + if (err) { + BT_ERR("Failed to send client message 0x%08x", param->opcode); + } + return err; + } + + if (!timer_handler) { + BT_ERR("Invalid timeout handler"); + return -EINVAL; + } + + if (bt_mesh_client_check_node_in_list(&internal->queue, param->ctx.addr)) { + BT_ERR("Busy sending message to DST 0x%04x", param->ctx.addr); + return -EBUSY; + } + + /* Don't forget to free the node in the timeout (timer_handler) function. */ + node = (bt_mesh_client_node_t *)bt_mesh_calloc(sizeof(bt_mesh_client_node_t)); + if (!node) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + memcpy(&node->ctx, ¶m->ctx, sizeof(struct bt_mesh_msg_ctx)); + node->model = param->model; + node->opcode = param->opcode; + node->op_pending = bt_mesh_client_get_status_op(client->op_pair, client->op_pair_size, param->opcode); + if (node->op_pending == 0U) { + BT_ERR("Status opcode not found in op_pair list, opcode 0x%08x", param->opcode); + bt_mesh_free(node); + return -EINVAL; + } + node->timeout = bt_mesh_client_calc_timeout(¶m->ctx, msg, param->opcode, + param->msg_timeout ? param->msg_timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT); + + if (k_delayed_work_init(&node->timer, timer_handler)) { + BT_ERR("Failed to create a timer"); + bt_mesh_free(node); + return -EIO; + } + + bt_mesh_list_lock(); + sys_slist_append(&internal->queue, &node->client_node); + bt_mesh_list_unlock(); + + /* "bt_mesh_model_send" will post the mesh packet to the mesh adv queue. + * Due to the higher priority of adv_thread (than btc task), we need to + * send the packet after the list item "node" is initialized properly. + */ + err = bt_mesh_model_send(param->model, ¶m->ctx, msg, &send_cb, node); + if (err) { + BT_ERR("Failed to send client message 0x%08x", node->opcode); + k_delayed_work_free(&node->timer); + bt_mesh_client_free_node(node); + } + + return err; +} + +static bt_mesh_mutex_t client_model_lock; + +void bt_mesh_client_model_lock(void) +{ + bt_mesh_mutex_lock(&client_model_lock); +} + +void bt_mesh_client_model_unlock(void) +{ + bt_mesh_mutex_unlock(&client_model_lock); +} + +int bt_mesh_client_init(struct bt_mesh_model *model) +{ + bt_mesh_client_internal_data_t *internal = NULL; + bt_mesh_client_user_data_t *client = NULL; + + if (!model || !model->op) { + BT_ERR("Invalid vendor client model"); + return -EINVAL; + } + + client = (bt_mesh_client_user_data_t *)model->user_data; + if (!client) { + BT_ERR("No vendor client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(bt_mesh_client_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->internal_data = internal; + + bt_mesh_mutex_create(&client_model_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +int bt_mesh_client_deinit(struct bt_mesh_model *model) +{ + bt_mesh_client_user_data_t *client = NULL; + + if (!model) { + BT_ERR("Invalid vendor client model"); + return -EINVAL; + } + + client = (bt_mesh_client_user_data_t *)model->user_data; + if (!client) { + BT_ERR("No vendor client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&client_model_lock); + + return 0; +} +#endif /* CONFIG_BLE_MESH_DEINIT */ + +int bt_mesh_client_free_node(bt_mesh_client_node_t *node) +{ + bt_mesh_client_internal_data_t *internal = NULL; + bt_mesh_client_user_data_t *client = NULL; + + if (!node || !node->model) { + BT_ERR("Invalid client list item"); + return -EINVAL; + } + + client = (bt_mesh_client_user_data_t *)node->model->user_data; + if (!client) { + BT_ERR("Invalid client user data"); + return -EINVAL; + } + + internal = (bt_mesh_client_internal_data_t *)client->internal_data; + if (!internal) { + BT_ERR("Invalid client internal data"); + return -EINVAL; + } + + // Release the client node from the queue + bt_mesh_list_lock(); + sys_slist_find_and_remove(&internal->queue, &node->client_node); + bt_mesh_list_unlock(); + + // Free the node + bt_mesh_free(node); + + return 0; +} + +int bt_mesh_client_clear_list(void *data) +{ + bt_mesh_client_internal_data_t *internal = NULL; + bt_mesh_client_node_t *node = NULL; + + if (!data) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + internal = (bt_mesh_client_internal_data_t *)data; + + bt_mesh_list_lock(); + while (!sys_slist_is_empty(&internal->queue)) { + node = (void *)sys_slist_get_not_empty(&internal->queue); + k_delayed_work_free(&node->timer); + bt_mesh_free(node); + } + bt_mesh_list_unlock(); + + return 0; +} diff --git a/lib/bt/esp_ble_mesh/models/client/generic_client.c b/lib/bt/esp_ble_mesh/models/client/generic_client.c new file mode 100644 index 00000000..af09dc1b --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/generic_client.c @@ -0,0 +1,1185 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> +#include <errno.h> + +#include "btc_ble_mesh_generic_model.h" + +#include "mesh/config.h" +#include "mesh/model_opcode.h" + +#if CONFIG_BLE_MESH_GENERIC_CLIENT +#include "mesh/generic_client.h" + +/* The followings are the macro definitions of Generic client + * model message length, and a message is composed of 3 parts: + * Opcode + Payload + MIC + */ +/* Generic onoff client messages length */ +#define BLE_MESH_GEN_ONOFF_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_ONOFF_SET_MSG_LEN (2 + 4 + 4) + +/* Generic level client messages length */ +#define BLE_MESH_GEN_LEVEL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_LEVEL_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_GEN_DELTA_SET_MSG_LEN (2 + 7 + 4) +#define BLE_MESH_GEN_MOVE_SET_MSG_LEN (2 + 5 + 4) + +/* Generic default transition time client messages length */ +#define BLE_MESH_GEN_DEF_TRANS_TIME_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_DEF_TRANS_TIME_SET_MSG_LEN (2 + 1 + 4) + +/* Generic power onoff client messages length */ +#define BLE_MESH_GEN_ONPOWERUP_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_ONPOWERUP_SET_MSG_LEN (2 + 1 + 4) + +/* Generic power level client messages length */ +#define BLE_MESH_GEN_POWER_LEVEL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_LEVEL_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_GEN_POWER_LAST_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_DEFAULT_SET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_POWER_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_POWER_RANGE_SET_MSG_LEN (2 + 4 + 4) + +/* Generic battery client messages length */ +#define BLE_MESH_GEN_BATTERY_GET_MSG_LEN (2 + 0 + 4) + +/* Generic location client messages length */ +#define BLE_MESH_GEN_LOC_GLOBAL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_LOC_GLOBAL_SET_MSG_LEN (1 + 10 + 4) +#define BLE_MESH_GEN_LOC_LOCAL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_LOC_LOCAL_SET_MSG_LEN (2 + 9 + 4) + +/* Generic property client messages length */ +#define BLE_MESH_GEN_USER_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_USER_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_USER_PROPERTY_SET_MSG_LEN /* variable */ +#define BLE_MESH_GEN_ADMIN_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_ADMIN_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_ADMIN_PROPERTY_SET_MSG_LEN /* variable */ +#define BLE_MESH_GEN_MANU_PROPERTIES_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_GEN_MANU_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_GEN_MANU_PROPERTY_SET_MSG_LEN (1 + 3 + 4) +#define BLE_MESH_GEN_CLIENT_PROPERTIES_GET_MSG_LEN (1 + 2 + 4) + +#define BLE_MESH_GEN_GET_STATE_MSG_LEN (2 + 2 + 4) + +static const bt_mesh_client_op_pair_t gen_op_pair[] = { + { BLE_MESH_MODEL_OP_GEN_ONOFF_GET, BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ONOFF_SET, BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LEVEL_GET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LEVEL_SET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_DELTA_SET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MOVE_SET, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET, BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS }, + { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET, BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET, BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET, BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET, BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_GEN_BATTERY_GET, BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET, BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET, BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET, BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET, BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET, BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET, BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET, BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS }, +}; + +static bt_mesh_mutex_t generic_client_lock; + +static void timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + uint32_t opcode = 0U; + + BT_WARN("Receive generic status message timeout"); + + bt_mesh_mutex_lock(&generic_client_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (node) { + memcpy(&ctx, &node->ctx, sizeof(ctx)); + opcode = node->opcode; + model = node->model; + bt_mesh_client_free_node(node); + bt_mesh_generic_client_cb_evt_to_btc( + opcode, BTC_BLE_MESH_EVT_GENERIC_CLIENT_TIMEOUT, model, &ctx, NULL, 0); + } + } + + bt_mesh_mutex_unlock(&generic_client_lock); +} + +static void generic_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + bt_mesh_client_node_t *node = NULL; + uint8_t *val = NULL; + uint8_t evt = 0xFF; + size_t len = 0U; + + BT_DBG("len %d, bytes %s", buf->len, bt_hex(buf->data, buf->len)); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS: { + struct bt_mesh_gen_onoff_status *status = NULL; + if (buf->len != 1 && buf->len != 3) { + BT_ERR("Invalid Generic OnOff Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_onoff_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_onoff = net_buf_simple_pull_u8(buf); + if (buf->len) { + status->op_en = true; + status->target_onoff = net_buf_simple_pull_u8(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_onoff_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS: { + struct bt_mesh_gen_level_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Generic Level Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_level_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_level = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_level = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_level_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS: { + struct bt_mesh_gen_def_trans_time_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Generic Default Trans Time Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_def_trans_time_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->trans_time = net_buf_simple_pull_u8(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_def_trans_time_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS: { + struct bt_mesh_gen_onpowerup_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Generic OnPowerUp Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_onpowerup_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->onpowerup = net_buf_simple_pull_u8(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_onpowerup_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS: { + struct bt_mesh_gen_power_level_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Generic Power Level Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_power_level_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_power = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_power = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_power_level_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS: { + struct bt_mesh_gen_power_last_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Generic Power Last Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_power_last_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->power = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_power_last_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS: { + struct bt_mesh_gen_power_default_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Generic Power Default Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_power_default_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->power = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_power_default_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS: { + struct bt_mesh_gen_power_range_status *status = NULL; + if (buf->len != 5) { + BT_ERR("Invalid Generic Power Range Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_power_range_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->range_min = net_buf_simple_pull_le16(buf); + status->range_max = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_power_range_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS: { + struct bt_mesh_gen_battery_status *status = NULL; + if (buf->len != 8) { + BT_ERR("Invalid Generic Battery Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_battery_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + uint32_t value = 0; + value = net_buf_simple_pull_le32(buf); + status->battery_level = (uint8_t)value; + status->time_to_discharge = (value >> 8); + value = net_buf_simple_pull_le32(buf); + status->time_to_charge = (value & 0xffffff); + status->flags = (uint8_t)(value >> 24); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_battery_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS: { + struct bt_mesh_gen_loc_global_status *status = NULL; + if (buf->len != 10) { + BT_ERR("Invalid Generic Location Global Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_loc_global_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->global_latitude = net_buf_simple_pull_le32(buf); + status->global_longitude = net_buf_simple_pull_le32(buf); + status->global_altitude = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_loc_global_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS: { + struct bt_mesh_gen_loc_local_status *status = NULL; + if (buf->len != 9) { + BT_ERR("Invalid Generic Location Local Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_loc_local_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->local_north = net_buf_simple_pull_le16(buf); + status->local_east = net_buf_simple_pull_le16(buf); + status->local_altitude = net_buf_simple_pull_le16(buf); + status->floor_number = net_buf_simple_pull_u8(buf); + status->uncertainty = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_loc_local_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: { + struct bt_mesh_gen_user_properties_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_user_properties_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->user_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->user_property_ids) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->user_property_ids, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_user_properties_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS: { + struct bt_mesh_gen_user_property_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_user_property_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->user_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->user_access = net_buf_simple_pull_u8(buf); + status->user_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->user_property_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->user_property_value, buf->data, buf->len); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_user_property_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS: { + struct bt_mesh_gen_admin_properties_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_admin_properties_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->admin_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->admin_property_ids) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->admin_property_ids, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_admin_properties_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS: { + struct bt_mesh_gen_admin_property_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_admin_property_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->admin_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->admin_user_access = net_buf_simple_pull_u8(buf); + status->admin_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->admin_property_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->admin_property_value, buf->data, buf->len); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_admin_property_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS: { + struct bt_mesh_gen_manu_properties_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_manu_properties_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->manu_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->manu_property_ids) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->manu_property_ids, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_manu_properties_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS: { + struct bt_mesh_gen_manu_property_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_manu_property_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->manu_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->manu_user_access = net_buf_simple_pull_u8(buf); + status->manu_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->manu_property_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->manu_property_value, buf->data, buf->len); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_manu_property_status); + break; + } + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS: { + struct bt_mesh_gen_client_properties_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_gen_client_properties_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->client_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->client_property_ids) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->client_property_ids, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_gen_client_properties_status); + break; + } + default: + BT_ERR("Invalid Generic Status opcode 0x%04x", ctx->recv_op); + return; + } + + buf->data = val; + buf->len = len; + + bt_mesh_mutex_lock(&generic_client_lock); + + node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected Generic Status 0x%04x", ctx->recv_op); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET: + case BLE_MESH_MODEL_OP_GEN_BATTERY_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: + evt = BTC_BLE_MESH_EVT_GENERIC_CLIENT_GET_STATE; + break; + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_DELTA_SET: + case BLE_MESH_MODEL_OP_GEN_MOVE_SET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET: + evt = BTC_BLE_MESH_EVT_GENERIC_CLIENT_SET_STATE; + break; + default: + break; + } + + if (!k_delayed_work_free(&node->timer)) { + uint32_t opcode = node->opcode; + bt_mesh_client_free_node(node); + bt_mesh_generic_client_cb_evt_to_btc(opcode, evt, model, ctx, val, len); + } + } + + bt_mesh_mutex_unlock(&generic_client_lock); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS: { + struct bt_mesh_gen_user_properties_status *status; + status = (struct bt_mesh_gen_user_properties_status *)val; + bt_mesh_free_buf(status->user_property_ids); + break; + } + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS: { + struct bt_mesh_gen_user_property_status *status; + status = (struct bt_mesh_gen_user_property_status *)val; + bt_mesh_free_buf(status->user_property_value); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS: { + struct bt_mesh_gen_admin_properties_status *status; + status = (struct bt_mesh_gen_admin_properties_status *)val; + bt_mesh_free_buf(status->admin_property_ids); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS: { + struct bt_mesh_gen_admin_property_status *status; + status = (struct bt_mesh_gen_admin_property_status *)val; + bt_mesh_free_buf(status->admin_property_value); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS: { + struct bt_mesh_gen_manu_properties_status *status; + status = (struct bt_mesh_gen_manu_properties_status *)val; + bt_mesh_free_buf(status->manu_property_ids); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS: { + struct bt_mesh_gen_manu_property_status *status; + status = (struct bt_mesh_gen_manu_property_status *)val; + bt_mesh_free_buf(status->manu_property_value); + break; + } + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS: { + struct bt_mesh_gen_client_properties_status *status; + status = (struct bt_mesh_gen_client_properties_status *)val; + bt_mesh_free_buf(status->client_property_ids); + break; + } + default: + break; + } + + bt_mesh_free(val); +} + +const struct bt_mesh_model_op bt_mesh_gen_onoff_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_level_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS, 2, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_def_trans_time_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS, 1, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_power_onoff_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS, 1, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_power_level_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS, 5, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_battery_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS, 8, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_location_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS, 10, generic_status }, + { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS, 9, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_gen_property_cli_op[] = { + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS, 2, generic_status }, + { BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS, 2, generic_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int gen_get_state(bt_mesh_client_common_param_t *common, void *value) +{ + NET_BUF_SIMPLE_DEFINE(msg, BLE_MESH_GEN_GET_STATE_MSG_LEN); + + bt_mesh_model_msg_init(&msg, common->opcode); + + if (value) { + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: { + struct bt_mesh_gen_user_property_get *get; + get = (struct bt_mesh_gen_user_property_get *)value; + net_buf_simple_add_le16(&msg, get->user_property_id); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: { + struct bt_mesh_gen_admin_property_get *get; + get = (struct bt_mesh_gen_admin_property_get *)value; + net_buf_simple_add_le16(&msg, get->admin_property_id); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: { + struct bt_mesh_gen_manu_property_get *get; + get = (struct bt_mesh_gen_manu_property_get *)value; + net_buf_simple_add_le16(&msg, get->manu_property_id); + break; + } + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: { + struct bt_mesh_gen_client_properties_get *get; + get = (struct bt_mesh_gen_client_properties_get *)value; + net_buf_simple_add_le16(&msg, get->client_property_id); + break; + } + default: + BT_DBG("No parameters for Generic Get 0x%04x", common->opcode); + break; + } + } + + return bt_mesh_client_send_msg(common, &msg, true, timeout_handler); +} + +static int gen_set_state(bt_mesh_client_common_param_t *common, + void *value, uint16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err = 0; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: { + struct bt_mesh_gen_onoff_set *set; + set = (struct bt_mesh_gen_onoff_set *)value; + net_buf_simple_add_u8(msg, set->onoff); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK: { + struct bt_mesh_gen_level_set *set; + set = (struct bt_mesh_gen_level_set *)value; + net_buf_simple_add_le16(msg, set->level); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_DELTA_SET: + case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK: { + struct bt_mesh_gen_delta_set *set; + set = (struct bt_mesh_gen_delta_set *)value; + net_buf_simple_add_le32(msg, set->delta_level); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_MOVE_SET: + case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK: { + struct bt_mesh_gen_move_set *set; + set = (struct bt_mesh_gen_move_set *)value; + net_buf_simple_add_le16(msg, set->delta_level); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK: { + struct bt_mesh_gen_def_trans_time_set *set; + set = (struct bt_mesh_gen_def_trans_time_set *)value; + net_buf_simple_add_u8(msg, set->trans_time); + break; + } + + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK: { + struct bt_mesh_gen_onpowerup_set *set; + set = (struct bt_mesh_gen_onpowerup_set *)value; + net_buf_simple_add_u8(msg, set->onpowerup); + break; + } + + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK: { + struct bt_mesh_gen_power_level_set *set; + set = (struct bt_mesh_gen_power_level_set *)value; + net_buf_simple_add_le16(msg, set->power); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK: { + struct bt_mesh_gen_power_default_set *set; + set = (struct bt_mesh_gen_power_default_set *)value; + net_buf_simple_add_le16(msg, set->power); + break; + } + + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK: { + struct bt_mesh_gen_power_range_set *set; + set = (struct bt_mesh_gen_power_range_set *)value; + net_buf_simple_add_le16(msg, set->range_min); + net_buf_simple_add_le16(msg, set->range_max); + break; + } + + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK: { + struct bt_mesh_gen_loc_global_set *set; + set = (struct bt_mesh_gen_loc_global_set *)value; + net_buf_simple_add_le32(msg, set->global_latitude); + net_buf_simple_add_le32(msg, set->global_longitude); + net_buf_simple_add_le16(msg, set->global_altitude); + break; + } + + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK: { + struct bt_mesh_gen_loc_local_set *set; + set = (struct bt_mesh_gen_loc_local_set *)value; + net_buf_simple_add_le16(msg, set->local_north); + net_buf_simple_add_le16(msg, set->local_east); + net_buf_simple_add_le16(msg, set->local_altitude); + net_buf_simple_add_u8(msg, set->floor_number); + net_buf_simple_add_le16(msg, set->uncertainty); + break; + } + + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_user_property_set *set; + set = (struct bt_mesh_gen_user_property_set *)value; + net_buf_simple_add_le16(msg, set->user_property_id); + net_buf_simple_add_mem(msg, set->user_property_value->data, set->user_property_value->len); + break; + } + + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_admin_property_set *set; + set = (struct bt_mesh_gen_admin_property_set *)value; + net_buf_simple_add_le16(msg, set->admin_property_id); + net_buf_simple_add_u8(msg, set->admin_user_access); + net_buf_simple_add_mem(msg, set->admin_property_value->data, set->admin_property_value->len); + break; + } + + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_manu_property_set *set; + set = (struct bt_mesh_gen_manu_property_set *)value; + net_buf_simple_add_le16(msg, set->manu_property_id); + net_buf_simple_add_u8(msg, set->manu_user_access); + break; + } + + default: + BT_ERR("Invalid Generic Set opcode 0x%04x", common->opcode); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common, msg, need_ack, timeout_handler); + +end: + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_generic_client_get_state(bt_mesh_client_common_param_t *common, void *get) +{ + bt_mesh_generic_client_t *client = NULL; + + if (!common || !common->model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Generic client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + case BLE_MESH_MODEL_OP_GEN_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET: + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET: + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET: + case BLE_MESH_MODEL_OP_GEN_BATTERY_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET: + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET: + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET: + break; + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: + if (!get) { + BT_ERR("Invalid Generic User Property Get"); + return -EINVAL; + } + break; + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: + if (!get) { + BT_ERR("Invalid Generic Admin Property Get"); + return -EINVAL; + } + break; + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: + if (!get) { + BT_ERR("Invalid Generic Manu Property Get"); + return -EINVAL; + } + break; + case BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET: + if (!get) { + BT_ERR("Invalid Generic Client Properties Get"); + return -EINVAL; + } + break; + default: + BT_ERR("Invalid Generic Get opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return gen_get_state(common, get); +} + +int bt_mesh_generic_client_set_state(bt_mesh_client_common_param_t *common, void *set) +{ + bt_mesh_generic_client_t *client = NULL; + uint16_t length = 0U; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Generic client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: { + struct bt_mesh_gen_onoff_set *value; + value = (struct bt_mesh_gen_onoff_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Generic OnOff Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_GEN_ONOFF_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK: { + struct bt_mesh_gen_level_set *value; + value = (struct bt_mesh_gen_level_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Generic Level Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_GEN_LEVEL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_DELTA_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK: { + struct bt_mesh_gen_delta_set *value; + value = (struct bt_mesh_gen_delta_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Generic Delta Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_GEN_DELTA_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_MOVE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK: { + struct bt_mesh_gen_move_set *value; + value = (struct bt_mesh_gen_move_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Generic Move Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_GEN_MOVE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK: { + uint8_t value = *(uint8_t *)set; + if ((value & 0x3F) > 0x3E) { + BT_ERR("Invalid Generic Default Trans Time Set transition time"); + return -EINVAL; + } + length = BLE_MESH_GEN_DEF_TRANS_TIME_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK: + length = BLE_MESH_GEN_ONPOWERUP_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK: { + struct bt_mesh_gen_power_level_set *value; + value = (struct bt_mesh_gen_power_level_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Generic Power Level Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_GEN_POWER_LEVEL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK: + length = BLE_MESH_GEN_POWER_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK: { + struct bt_mesh_gen_power_range_set *value; + value = (struct bt_mesh_gen_power_range_set *)set; + if (value->range_min > value->range_max) { + BT_ERR("Generic Power Level Set range min is greater than range max"); + return -EINVAL; + } + length = BLE_MESH_GEN_POWER_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK: + length = BLE_MESH_GEN_LOC_GLOBAL_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK: + length = BLE_MESH_GEN_LOC_LOCAL_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_user_property_set *value; + value = (struct bt_mesh_gen_user_property_set *)set; + if (!value->user_property_value) { + BT_ERR("Invalid Generic User Property value"); + return -EINVAL; + } + length = (1 + 2 + value->user_property_value->len + 4); + break; + } + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK: { + struct bt_mesh_gen_admin_property_set *value; + value = (struct bt_mesh_gen_admin_property_set *)set; + if (!value->admin_property_value) { + BT_ERR("Invalid Generic Admin Property value"); + return -EINVAL; + } + length = (1 + 2 + 1 + value->admin_property_value->len + 4); + break; + } + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK: + length = BLE_MESH_GEN_MANU_PROPERTY_SET_MSG_LEN; + break; + default: + BT_ERR("Invalid Generic Set opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return gen_set_state(common, set, length, need_ack); +} + +static int generic_client_init(struct bt_mesh_model *model) +{ + generic_internal_data_t *internal = NULL; + bt_mesh_generic_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Generic client model"); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)model->user_data; + if (!client) { + BT_ERR("No Generic client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(generic_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(gen_op_pair); + client->op_pair = gen_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&generic_client_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +static int generic_client_deinit(struct bt_mesh_model *model) +{ + bt_mesh_generic_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Generic client model"); + return -EINVAL; + } + + client = (bt_mesh_generic_client_t *)model->user_data; + if (!client) { + BT_ERR("No Generic client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&generic_client_lock); + + return 0; +} +#endif /* CONFIG_BLE_MESH_DEINIT */ + +const struct bt_mesh_model_cb bt_mesh_generic_client_cb = { + .init = generic_client_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = generic_client_deinit, +#endif /* CONFIG_BLE_MESH_DEINIT */ +}; + +#endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */ diff --git a/lib/bt/esp_ble_mesh/models/client/include/mesh/client_common.h b/lib/bt/esp_ble_mesh/models/client/include/mesh/client_common.h new file mode 100644 index 00000000..25834a1d --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/include/mesh/client_common.h @@ -0,0 +1,119 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _CLIENT_COMMON_H_ +#define _CLIENT_COMMON_H_ + +#include "mesh/access.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Client model opcode pair table */ +typedef struct { + uint32_t cli_op; /* Client message opcode */ + uint32_t status_op; /* Corresponding status message opcode */ +} bt_mesh_client_op_pair_t; + +/** Client model user data context */ +typedef struct { + /** Pointer to the client model */ + struct bt_mesh_model *model; + + /** Size of the opcode pair table */ + uint32_t op_pair_size; + + /** Pointer to the opcode pair table */ + const bt_mesh_client_op_pair_t *op_pair; + + /** + * @brief This function is a callback function used to push the received unsolicited + * messages to the application layer. + * + * @param[in] opcode: Opcode of received status message + * @param[in] model: Model associated with the status message + * @param[in] ctx: Context information of the status message + * @param[in] buf: Buffer contains the status message value + * + * @return None + */ + void (*publish_status)(uint32_t opcode, struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf); + + /** Pointer to the internal data of client model */ + void *internal_data; + + /** Pointer to the vendor data of client model */ + void *vendor_data; + + /** Role of the device to which the client model belongs */ + uint8_t msg_role __attribute__((deprecated)); +} bt_mesh_client_user_data_t; + +/** Client model internal data context */ +typedef struct { + sys_slist_t queue; +} bt_mesh_client_internal_data_t; + +/** Client model sending message related context */ +typedef struct { + sys_snode_t client_node; + struct bt_mesh_model *model; /* Pointer to the client model */ + struct bt_mesh_msg_ctx ctx; /* Message context */ + uint32_t opcode; /* Message opcode */ + uint32_t op_pending; /* Expected status message opcode */ + int32_t timeout; /* Calculated message timeout value */ + struct k_delayed_work timer; /* Time used to get response. Only for internal use. */ +} bt_mesh_client_node_t; + +/** Client model sending message parameters */ +typedef struct { + uint32_t opcode; /* Message opcode */ + struct bt_mesh_model *model; /* Pointer to the client model */ + struct bt_mesh_msg_ctx ctx; /* Message context */ + int32_t msg_timeout; /* Time to get corresponding response */ + uint8_t msg_role __attribute__((deprecated)); /* Role (Node/Provisioner) of the device */ + const struct bt_mesh_send_cb *cb; /* User defined callback function */ + void *cb_data; /* User defined callback value */ +} bt_mesh_client_common_param_t; + +void bt_mesh_client_model_lock(void); + +void bt_mesh_client_model_unlock(void); + +int bt_mesh_client_init(struct bt_mesh_model *model); + +int bt_mesh_client_deinit(struct bt_mesh_model *model); + +/** + * @brief Check if the msg received by client model is a publish msg or not + * + * @param model Mesh (client) Model that the message belongs to. + * @param ctx Message context, includes keys, TTL, etc. + * @param buf The message buffer + * @param need_pub Indicate if the msg sent to app layer as a publish msg + * @return 0 on success, or (negative) error code on failure. + */ +bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, + bool need_pub); + +int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, + struct net_buf_simple *msg, bool need_ack, + k_work_handler_t timer_handler); + +int bt_mesh_client_free_node(bt_mesh_client_node_t *node); + +int bt_mesh_client_clear_list(void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* _CLIENT_COMMON_H_ */ diff --git a/lib/bt/esp_ble_mesh/models/client/include/mesh/generic_client.h b/lib/bt/esp_ble_mesh/models/client/include/mesh/generic_client.h new file mode 100644 index 00000000..b484ef43 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/include/mesh/generic_client.h @@ -0,0 +1,408 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Bluetooth Mesh Generic Client Model APIs. + */ + +#ifndef _GENERIC_CLIENT_H_ +#define _GENERIC_CLIENT_H_ + +#include "mesh/client_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Generic client model common structure */ +typedef bt_mesh_client_user_data_t bt_mesh_generic_client_t; +typedef bt_mesh_client_internal_data_t generic_internal_data_t; + +/* Generic Client Model Callback */ +extern const struct bt_mesh_model_cb bt_mesh_generic_client_cb; + +/* Generic OnOff Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_onoff_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_ONOFF_CLI + * + * Define a new generic onoff client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic onoff client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_onoff_cli. + * + * @return New generic onoff client model instance. + */ +#define BLE_MESH_MODEL_GEN_ONOFF_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, \ + bt_mesh_gen_onoff_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_onoff_client_t; + +struct bt_mesh_gen_onoff_status { + bool op_en; /* Indicate whether optional parameters included */ + uint8_t present_onoff; /* Present value of Generic OnOff state */ + uint8_t target_onoff; /* Target value of Generic OnOff state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_gen_onoff_set { + bool op_en; /* Indicate whether optional parameters included */ + uint8_t onoff; /* Target value of Generic OnOff state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +/* Generic Level Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_level_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_LEVEL_CLI + * + * Define a new generic level client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic level client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_level_cli. + * + * @return New generic level client model instance. + */ +#define BLE_MESH_MODEL_GEN_LEVEL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_LEVEL_CLI, \ + bt_mesh_gen_level_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_level_client_t; + +struct bt_mesh_gen_level_status { + bool op_en; /* Indicate whether optional parameters included */ + int16_t present_level; /* Present value of Generic Level state */ + int16_t target_level; /* Target value of the Generic Level state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_gen_level_set { + bool op_en; /* Indicate whether optional parameters included */ + int16_t level; /* Target value of Generic Level state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_gen_delta_set { + bool op_en; /* Indicate whether optional parameters included */ + int32_t delta_level; /* Delta change of Generic Level state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_gen_move_set { + bool op_en; /* Indicate whether optional parameters included */ + int16_t delta_level; /* Delta Level step to calculate Move speed for Generic Level state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +/* Generic Default Transition Time Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_def_trans_time_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI + * + * Define a new generic default transition time client model. Note + * that this API needs to be repeated for each element that the + * application wants to have a generic default transition client + * model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_def_trans_time_cli. + * + * @return New generic default transition time client model instance. + */ +#define BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI, \ + bt_mesh_gen_def_trans_time_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_def_trans_time_client_t; + +struct bt_mesh_gen_def_trans_time_set { + uint8_t trans_time; /* The value of the Generic Default Transition Time state */ +}; + +struct bt_mesh_gen_def_trans_time_status { + uint8_t trans_time; /* The value of the Generic Default Transition Time state */ +}; + +/* Generic Power OnOff Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_power_onoff_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI + * + * Define a new generic power onoff client model. Note that this API + * needs to be repeated for each element which the application wants + * to have a generic power onoff client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_power_onoff_cli. + * + * @return New generic power onoff client model instance. + */ +#define BLE_MESH_MODEL_GEN_POWER_ONOFF_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI, \ + bt_mesh_gen_power_onoff_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_power_onoff_client_t; + +struct bt_mesh_gen_onpowerup_set { + uint8_t onpowerup; /* The value of the Generic OnPowerUp state */ +}; + +struct bt_mesh_gen_onpowerup_status { + uint8_t onpowerup; /* The value of the Generic OnPowerUp state */ +}; + +/* Generic Power Level Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_power_level_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI + * + * Define a new generic power level client model. Note that this API + * needs to be repeated for each element which the application wants + * to have a generic power level client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_power_level_cli. + * + * @return New generic power level client model instance. + */ +#define BLE_MESH_MODEL_GEN_POWER_LEVEL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI, \ + bt_mesh_gen_power_level_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_power_level_client_t; + +struct bt_mesh_gen_power_level_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_power; /* Present value of Generic Power Actual state */ + uint16_t target_power; /* Target value of Generic Power Actual state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_gen_power_last_status { + uint16_t power; /* The value of the Generic Power Last state */ +}; + +struct bt_mesh_gen_power_default_status { + uint16_t power; /* The value of the Generic Default Last state */ +}; + +struct bt_mesh_gen_power_range_status { + uint8_t status_code; /* Status Code for the requesting message */ + uint16_t range_min; /* Value of Range Min field of Generic Power Range state */ + uint16_t range_max; /* Value of Range Max field of Generic Power Range state */ +}; + +struct bt_mesh_gen_power_level_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t power; /* Target value of Generic Power Actual state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_gen_power_default_set { + uint16_t power; /* The value of the Generic Power Default state */ +}; + +struct bt_mesh_gen_power_range_set { + uint16_t range_min; /* Value of Range Min field of Generic Power Range state */ + uint16_t range_max; /* Value of Range Max field of Generic Power Range state */ +}; + +/* Generic Battery Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_battery_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_BATTERY_CLI + * + * Define a new generic battery client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic battery client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_battery_cli. + * + * @return New generic battery client model instance. + */ +#define BLE_MESH_MODEL_GEN_BATTERY_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_BATTERY_CLI, \ + bt_mesh_gen_battery_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_battery_client_t; + +struct bt_mesh_gen_battery_status { + uint32_t battery_level : 8; /* Value of Generic Battery Level state */ + uint32_t time_to_discharge : 24; /* Value of Generic Battery Time to Discharge state */ + uint32_t time_to_charge : 24; /* Value of Generic Battery Time to Charge state */ + uint32_t flags : 8; /* Value of Generic Battery Flags state */ +}; + +/* Generic Location Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_location_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_LOCATION_CLI + * + * Define a new generic location client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic location client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_location_cli. + * + * @return New generic location client model instance. + */ +#define BLE_MESH_MODEL_GEN_LOCATION_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_LOCATION_CLI, \ + bt_mesh_gen_location_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_location_client_t; + +struct bt_mesh_gen_loc_global_status { + int32_t global_latitude; /* Global Coordinates (Latitude) */ + int32_t global_longitude; /* Global Coordinates (Longitude) */ + int16_t global_altitude; /* Global Altitude */ +}; + +struct bt_mesh_gen_loc_local_status { + int16_t local_north; /* Local Coordinates (North) */ + int16_t local_east; /* Local Coordinates (East) */ + int16_t local_altitude; /* Local Altitude */ + uint8_t floor_number; /* Floor Number */ + uint16_t uncertainty; /* Uncertainty */ +}; + +struct bt_mesh_gen_loc_global_set { + int32_t global_latitude; /* Global Coordinates (Latitude) */ + int32_t global_longitude; /* Global Coordinates (Longitude) */ + int16_t global_altitude; /* Global Altitude */ +}; + +struct bt_mesh_gen_loc_local_set { + int16_t local_north; /* Local Coordinates (North) */ + int16_t local_east; /* Local Coordinates (East) */ + int16_t local_altitude; /* Local Altitude */ + uint8_t floor_number; /* Floor Number */ + uint16_t uncertainty; /* Uncertainty */ +}; + +/* Generic Property Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_gen_property_cli_op[]; + +/** @def BLE_MESH_MODEL_GEN_LOCATION_CLI + * + * Define a new generic location client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a generic location client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_gen_location_cli. + * + * @return New generic location client model instance. + */ +#define BLE_MESH_MODEL_GEN_PROPERTY_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_GEN_PROP_CLI, \ + bt_mesh_gen_property_cli_op, cli_pub, cli_data, &bt_mesh_generic_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_gen_property_client_t; + +struct bt_mesh_gen_user_properties_status { + struct net_buf_simple *user_property_ids; /* Buffer contains a sequence of N User Property IDs */ +}; + +struct bt_mesh_gen_user_property_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t user_property_id; /* Property ID identifying a Generic User Property */ + uint8_t user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *user_property_value; /* Raw value for the User Property (C.1) */ +}; + +struct bt_mesh_gen_admin_properties_status { + struct net_buf_simple *admin_property_ids; /* Buffer contains a sequence of N Admin Property IDs */ +}; + +struct bt_mesh_gen_admin_property_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t admin_property_id; /* Property ID identifying a Generic Admin Property */ + uint8_t admin_user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *admin_property_value; /* Raw value for the Admin Property (C.1) */ +}; + +struct bt_mesh_gen_manu_properties_status { + struct net_buf_simple *manu_property_ids; /* Buffer contains a sequence of N Manufacturer Property IDs */ +}; + +struct bt_mesh_gen_manu_property_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t manu_property_id; /* Property ID identifying a Generic Manufacturer Property */ + uint8_t manu_user_access; /* Enumeration indicating user access (optional) */ + struct net_buf_simple *manu_property_value; /* Raw value for the Manufacturer Property (C.1) */ +}; + +struct bt_mesh_gen_client_properties_status { + struct net_buf_simple *client_property_ids; /* Buffer contains a sequence of N Client Property IDs */ +}; + +struct bt_mesh_gen_user_property_get { + uint16_t user_property_id; /* Property ID identifying a Generic User Property */ +}; + +struct bt_mesh_gen_user_property_set { + uint16_t user_property_id; /* Property ID identifying a Generic User Property */ + struct net_buf_simple *user_property_value; /* Raw value for the User Property */ +}; + +struct bt_mesh_gen_admin_property_get { + uint16_t admin_property_id; /* Property ID identifying a Generic Admin Property */ +}; + +struct bt_mesh_gen_admin_property_set { + uint16_t admin_property_id; /* Property ID identifying a Generic Admin Property */ + uint8_t admin_user_access; /* Enumeration indicating user access */ + struct net_buf_simple *admin_property_value; /* Raw value for the Admin Property */ +}; + +struct bt_mesh_gen_manu_property_get { + uint16_t manu_property_id; /* Property ID identifying a Generic Manufacturer Property */ +}; + +struct bt_mesh_gen_manu_property_set { + uint16_t manu_property_id; /* Property ID identifying a Generic Manufacturer Property */ + uint8_t manu_user_access; /* Enumeration indicating user access */ +}; + +struct bt_mesh_gen_client_properties_get { + uint16_t client_property_id; /* A starting Client Property ID present within an element */ +}; + +/** + * @brief This function is called to get generic states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of generic get message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_generic_client_get_state(bt_mesh_client_common_param_t *common, void *get); + +/** + * @brief This function is called to set generic states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of generic set message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_generic_client_set_state(bt_mesh_client_common_param_t *common, void *set); + +#ifdef __cplusplus +} +#endif + +#endif /* _GENERIC_CLIENT_H_ */ diff --git a/lib/bt/esp_ble_mesh/models/client/include/mesh/lighting_client.h b/lib/bt/esp_ble_mesh/models/client/include/mesh/lighting_client.h new file mode 100644 index 00000000..c86cbfa9 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/include/mesh/lighting_client.h @@ -0,0 +1,440 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Bluetooth Mesh Lighting Client Model APIs. + */ + +#ifndef _LIGHTING_CLIENT_H_ +#define _LIGHTING_CLIENT_H_ + +#include "mesh/client_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Light client model common structure */ +typedef bt_mesh_client_user_data_t bt_mesh_light_client_t; +typedef bt_mesh_client_internal_data_t light_internal_data_t; + +/* Lighting Client Model Callback */ +extern const struct bt_mesh_model_cb bt_mesh_lighting_client_cb; + +/* Light Lightness Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_light_lightness_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI + * + * Define a new light lightness client model. Note that this API + * needs to be repeated for each element which the application + * wants to have a light lightness client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_lightness_cli. + * + * @return New light lightness client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_LIGHTNESS_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI, \ + bt_mesh_light_lightness_cli_op, cli_pub, cli_data, &bt_mesh_lighting_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_light_lightness_client_t; + +struct bt_mesh_light_lightness_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_lightness; /* Present value of light lightness actual state */ + uint16_t target_lightness; /* Target value of light lightness actual state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_lightness_linear_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_lightness; /* Present value of light lightness linear state */ + uint16_t target_lightness; /* Target value of light lightness linear state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_lightness_last_status { + uint16_t lightness; /* The value of the Light Lightness Last state */ +}; + +struct bt_mesh_light_lightness_default_status { + uint16_t lightness; /* The value of the Light Lightness default state */ +}; + +struct bt_mesh_light_lightness_range_status { + uint8_t status_code; /* Status Code for the requesting message */ + uint16_t range_min; /* Value of range min field of light lightness range state */ + uint16_t range_max; /* Value of range max field of light lightness range state */ +}; + +struct bt_mesh_light_lightness_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t lightness; /* Target value of light lightness actual state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_lightness_linear_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t lightness; /* Target value of light lightness linear state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_lightness_default_set { + uint16_t lightness; /* The value of the Light Lightness Default state */ +}; + +struct bt_mesh_light_lightness_range_set { + uint16_t range_min; /* Value of range min field of light lightness range state */ + uint16_t range_max; /* Value of range max field of light lightness range state */ +}; + +/* Light CTL Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_light_ctl_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_CTL_CLI + * + * Define a new light CTL client model. Note that this API needs + * to be repeated for each element which the application wants to + * have a light CTL client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_ctl_cli. + * + * @return New light CTL client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_CTL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_LIGHT_CTL_CLI, \ + bt_mesh_light_ctl_cli_op, cli_pub, cli_data, &bt_mesh_lighting_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_light_ctl_client_t; + +struct bt_mesh_light_ctl_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_ctl_lightness; /* Present value of light ctl lightness state */ + uint16_t present_ctl_temperature; /* Present value of light ctl temperature state */ + uint16_t target_ctl_lightness; /* Target value of light ctl lightness state (optional) */ + uint16_t target_ctl_temperature; /* Target value of light ctl temperature state (C.1) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_ctl_temperature; /* Present value of light ctl temperature state */ + uint16_t present_ctl_delta_uv; /* Present value of light ctl delta UV state */ + uint16_t target_ctl_temperature; /* Target value of light ctl temperature state (optional) */ + uint16_t target_ctl_delta_uv; /* Target value of light ctl delta UV state (C.1) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_range_status { + uint8_t status_code; /* Status code for the requesting message */ + uint16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ + uint16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ +}; + +struct bt_mesh_light_ctl_default_status { + uint16_t lightness; /* Value of light lightness default state */ + uint16_t temperature; /* Value of light temperature default state */ + int16_t delta_uv; /* Value of light delta UV default state */ +}; + +struct bt_mesh_light_ctl_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t ctl_lightness; /* Target value of light ctl lightness state */ + uint16_t ctl_temperature; /* Target value of light ctl temperature state */ + int16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t ctl_temperature; /* Target value of light ctl temperature state */ + int16_t ctl_delta_uv; /* Target value of light ctl delta UV state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_ctl_temperature_range_set { + uint16_t range_min; /* Value of temperature range min field of light ctl temperature range state */ + uint16_t range_max; /* Value of temperature range max field of light ctl temperature range state */ +}; + +struct bt_mesh_light_ctl_default_set { + uint16_t lightness; /* Value of light lightness default state */ + uint16_t temperature; /* Value of light temperature default state */ + int16_t delta_uv; /* Value of light delta UV default state */ +}; + +/* Light HSL Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_light_hsl_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_HSL_CLI + * + * Define a new light HSL client model. Note that this API needs + * to be repeated for each element which the application wants to + * have a light HSL client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_hsl_cli. + * + * @return New light HSL client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_HSL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_LIGHT_HSL_CLI, \ + bt_mesh_light_hsl_cli_op, cli_pub, cli_data, &bt_mesh_lighting_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_light_hsl_client_t; + +struct bt_mesh_light_hsl_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t hsl_lightness; /* Present value of light hsl lightness state */ + uint16_t hsl_hue; /* Present value of light hsl hue state */ + uint16_t hsl_saturation; /* Present value of light hsl saturation state */ + uint8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_hsl_target_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t hsl_lightness_target; /* Target value of light hsl lightness state */ + uint16_t hsl_hue_target; /* Target value of light hsl hue state */ + uint16_t hsl_saturation_target; /* Target value of light hsl saturation state */ + uint8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_hsl_hue_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_hue; /* Present value of light hsl hue state */ + uint16_t target_hue; /* Target value of light hsl hue state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_hsl_saturation_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t present_saturation; /* Present value of light hsl saturation state */ + uint16_t target_saturation; /* Target value of light hsl saturation state (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_hsl_default_status { + uint16_t lightness; /* Value of light lightness default state */ + uint16_t hue; /* Value of light hue default state */ + uint16_t saturation; /* Value of light saturation default state */ +}; + +struct bt_mesh_light_hsl_range_status { + uint8_t status_code; /* Status code for the requesting message */ + uint16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ + uint16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ + uint16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ + uint16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +}; + +struct bt_mesh_light_hsl_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t hsl_lightness; /* Target value of light hsl lightness state */ + uint16_t hsl_hue; /* Target value of light hsl hue state */ + uint16_t hsl_saturation; /* Target value of light hsl saturation state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_hsl_hue_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t hue; /* Target value of light hsl hue state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_hsl_saturation_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t saturation; /* Target value of light hsl hue state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_hsl_default_set { + uint16_t lightness; /* Value of light lightness default state */ + uint16_t hue; /* Value of light hue default state */ + uint16_t saturation; /* Value of light saturation default state */ +}; + +struct bt_mesh_light_hsl_range_set { + uint16_t hue_range_min; /* Value of hue range min field of light hsl hue range state */ + uint16_t hue_range_max; /* Value of hue range max field of light hsl hue range state */ + uint16_t saturation_range_min; /* Value of saturation range min field of light hsl saturation range state */ + uint16_t saturation_range_max; /* Value of saturation range max field of light hsl saturation range state */ +}; + +/* Light xyL Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_light_xyl_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_XYL_CLI + * + * Define a new light xyL client model. Note that this API needs + * to be repeated for each element which the application wants + * to have a light xyL client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_xyl_cli. + * + * @return New light xyL client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_XYL_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_LIGHT_XYL_CLI, \ + bt_mesh_light_xyl_cli_op, cli_pub, cli_data, &bt_mesh_lighting_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_light_xyl_client_t; + +struct bt_mesh_light_xyl_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t xyl_lightness; /* The present value of the Light xyL Lightness state */ + uint16_t xyl_x; /* The present value of the Light xyL x state */ + uint16_t xyl_y; /* The present value of the Light xyL y state */ + uint8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_xyl_target_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t target_xyl_lightness; /* The target value of the Light xyL Lightness state */ + uint16_t target_xyl_x; /* The target value of the Light xyL x state */ + uint16_t target_xyl_y; /* The target value of the Light xyL y state */ + uint8_t remain_time; /* Time to complete state transition (optional) */ +}; + +struct bt_mesh_light_xyl_default_status { + uint16_t lightness; /* The value of the Light Lightness Default state */ + uint16_t xyl_x; /* The value of the Light xyL x Default state */ + uint16_t xyl_y; /* The value of the Light xyL y Default state */ +}; + +struct bt_mesh_light_xyl_range_status { + uint8_t status_code; /* Status Code for the requesting message */ + uint16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ + uint16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ + uint16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ + uint16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +}; + +struct bt_mesh_light_xyl_set { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t xyl_lightness; /* The target value of the Light xyL Lightness state */ + uint16_t xyl_x; /* The target value of the Light xyL x state */ + uint16_t xyl_y; /* The target value of the Light xyL y state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_xyl_default_set { + uint16_t lightness; /* The value of the Light Lightness Default state */ + uint16_t xyl_x; /* The value of the Light xyL x Default state */ + uint16_t xyl_y; /* The value of the Light xyL y Default state */ +}; + +struct bt_mesh_light_xyl_range_set { + uint16_t xyl_x_range_min; /* The value of the xyL x Range Min field of the Light xyL x Range state */ + uint16_t xyl_x_range_max; /* The value of the xyL x Range Max field of the Light xyL x Range state */ + uint16_t xyl_y_range_min; /* The value of the xyL y Range Min field of the Light xyL y Range state */ + uint16_t xyl_y_range_max; /* The value of the xyL y Range Max field of the Light xyL y Range state */ +}; + +/* Light LC Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_light_lc_cli_op[]; + +/** @def BLE_MESH_MODEL_LIGHT_LC_CLI + * + * Define a new light lc client model. Note that this API needs + * to be repeated for each element which the application wants + * to have a light lc client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_light_lc_cli. + * + * @return New light lc client model instance. + */ +#define BLE_MESH_MODEL_LIGHT_LC_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_LIGHT_LC_CLI, \ + bt_mesh_light_lc_cli_op, cli_pub, cli_data, &bt_mesh_lighting_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_light_lc_client_t; + +struct bt_mesh_light_lc_mode_status { + uint8_t mode; /* The present value of the Light LC Mode state */ +}; + +struct bt_mesh_light_lc_om_status { + uint8_t mode; /* The present value of the Light LC Occupancy Mode state */ +}; + +struct bt_mesh_light_lc_light_onoff_status { + bool op_en; /* Indicate whether optional parameters included */ + uint8_t present_light_onoff; /* The present value of the Light LC Light OnOff state */ + uint8_t target_light_onoff; /* The target value of the Light LC Light OnOff state (Optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_light_lc_property_status { + uint16_t light_lc_property_id; /* Property ID identifying a Light LC Property */ + struct net_buf_simple *light_lc_property_value; /* Raw value for the Light LC Property */ +}; + +struct bt_mesh_light_lc_mode_set { + uint8_t mode; /* The target value of the Light LC Mode state */ +}; + +struct bt_mesh_light_lc_om_set { + uint8_t mode; /* The target value of the Light LC Occupancy Mode state */ +}; + +struct bt_mesh_light_lc_light_onoff_set { + bool op_en; /* Indicate whether optional parameters included */ + uint8_t light_onoff; /* The target value of the Light LC Light OnOff state */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_light_lc_property_get { + uint16_t light_lc_property_id; /* Property ID identifying a Light LC Property */ +}; + +struct bt_mesh_light_lc_property_set { + uint16_t light_lc_property_id; /* Property ID identifying a Light LC Property */ + struct net_buf_simple *light_lc_property_value; /* Raw value for the Light LC Property */ +}; + +/** + * @brief This function is called to get light states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of light get message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_client_get_state(bt_mesh_client_common_param_t *common, void *get); + +/** + * @brief This function is called to set light states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of light set message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_light_client_set_state(bt_mesh_client_common_param_t *common, void *set); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIGHTING_CLIENT_H_ */ diff --git a/lib/bt/esp_ble_mesh/models/client/include/mesh/sensor_client.h b/lib/bt/esp_ble_mesh/models/client/include/mesh/sensor_client.h new file mode 100644 index 00000000..f8b0057c --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/include/mesh/sensor_client.h @@ -0,0 +1,155 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Bluetooth Mesh Sensor Client Model APIs. + */ + +#ifndef _SENSOR_CLIENT_H_ +#define _SENSOR_CLIENT_H_ + +#include "mesh/client_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Sensor Client Model Callback */ +extern const struct bt_mesh_model_cb bt_mesh_sensor_client_cb; + +/* Sensor Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_sensor_cli_op[]; + +/** @def BLE_MESH_MODEL_SENSOR_CLI + * + * Define a new sensor client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a sensor client model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_sensor_cli. + * + * @return New sensor client model instance. + */ +#define BLE_MESH_MODEL_SENSOR_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_SENSOR_CLI, \ + bt_mesh_sensor_cli_op, cli_pub, cli_data, &bt_mesh_sensor_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_sensor_client_t; +typedef bt_mesh_client_internal_data_t sensor_internal_data_t; + +struct bt_mesh_sensor_descriptor_status { + struct net_buf_simple *descriptor; /* Sequence of 8-octet sensor descriptors (optional) */ +}; + +struct bt_mesh_sensor_cadence_status { + uint16_t property_id; /* Property for the sensor */ + struct net_buf_simple *sensor_cadence_value; /* Value of sensor cadence state */ +}; + +struct bt_mesh_sensor_settings_status { + uint16_t sensor_property_id; /* Property ID identifying a sensor */ + struct net_buf_simple *sensor_setting_property_ids; /* A sequence of N sensor setting property IDs (optional) */ +}; + +struct bt_mesh_sensor_setting_status { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t sensor_property_id; /* Property ID identifying a sensor */ + uint16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + uint8_t sensor_setting_access; /* Read/Write access rights for the setting (optional) */ + struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ +}; + +struct bt_mesh_sensor_status { + struct net_buf_simple *marshalled_sensor_data; /* Value of sensor data state (optional) */ +}; + +struct bt_mesh_sensor_column_status { + uint16_t property_id; /* Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_column_value; /* Left values of sensor column status */ +}; + +struct bt_mesh_sensor_series_status { + uint16_t property_id; /* Property identifying a sensor and the Y axis */ + struct net_buf_simple *sensor_series_value; /* Left values of sensor series status */ +}; + +struct bt_mesh_sensor_descriptor_get { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t property_id; /* Property ID for the sensor (optional) */ +}; + +struct bt_mesh_sensor_cadence_get { + uint16_t property_id; /* Property ID for the sensor */ +}; + +struct bt_mesh_sensor_cadence_set { + uint16_t property_id; /* Property ID for the sensor */ + uint8_t fast_cadence_period_divisor : 7, /* Divisor for the publish period */ + status_trigger_type : 1; /* The unit and format of the Status Trigger Delta fields */ + struct net_buf_simple *status_trigger_delta_down; /* Delta down value that triggers a status message */ + struct net_buf_simple *status_trigger_delta_up; /* Delta up value that triggers a status message */ + uint8_t status_min_interval; /* Minimum interval between two consecutive Status messages */ + struct net_buf_simple *fast_cadence_low; /* Low value for the fast cadence range */ + struct net_buf_simple *fast_cadence_high; /* Fast value for the fast cadence range */ +}; + +struct bt_mesh_sensor_settings_get { + uint16_t sensor_property_id; /* Property ID for the sensor */ +}; + +struct bt_mesh_sensor_setting_get { + uint16_t sensor_property_id; /* Property ID identifying a sensor */ + uint16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ +}; + +struct bt_mesh_sensor_setting_set { + uint16_t sensor_property_id; /* Property ID identifying a sensor */ + uint16_t sensor_setting_property_id; /* Setting ID identifying a setting within a sensor */ + struct net_buf_simple *sensor_setting_raw; /* Raw value for the setting */ +}; + +struct bt_mesh_sensor_get { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t property_id; /* Property ID for the sensor (optional) */ +}; + +struct bt_mesh_sensor_column_get { + uint16_t property_id; /* Property identifying a sensor */ + struct net_buf_simple *raw_value_x; /* Raw value identifying a column */ +}; + +struct bt_mesh_sensor_series_get { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t property_id; /* Property identifying a sensor */ + struct net_buf_simple *raw_value_x1; /* Raw value identifying a starting column (optional) */ + struct net_buf_simple *raw_value_x2; /* Raw value identifying a ending column (C.1) */ +}; + +/** + * @brief This function is called to get sensor states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of sensor get message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_sensor_client_get_state(bt_mesh_client_common_param_t *common, void *get); + +/** + * @brief This function is called to set sensor states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of sensor set message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_sensor_client_set_state(bt_mesh_client_common_param_t *common, void *set); + +#ifdef __cplusplus +} +#endif + +#endif /* _SENSOR_CLIENT_H_ */ diff --git a/lib/bt/esp_ble_mesh/models/client/include/mesh/time_scene_client.h b/lib/bt/esp_ble_mesh/models/client/include/mesh/time_scene_client.h new file mode 100644 index 00000000..cfb62e05 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/include/mesh/time_scene_client.h @@ -0,0 +1,225 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Bluetooth Mesh Time and Scene Client Model APIs. + */ + +#ifndef _TIME_SCENE_CLIENT_H_ +#define _TIME_SCENE_CLIENT_H_ + +#include "mesh/client_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Time scene client model common structure */ +typedef bt_mesh_client_user_data_t bt_mesh_time_scene_client_t; +typedef bt_mesh_client_internal_data_t time_scene_internal_data_t; + +/* Time Scene Client Model Callback */ +extern const struct bt_mesh_model_cb bt_mesh_time_scene_client_cb; + +/* Time Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_time_cli_op[]; + +/** @def BLE_MESH_MODEL_TIME_CLI + * + * Define a new time client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a time model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_time_cli. + * + * @return New time client model instance. + */ +#define BLE_MESH_MODEL_TIME_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_TIME_CLI, \ + bt_mesh_time_cli_op, cli_pub, cli_data, &bt_mesh_time_scene_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_time_client_t; + +struct bt_mesh_time_status { + uint8_t tai_seconds[5]; /* The current TAI time in seconds */ + uint8_t sub_second; /* The sub-second time in units of 1/256 second */ + uint8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ + uint16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ + uint16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ + uint8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ +}; + +struct bt_mesh_time_zone_status { + uint8_t time_zone_offset_curr; /* Current local time zone offset */ + uint8_t time_zone_offset_new; /* Upcoming local time zone offset */ + uint8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ +}; + +struct bt_mesh_tai_utc_delta_status { + uint16_t tai_utc_delta_curr : 15; /* Current difference between TAI and UTC in seconds */ + uint16_t padding_1 : 1; /* Always 0b0. Other values are Prohibited. */ + uint16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ + uint16_t padding_2 : 1; /* Always 0b0. Other values are Prohibited. */ + uint8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ +}; + +struct bt_mesh_time_role_status { + uint8_t time_role; /* The Time Role for the element */ +}; + +struct bt_mesh_time_set { + uint8_t tai_seconds[5]; /* The current TAI time in seconds */ + uint8_t sub_second; /* The sub-second time in units of 1/256 second */ + uint8_t uncertainty; /* The estimated uncertainty in 10-millisecond steps */ + uint16_t time_authority : 1; /* 0 = No Time Authority, 1 = Time Authority */ + uint16_t tai_utc_delta : 15; /* Current difference between TAI and UTC in seconds */ + uint8_t time_zone_offset; /* The local time zone offset in 15-minute increments */ +}; + +struct bt_mesh_time_zone_set { + uint8_t time_zone_offset_new; /* Upcoming local time zone offset */ + uint8_t tai_zone_change[5]; /* TAI Seconds time of the upcoming Time Zone Offset change */ +}; + +struct bt_mesh_tai_utc_delta_set { + uint16_t tai_utc_delta_new : 15; /* Upcoming difference between TAI and UTC in seconds */ + uint16_t padding : 1; /* Always 0b0. Other values are Prohibited. */ + uint8_t tai_delta_change[5]; /* TAI Seconds time of the upcoming TAI-UTC Delta change */ +}; + +struct bt_mesh_time_role_set { + uint8_t time_role; /* The Time Role for the element */ +}; + +/* Scene Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_scene_cli_op[]; + +/** @def BLE_MESH_MODEL_SCENE_CLI + * + * Define a new scene client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a scene model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_scene_cli. + * + * @return New scene client model instance. + */ +#define BLE_MESH_MODEL_SCENE_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_SCENE_CLI, \ + bt_mesh_scene_cli_op, cli_pub, cli_data, &bt_mesh_time_scene_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_scene_client_t; + +struct bt_mesh_scene_status { + bool op_en; /* Indicate whether optional parameters included */ + uint8_t status_code; /* Status code for the last operation */ + uint16_t current_scene; /* Scene Number of a current scene */ + uint16_t target_scene; /* Scene Number of a target scene (optional) */ + uint8_t remain_time; /* Time to complete state transition (C.1) */ +}; + +struct bt_mesh_scene_register_status { + uint8_t status_code; /* Status code for the previous operation */ + uint16_t current_scene; /* Scene Number of a current scene */ + struct net_buf_simple *scenes; /* A list of scenes stored within an element */ +}; + +struct bt_mesh_scene_store { + uint16_t scene_number; /* The number of the scene to be stored */ +}; + +struct bt_mesh_scene_recall { + bool op_en; /* Indicate whether optional parameters included */ + uint16_t scene_number; /* The number of the scene to be recalled */ + uint8_t tid; /* Transaction Identifier */ + uint8_t trans_time; /* Time to complete state transition (optional) */ + uint8_t delay; /* Indicate message execution delay (C.1) */ +}; + +struct bt_mesh_scene_delete { + uint16_t scene_number; /* The number of the scene to be deleted */ +}; + +/* Scheduler Client Model Context */ +extern const struct bt_mesh_model_op bt_mesh_scheduler_cli_op[]; + +/** @def BLE_MESH_MODEL_SCHEDULER_CLI + * + * Define a new scheduler client model. Note that this API needs to + * be repeated for each element which the application wants to + * have a scheduler model on. + * @param cli_pub Pointer to a unique struct bt_mesh_model_pub. + * @param cli_data Pointer to a unique struct bt_mesh_scheduler_cli. + * + * @return New scheduler client model instance. + */ +#define BLE_MESH_MODEL_SCHEDULER_CLI(cli_pub, cli_data) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_SCHEDULER_CLI, \ + bt_mesh_scheduler_cli_op, cli_pub, cli_data, &bt_mesh_time_scene_client_cb) + +typedef bt_mesh_client_user_data_t bt_mesh_scheduler_client_t; + +struct bt_mesh_scheduler_status { + uint16_t schedules; /* Bit field indicating defined Actions in the Schedule Register */ +}; + +struct bt_mesh_scheduler_act_status { + uint64_t index : 4; /* Enumerates (selects) a Schedule Register entry */ + uint64_t year : 7; /* Scheduled year for the action */ + uint64_t month : 12; /* Scheduled month for the action */ + uint64_t day : 5; /* Scheduled day of the month for the action */ + uint64_t hour : 5; /* Scheduled hour for the action */ + uint64_t minute : 6; /* Scheduled minute for the action */ + uint64_t second : 6; /* Scheduled second for the action */ + uint64_t day_of_week : 7; /* Schedule days of the week for the action */ + uint64_t action : 4; /* Action to be performed at the scheduled time */ + uint64_t trans_time : 8; /* Transition time for this action */ + uint16_t scene_number; /* Transition time for this action */ +}; + +struct bt_mesh_scheduler_act_get { + uint8_t index; /* Index of the Schedule Register entry to get */ +}; + +struct bt_mesh_scheduler_act_set { + uint64_t index : 4; /* Index of the Schedule Register entry to set */ + uint64_t year : 7; /* Scheduled year for the action */ + uint64_t month : 12; /* Scheduled month for the action */ + uint64_t day : 5; /* Scheduled day of the month for the action */ + uint64_t hour : 5; /* Scheduled hour for the action */ + uint64_t minute : 6; /* Scheduled minute for the action */ + uint64_t second : 6; /* Scheduled second for the action */ + uint64_t day_of_week : 7; /* Schedule days of the week for the action */ + uint64_t action : 4; /* Action to be performed at the scheduled time */ + uint64_t trans_time : 8; /* Transition time for this action */ + uint16_t scene_number; /* Transition time for this action */ +}; + +/** + * @brief This function is called to get scene states. + * + * @param[in] common: Message common information structure + * @param[in] get: Pointer of time scene get message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_time_scene_client_get_state(bt_mesh_client_common_param_t *common, void *get); + +/** + * @brief This function is called to set scene states. + * + * @param[in] common: Message common information structure + * @param[in] set: Pointer of time scene set message value + * + * @return Zero-success, other-fail + */ +int bt_mesh_time_scene_client_set_state(bt_mesh_client_common_param_t *common, void *set); + +#ifdef __cplusplus +} +#endif + +#endif /* _TIME_SCENE_CLIENT_H_ */ diff --git a/lib/bt/esp_ble_mesh/models/client/lighting_client.c b/lib/bt/esp_ble_mesh/models/client/lighting_client.c new file mode 100644 index 00000000..6448a410 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/lighting_client.c @@ -0,0 +1,1375 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> +#include <errno.h> + +#include "btc_ble_mesh_lighting_model.h" + +#include "mesh/config.h" +#include "mesh/model_opcode.h" + +#if CONFIG_BLE_MESH_LIGHTING_CLIENT +#include "mesh/lighting_client.h" + +/* The followings are the macro definitions of Lighting client + * model message length, and a message is composed of 3 parts: + * Opcode + Payload + MIC + */ +/* Light lightness client messages length */ +#define BLE_MESH_LIGHT_LIGHTNESS_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_LINEAR_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_LINEAR_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_LAST_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_DEFAULT_SET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_LIGHTNESS_RANGE_SET_MSG_LEN (2 + 4 + 4) + +/* Light CTL client messages length */ +#define BLE_MESH_LIGHT_CTL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_SET_MSG_LEN (2 + 9 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_SET_MSG_LEN (2 + 7 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_TEMPERATURE_RANGE_SET_MSG_LEN (2 + 4 + 4) +#define BLE_MESH_LIGHT_CTL_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_CTL_DEFAULT_SET_MSG_LEN (2 + 6 + 4) + +/* Light HSL client messages length */ +#define BLE_MESH_LIGHT_HSL_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_SET_MSG_LEN (2 + 9 + 4) +#define BLE_MESH_LIGHT_HSL_TARGET_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_HUE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_HUE_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_HSL_SATURATION_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_SATURATION_SET_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_LIGHT_HSL_DEFAULT_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_DEFAULT_SET_MSG_LEN (2 + 6 + 4) +#define BLE_MESH_LIGHT_HSL_RANGE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_LIGHT_HSL_RANGE_SET_MSG_LEN (2 + 8 + 4) + +/* Light xyL client messages length */ +#define BLE_MESH_LIGHT_XYL_SET_MSG_LEN (2 + 9 + 4) +#define BLE_MESH_LIGHT_XYL_DEFAULT_SET_MSG_LEN (2 + 6 + 4) +#define BLE_MESH_LIGHT_XYL_RANGE_SET_MSG_LEN (2 + 8 + 4) + +/* Light LC client messages length */ +#define BLE_MESH_LIGHT_LC_MODE_SET_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_LIGHT_LC_OM_SET_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_LIGHT_LC_LIGHT_ONOFF_SET_MSG_LEN (2 + 4 + 4) +#define BLE_MESH_LIGHT_LC_PROPERTY_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_LIGHT_LC_PROPERTY_SET_MSG_LEN /* variable */ + +#define BLE_MESH_LIGHT_GET_STATE_MSG_LEN (2 + 2 + 4) + +static const bt_mesh_client_op_pair_t light_op_pair[] = { + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_SET, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET, BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS }, + { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET, BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS }, +}; + +static bt_mesh_mutex_t lighting_client_lock; + +static void timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + uint32_t opcode = 0U; + + BT_WARN("Receive light status message timeout"); + + bt_mesh_mutex_lock(&lighting_client_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (node) { + memcpy(&ctx, &node->ctx, sizeof(ctx)); + opcode = node->opcode; + model = node->model; + bt_mesh_client_free_node(node); + bt_mesh_lighting_client_cb_evt_to_btc( + opcode, BTC_BLE_MESH_EVT_LIGHTING_CLIENT_TIMEOUT, model, &ctx, NULL, 0); + } + } + + bt_mesh_mutex_unlock(&lighting_client_lock); +} + +static void light_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + bt_mesh_client_node_t *node = NULL; + uint8_t *val = NULL; + uint8_t evt = 0xFF; + size_t len = 0U; + + BT_DBG("len %d, bytes %s", buf->len, bt_hex(buf->data, buf->len)); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS: { + struct bt_mesh_light_lightness_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Light Lightness Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lightness_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_lightness = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_lightness = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS: { + struct bt_mesh_light_lightness_linear_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Light Lightness Linear Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lightness_linear_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_lightness = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_lightness = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_linear_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS: { + struct bt_mesh_light_lightness_last_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Light Lightness Last Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lightness_last_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_last_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS: { + struct bt_mesh_light_lightness_default_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Light Lightness Default Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lightness_default_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS: { + struct bt_mesh_light_lightness_range_status *status = NULL; + if (buf->len != 5) { + BT_ERR("Invalid Light Lightness Range Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lightness_range_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->range_min = net_buf_simple_pull_le16(buf); + status->range_max = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lightness_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS: { + struct bt_mesh_light_ctl_status *status = NULL; + if (buf->len != 4 && buf->len != 9) { + BT_ERR("Invalid Light CTL Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_ctl_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_ctl_lightness = net_buf_simple_pull_le16(buf); + status->present_ctl_temperature = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_ctl_lightness = net_buf_simple_pull_le16(buf); + status->target_ctl_temperature = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS: { + struct bt_mesh_light_ctl_temperature_status *status = NULL; + if (buf->len != 4 && buf->len != 9) { + BT_ERR("Invalid Light CTL Temperature Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_ctl_temperature_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_ctl_temperature = net_buf_simple_pull_le16(buf); + status->present_ctl_delta_uv = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_ctl_temperature = net_buf_simple_pull_le16(buf); + status->target_ctl_delta_uv = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_temperature_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS: { + struct bt_mesh_light_ctl_temperature_range_status *status = NULL; + if (buf->len != 5) { + BT_ERR("Invalid Light CTL Temperature Range Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_ctl_temperature_range_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->range_min = net_buf_simple_pull_le16(buf); + status->range_max = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_temperature_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS: { + struct bt_mesh_light_ctl_default_status *status = NULL; + if (buf->len != 6) { + BT_ERR("Invalid Light CTL Default Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_ctl_default_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + status->temperature = net_buf_simple_pull_le16(buf); + status->delta_uv = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_ctl_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS: { + struct bt_mesh_light_hsl_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("Invalid Light HSL Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_hsl_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->hsl_lightness = net_buf_simple_pull_le16(buf); + status->hsl_hue = net_buf_simple_pull_le16(buf); + status->hsl_saturation = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS: { + struct bt_mesh_light_hsl_target_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("Invalid Light HSL Target Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_hsl_target_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->hsl_lightness_target = net_buf_simple_pull_le16(buf); + status->hsl_hue_target = net_buf_simple_pull_le16(buf); + status->hsl_saturation_target = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_target_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS: { + struct bt_mesh_light_hsl_hue_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Light HSL Hue Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_hsl_hue_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_hue = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_hue = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_hue_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS: { + struct bt_mesh_light_hsl_saturation_status *status = NULL; + if (buf->len != 2 && buf->len != 5) { + BT_ERR("Invalid Light HSL Saturation Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_hsl_saturation_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_saturation = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_saturation = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_saturation_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS: { + struct bt_mesh_light_hsl_default_status *status = NULL; + if (buf->len != 6) { + BT_ERR("Invalid Light HSL Default Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_hsl_default_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + status->hue = net_buf_simple_pull_le16(buf); + status->saturation = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS: { + struct bt_mesh_light_hsl_range_status *status = NULL; + if (buf->len != 9) { + BT_ERR("Invalid Light HSL Range Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_hsl_range_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->hue_range_min = net_buf_simple_pull_le16(buf); + status->hue_range_max = net_buf_simple_pull_le16(buf); + status->saturation_range_min = net_buf_simple_pull_le16(buf); + status->saturation_range_max = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_hsl_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS: { + struct bt_mesh_light_xyl_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("Invalid Light xyL Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_xyl_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->xyl_lightness = net_buf_simple_pull_le16(buf); + status->xyl_x = net_buf_simple_pull_le16(buf); + status->xyl_y = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS: { + struct bt_mesh_light_xyl_target_status *status = NULL; + if (buf->len != 6 && buf->len != 7) { + BT_ERR("Invalid Light xyL Target Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_xyl_target_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->target_xyl_lightness = net_buf_simple_pull_le16(buf); + status->target_xyl_x = net_buf_simple_pull_le16(buf); + status->target_xyl_y = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_target_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS: { + struct bt_mesh_light_xyl_default_status *status = NULL; + if (buf->len != 6) { + BT_ERR("Invalid Light xyL Default Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_xyl_default_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->lightness = net_buf_simple_pull_le16(buf); + status->xyl_x = net_buf_simple_pull_le16(buf); + status->xyl_y = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_default_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS: { + struct bt_mesh_light_xyl_range_status *status = NULL; + if (buf->len != 9) { + BT_ERR("Invalid Light xyL Range Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_xyl_range_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->xyl_x_range_min = net_buf_simple_pull_le16(buf); + status->xyl_x_range_max = net_buf_simple_pull_le16(buf); + status->xyl_y_range_min = net_buf_simple_pull_le16(buf); + status->xyl_y_range_max = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_xyl_range_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS: { + struct bt_mesh_light_lc_mode_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Light LC Mode Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lc_mode_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->mode = net_buf_simple_pull_u8(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lc_mode_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS: { + struct bt_mesh_light_lc_om_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Light LC OM Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lc_om_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->mode = net_buf_simple_pull_u8(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lc_om_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS: { + struct bt_mesh_light_lc_light_onoff_status *status = NULL; + if (buf->len != 1 && buf->len != 3) { + BT_ERR("Invalid Light LC Light OnOff Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lc_light_onoff_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->present_light_onoff = net_buf_simple_pull_u8(buf); + if (buf->len) { + status->op_en = true; + status->target_light_onoff = net_buf_simple_pull_u8(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lc_light_onoff_status); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: { + struct bt_mesh_light_lc_property_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_light_lc_property_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->light_lc_property_id = net_buf_simple_pull_le16(buf); + status->light_lc_property_value = bt_mesh_alloc_buf(buf->len); + if (!status->light_lc_property_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->light_lc_property_value, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_light_lc_property_status); + break; + } + default: + BT_ERR("Invalid Lighting Status opcode 0x%04x", ctx->recv_op); + return; + } + + buf->data = val; + buf->len = len; + + bt_mesh_mutex_lock(&lighting_client_lock); + + node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected Lighting Status 0x%04x", ctx->recv_op); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: + evt = BTC_BLE_MESH_EVT_LIGHTING_CLIENT_GET_STATE; + break; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + evt = BTC_BLE_MESH_EVT_LIGHTING_CLIENT_SET_STATE; + break; + default: + break; + } + + if (!k_delayed_work_free(&node->timer)) { + uint32_t opcode = node->opcode; + bt_mesh_client_free_node(node); + bt_mesh_lighting_client_cb_evt_to_btc(opcode, evt, model, ctx, val, len); + } + } + + bt_mesh_mutex_unlock(&lighting_client_lock); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS: { + struct bt_mesh_light_lc_property_status *status; + status = (struct bt_mesh_light_lc_property_status *)val; + bt_mesh_free_buf(status->light_lc_property_value); + break; + } + default: + break; + } + + bt_mesh_free(val); +} + +const struct bt_mesh_model_op bt_mesh_light_lightness_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS, 5, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_light_ctl_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS, 4, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS, 4, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS, 5, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS, 6, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_light_hsl_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS, 2, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS, 9, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_light_xyl_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS, 6, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS, 9, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_light_lc_cli_op[] = { + { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS, 1, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS, 1, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS, 1, light_status }, + { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS, 2, light_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int light_get_state(bt_mesh_client_common_param_t *common, void *value) +{ + NET_BUF_SIMPLE_DEFINE(msg, BLE_MESH_LIGHT_GET_STATE_MSG_LEN); + + bt_mesh_model_msg_init(&msg, common->opcode); + + if (value) { + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: { + struct bt_mesh_light_lc_property_get *get; + get = (struct bt_mesh_light_lc_property_get *)value; + net_buf_simple_add_le16(&msg, get->light_lc_property_id); + break; + } + default: + BT_DBG("No parameters for Lighting Get 0x%04x", common->opcode); + break; + } + } + + return bt_mesh_client_send_msg(common, &msg, true, timeout_handler); +} + +static int light_set_state(bt_mesh_client_common_param_t *common, + void *value, uint16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err = 0; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK: { + struct bt_mesh_light_lightness_set *set; + set = (struct bt_mesh_light_lightness_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK: { + struct bt_mesh_light_lightness_linear_set *set; + set = (struct bt_mesh_light_lightness_linear_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK: { + struct bt_mesh_light_lightness_default_set *set; + set = (struct bt_mesh_light_lightness_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK: { + struct bt_mesh_light_lightness_range_set *set; + set = (struct bt_mesh_light_lightness_range_set *)value; + net_buf_simple_add_le16(msg, set->range_min); + net_buf_simple_add_le16(msg, set->range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK: { + struct bt_mesh_light_ctl_set *set; + set = (struct bt_mesh_light_ctl_set *)value; + net_buf_simple_add_le16(msg, set->ctl_lightness); + net_buf_simple_add_le16(msg, set->ctl_temperature); + net_buf_simple_add_le16(msg, set->ctl_delta_uv); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_set *set; + set = (struct bt_mesh_light_ctl_temperature_set *)value; + net_buf_simple_add_le16(msg, set->ctl_temperature); + net_buf_simple_add_le16(msg, set->ctl_delta_uv); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_range_set *set; + set = (struct bt_mesh_light_ctl_temperature_range_set *)value; + net_buf_simple_add_le16(msg, set->range_min); + net_buf_simple_add_le16(msg, set->range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK: { + struct bt_mesh_light_ctl_default_set *set; + set = (struct bt_mesh_light_ctl_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_le16(msg, set->temperature); + net_buf_simple_add_le16(msg, set->delta_uv); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK: { + struct bt_mesh_light_hsl_set *set; + set = (struct bt_mesh_light_hsl_set *)value; + net_buf_simple_add_le16(msg, set->hsl_lightness); + net_buf_simple_add_le16(msg, set->hsl_hue); + net_buf_simple_add_le16(msg, set->hsl_saturation); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK: { + struct bt_mesh_light_hsl_hue_set *set; + set = (struct bt_mesh_light_hsl_hue_set *)value; + net_buf_simple_add_le16(msg, set->hue); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK: { + struct bt_mesh_light_hsl_saturation_set *set; + set = (struct bt_mesh_light_hsl_saturation_set *)value; + net_buf_simple_add_le16(msg, set->saturation); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK: { + struct bt_mesh_light_hsl_default_set *set; + set = (struct bt_mesh_light_hsl_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_le16(msg, set->hue); + net_buf_simple_add_le16(msg, set->saturation); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK: { + struct bt_mesh_light_hsl_range_set *set; + set = (struct bt_mesh_light_hsl_range_set *)value; + net_buf_simple_add_le16(msg, set->hue_range_min); + net_buf_simple_add_le16(msg, set->hue_range_max); + net_buf_simple_add_le16(msg, set->saturation_range_min); + net_buf_simple_add_le16(msg, set->saturation_range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK: { + struct bt_mesh_light_xyl_set *set; + set = (struct bt_mesh_light_xyl_set *)value; + net_buf_simple_add_le16(msg, set->xyl_lightness); + net_buf_simple_add_le16(msg, set->xyl_x); + net_buf_simple_add_le16(msg, set->xyl_y); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK: { + struct bt_mesh_light_xyl_default_set *set; + set = (struct bt_mesh_light_xyl_default_set *)value; + net_buf_simple_add_le16(msg, set->lightness); + net_buf_simple_add_le16(msg, set->xyl_x); + net_buf_simple_add_le16(msg, set->xyl_y); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK: { + struct bt_mesh_light_xyl_range_set *set; + set = (struct bt_mesh_light_xyl_range_set *)value; + net_buf_simple_add_le16(msg, set->xyl_x_range_min); + net_buf_simple_add_le16(msg, set->xyl_x_range_max); + net_buf_simple_add_le16(msg, set->xyl_y_range_min); + net_buf_simple_add_le16(msg, set->xyl_y_range_max); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK: { + struct bt_mesh_light_lc_mode_set *set; + set = (struct bt_mesh_light_lc_mode_set *)value; + net_buf_simple_add_u8(msg, set->mode); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK: { + struct bt_mesh_light_lc_om_set *set; + set = (struct bt_mesh_light_lc_om_set *)value; + net_buf_simple_add_u8(msg, set->mode); + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK: { + struct bt_mesh_light_lc_light_onoff_set *set; + set = (struct bt_mesh_light_lc_light_onoff_set *)value; + net_buf_simple_add_u8(msg, set->light_onoff); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK: { + struct bt_mesh_light_lc_property_set *set; + set = (struct bt_mesh_light_lc_property_set *)value; + net_buf_simple_add_le16(msg, set->light_lc_property_id); + net_buf_simple_add_mem(msg, set->light_lc_property_value->data, set->light_lc_property_value->len); + break; + } + default: + BT_ERR("Invalid Lighting Set opcode 0x%04x", common->opcode); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common, msg, need_ack, timeout_handler); + +end: + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_light_client_get_state(bt_mesh_client_common_param_t *common, void *get) +{ + bt_mesh_light_client_t *client = NULL; + + if (!common || !common->model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Lighting client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET: + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET: + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET: + break; + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET: + if (!get) { + BT_ERR("Invalid Lighting LC Property Get"); + return -EINVAL; + } + break; + default: + BT_ERR("Invalid Lighting Get opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return light_get_state(common, get); +} + +int bt_mesh_light_client_set_state(bt_mesh_client_common_param_t *common, void *set) +{ + bt_mesh_light_client_t *client = NULL; + uint16_t length = 0U; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Lighting client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK: { + struct bt_mesh_light_lightness_set *value; + value = (struct bt_mesh_light_lightness_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light Lightness Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_LIGHTNESS_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK: { + struct bt_mesh_light_lightness_linear_set *value; + value = (struct bt_mesh_light_lightness_linear_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light Lightness Linear Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_LIGHTNESS_LINEAR_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_LIGHTNESS_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK: { + struct bt_mesh_light_lightness_range_set *value; + value = (struct bt_mesh_light_lightness_range_set *)set; + if (value->range_min > value->range_max) { + BT_ERR("Light Lightness Range Set range min is greater than range max"); + return -EINVAL; + } + length = BLE_MESH_LIGHT_LIGHTNESS_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK: { + struct bt_mesh_light_ctl_set *value; + value = (struct bt_mesh_light_ctl_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light CTL Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_CTL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_set *value; + value = (struct bt_mesh_light_ctl_temperature_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light CTL Temperature Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_CTL_TEMPERATURE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK: { + struct bt_mesh_light_ctl_temperature_range_set *value; + value = (struct bt_mesh_light_ctl_temperature_range_set *)set; + if (value->range_min > value->range_max) { + BT_ERR("Light CTL Temperature Range Set range min is greater than range max"); + return -EINVAL; + } + length = BLE_MESH_LIGHT_CTL_TEMPERATURE_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_CTL_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK: { + struct bt_mesh_light_hsl_set *value; + value = (struct bt_mesh_light_hsl_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light HSL Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_HSL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK: { + struct bt_mesh_light_hsl_hue_set *value; + value = (struct bt_mesh_light_hsl_hue_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light HSL Hue Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_HSL_HUE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK: { + struct bt_mesh_light_hsl_saturation_set *value; + value = (struct bt_mesh_light_hsl_saturation_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light HSL Saturation Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_HSL_SATURATION_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_HSL_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK: { + struct bt_mesh_light_hsl_range_set *value; + value = (struct bt_mesh_light_hsl_range_set *)set; + if (value->hue_range_min > value->hue_range_max || + value->saturation_range_min > value->saturation_range_max) { + BT_ERR("Light HSL Range Set range min is greater than range max"); + return -EINVAL; + } + length = BLE_MESH_LIGHT_HSL_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK: { + struct bt_mesh_light_xyl_set *value; + value = (struct bt_mesh_light_xyl_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light xyL Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_XYL_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK: + length = BLE_MESH_LIGHT_XYL_DEFAULT_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK: { + struct bt_mesh_light_xyl_range_set *value; + value = (struct bt_mesh_light_xyl_range_set *)set; + if (value->xyl_x_range_min > value->xyl_x_range_max || + value->xyl_y_range_min > value->xyl_y_range_max) { + BT_ERR("Light xyL Range Set range min is greater than range max"); + return -EINVAL; + } + length = BLE_MESH_LIGHT_XYL_RANGE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK: + length = BLE_MESH_LIGHT_LC_MODE_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK: + length = BLE_MESH_LIGHT_LC_OM_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK: { + struct bt_mesh_light_lc_light_onoff_set *value; + value = (struct bt_mesh_light_lc_light_onoff_set *)set; + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Light LC Light OnOff Set transition time"); + return -EINVAL; + } + } + length = BLE_MESH_LIGHT_LC_LIGHT_ONOFF_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK: { + struct bt_mesh_light_lc_property_set *value; + value = (struct bt_mesh_light_lc_property_set *)set; + if (!value->light_lc_property_value) { + BT_ERR("Invalid Lighting Light LC Property value"); + return -EINVAL; + } + length = (1 + 2 + value->light_lc_property_value->len + 4); + break; + } + default: + BT_ERR("Invalid Lighting Set opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return light_set_state(common, set, length, need_ack); +} + +static int lighting_client_init(struct bt_mesh_model *model) +{ + light_internal_data_t *internal = NULL; + bt_mesh_light_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Lighting client model"); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)model->user_data; + if (!client) { + BT_ERR("No Lighting client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(light_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(light_op_pair); + client->op_pair = light_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&lighting_client_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +static int lighting_client_deinit(struct bt_mesh_model *model) +{ + bt_mesh_light_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Lighting client model"); + return -EINVAL; + } + + client = (bt_mesh_light_client_t *)model->user_data; + if (!client) { + BT_ERR("No Lighting client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&lighting_client_lock); + + return 0; +} +#endif /* CONFIG_BLE_MESH_DEINIT */ + +const struct bt_mesh_model_cb bt_mesh_lighting_client_cb = { + .init = lighting_client_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = lighting_client_deinit, +#endif /* CONFIG_BLE_MESH_DEINIT */ +}; + +#endif /* CONFIG_BLE_MESH_LIGHTING_CLIENT */ diff --git a/lib/bt/esp_ble_mesh/models/client/sensor_client.c b/lib/bt/esp_ble_mesh/models/client/sensor_client.c new file mode 100644 index 00000000..fa093ff6 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/sensor_client.c @@ -0,0 +1,625 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> +#include <errno.h> + +#include "btc_ble_mesh_sensor_model.h" + +#include "mesh/config.h" +#include "mesh/model_opcode.h" + +#if CONFIG_BLE_MESH_SENSOR_CLI +#include "mesh/sensor_client.h" + +/* The followings are the macro definitions of Sensor client + * model message length, and a message is composed of 3 parts: + * Opcode + Payload + MIC + */ +/* Sensor client messages length */ +#define BLE_MESH_SENSOR_DESCRIPTOR_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_CADENCE_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_CADENCE_SET_MSG_LEN /* variable */ +#define BLE_MESH_SENSOR_SETTINGS_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_SETTING_GET_MSG_LEN (2 + 4 + 4) +#define BLE_MESH_SENSOR_SETTING_SET_MSG_LEN /* variable */ +#define BLE_MESH_SENSOR_GET_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SENSOR_COLUMN_GET_MSG_LEN /* variable */ +#define BLE_MESH_SENSOR_SERIES_GET_MSG_LEN /* variable */ + +static const bt_mesh_client_op_pair_t sensor_op_pair[] = { + { BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET, BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET, BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET, BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET, BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SETTING_GET, BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SETTING_SET, BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_GET, BLE_MESH_MODEL_OP_SENSOR_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET, BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS }, + { BLE_MESH_MODEL_OP_SENSOR_SERIES_GET, BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS }, +}; + +static bt_mesh_mutex_t sensor_client_lock; + +static void timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + uint32_t opcode = 0U; + + BT_WARN("Receive sensor status message timeout"); + + bt_mesh_mutex_lock(&sensor_client_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (node) { + memcpy(&ctx, &node->ctx, sizeof(ctx)); + opcode = node->opcode; + model = node->model; + bt_mesh_client_free_node(node); + bt_mesh_sensor_client_cb_evt_to_btc( + opcode, BTC_BLE_MESH_EVT_SENSOR_CLIENT_TIMEOUT, model, &ctx, NULL, 0); + } + } + + bt_mesh_mutex_unlock(&sensor_client_lock); +} + +static void sensor_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + bt_mesh_client_node_t *node = NULL; + uint8_t *val = NULL; + uint8_t evt = 0xFF; + size_t len = 0U; + + BT_DBG("len %d, bytes %s", buf->len, bt_hex(buf->data, buf->len)); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { + struct bt_mesh_sensor_descriptor_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_descriptor_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->descriptor = bt_mesh_alloc_buf(buf->len); + if (!status->descriptor) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->descriptor, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_descriptor_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS: { + struct bt_mesh_sensor_cadence_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_cadence_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->property_id = net_buf_simple_pull_le16(buf); + status->sensor_cadence_value = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_cadence_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_cadence_value, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_cadence_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS: { + struct bt_mesh_sensor_settings_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_settings_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->sensor_property_id = net_buf_simple_pull_le16(buf); + status->sensor_setting_property_ids = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_setting_property_ids) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_setting_property_ids, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_settings_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS: { + struct bt_mesh_sensor_setting_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_setting_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->sensor_property_id = net_buf_simple_pull_le16(buf); + status->sensor_setting_property_id = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->sensor_setting_access = net_buf_simple_pull_u8(buf); + status->sensor_setting_raw = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_setting_raw) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_setting_raw, buf->data, buf->len); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_setting_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_STATUS: { + struct bt_mesh_sensor_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->marshalled_sensor_data = bt_mesh_alloc_buf(buf->len); + if (!status->marshalled_sensor_data) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->marshalled_sensor_data, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS: { + struct bt_mesh_sensor_column_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_column_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->property_id = net_buf_simple_pull_le16(buf); + status->sensor_column_value = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_column_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_column_value, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_column_status); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS: { + struct bt_mesh_sensor_series_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_sensor_series_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->property_id = net_buf_simple_pull_le16(buf); + status->sensor_series_value = bt_mesh_alloc_buf(buf->len); + if (!status->sensor_series_value) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->sensor_series_value, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_sensor_series_status); + break; + } + default: + BT_ERR("Invalid Sensor Status opcode 0x%04x", ctx->recv_op); + return; + } + + buf->data = val; + buf->len = len; + + bt_mesh_mutex_lock(&sensor_client_lock); + + node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected Sensor Status 0x%04x", ctx->recv_op); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: + case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: + case BLE_MESH_MODEL_OP_SENSOR_GET: + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: + case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: + evt = BTC_BLE_MESH_EVT_SENSOR_CLIENT_GET_STATE; + break; + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + evt = BTC_BLE_MESH_EVT_SENSOR_CLIENT_SET_STATE; + break; + default: + break; + } + + if (!k_delayed_work_free(&node->timer)) { + uint32_t opcode = node->opcode; + bt_mesh_client_free_node(node); + bt_mesh_sensor_client_cb_evt_to_btc(opcode, evt, model, ctx, val, len); + } + } + + bt_mesh_mutex_unlock(&sensor_client_lock); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS: { + struct bt_mesh_sensor_descriptor_status *status; + status = (struct bt_mesh_sensor_descriptor_status *)val; + bt_mesh_free_buf(status->descriptor); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS: { + struct bt_mesh_sensor_cadence_status *status; + status = (struct bt_mesh_sensor_cadence_status *)val; + bt_mesh_free_buf(status->sensor_cadence_value); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS: { + struct bt_mesh_sensor_settings_status *status; + status = (struct bt_mesh_sensor_settings_status *)val; + bt_mesh_free_buf(status->sensor_setting_property_ids); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS: { + struct bt_mesh_sensor_setting_status *status; + status = (struct bt_mesh_sensor_setting_status *)val; + bt_mesh_free_buf(status->sensor_setting_raw); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_STATUS: { + struct bt_mesh_sensor_status *status; + status = (struct bt_mesh_sensor_status *)val; + bt_mesh_free_buf(status->marshalled_sensor_data); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS: { + struct bt_mesh_sensor_column_status *status; + status = (struct bt_mesh_sensor_column_status *)val; + bt_mesh_free_buf(status->sensor_column_value); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS: { + struct bt_mesh_sensor_series_status *status; + status = (struct bt_mesh_sensor_series_status *)val; + bt_mesh_free_buf(status->sensor_series_value); + break; + } + default: + break; + } + + bt_mesh_free(val); +} + +const struct bt_mesh_model_op bt_mesh_sensor_cli_op[] = { + { BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS, 0, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS, 2, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS, 2, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS, 4, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_STATUS, 0, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS, 2, sensor_status }, + { BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS, 2, sensor_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int sensor_act_state(bt_mesh_client_common_param_t *common, + void *value, uint16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err = 0; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: { + struct bt_mesh_sensor_descriptor_get *act; + act = (struct bt_mesh_sensor_descriptor_get *)value; + if (act->op_en) { + net_buf_simple_add_le16(msg, act->property_id); + } + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: { + struct bt_mesh_sensor_cadence_get *act; + act = (struct bt_mesh_sensor_cadence_get *)value; + net_buf_simple_add_le16(msg, act->property_id); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK: { + struct bt_mesh_sensor_cadence_set *act; + act = (struct bt_mesh_sensor_cadence_set *)value; + net_buf_simple_add_le16(msg, act->property_id); + net_buf_simple_add_u8(msg, act->status_trigger_type << 7 | act->fast_cadence_period_divisor); + net_buf_simple_add_mem(msg, act->status_trigger_delta_down->data, act->status_trigger_delta_down->len); + net_buf_simple_add_mem(msg, act->status_trigger_delta_up->data, act->status_trigger_delta_up->len); + net_buf_simple_add_u8(msg, act->status_min_interval); + net_buf_simple_add_mem(msg, act->fast_cadence_low->data, act->fast_cadence_low->len); + net_buf_simple_add_mem(msg, act->fast_cadence_high->data, act->fast_cadence_high->len); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: { + struct bt_mesh_sensor_settings_get *act; + act = (struct bt_mesh_sensor_settings_get *)value; + net_buf_simple_add_le16(msg, act->sensor_property_id); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: { + struct bt_mesh_sensor_setting_get *act; + act = (struct bt_mesh_sensor_setting_get *)value; + net_buf_simple_add_le16(msg, act->sensor_property_id); + net_buf_simple_add_le16(msg, act->sensor_setting_property_id); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK: { + struct bt_mesh_sensor_setting_set *act; + act = (struct bt_mesh_sensor_setting_set *)value; + net_buf_simple_add_le16(msg, act->sensor_property_id); + net_buf_simple_add_le16(msg, act->sensor_setting_property_id); + net_buf_simple_add_mem(msg, act->sensor_setting_raw->data, act->sensor_setting_raw->len); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_GET: { + struct bt_mesh_sensor_get *act; + act = (struct bt_mesh_sensor_get *)value; + if (act->op_en) { + net_buf_simple_add_le16(msg, act->property_id); + } + break; + } + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: { + struct bt_mesh_sensor_column_get *act; + act = (struct bt_mesh_sensor_column_get *)value; + net_buf_simple_add_le16(msg, act->property_id); + net_buf_simple_add_mem(msg, act->raw_value_x->data, act->raw_value_x->len); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: { + struct bt_mesh_sensor_series_get *act; + act = (struct bt_mesh_sensor_series_get *)value; + net_buf_simple_add_le16(msg, act->property_id); + if (act->op_en) { + net_buf_simple_add_mem(msg, act->raw_value_x1->data, act->raw_value_x1->len); + net_buf_simple_add_mem(msg, act->raw_value_x2->data, act->raw_value_x2->len); + } + break; + } + default: + BT_ERR("Invalid Sensor client opcode 0x%04x", common->opcode); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common, msg, need_ack, timeout_handler); + +end: + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_sensor_client_get_state(bt_mesh_client_common_param_t *common, void *get) +{ + bt_mesh_sensor_client_t *client = NULL; + uint16_t length = 0U; + + if (!common || !common->model || !get) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Sensor client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET: + length = BLE_MESH_SENSOR_DESCRIPTOR_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET: + length = BLE_MESH_SENSOR_CADENCE_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET: + length = BLE_MESH_SENSOR_SETTINGS_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: + length = BLE_MESH_SENSOR_SETTING_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_GET: + length = BLE_MESH_SENSOR_GET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET: { + struct bt_mesh_sensor_column_get *value; + value = (struct bt_mesh_sensor_column_get *)get; + if (!value->raw_value_x) { + BT_ERR("Invalid Sensor Column Get"); + return -EINVAL; + } + length = (2 + 2 + value->raw_value_x->len + 4); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: { + struct bt_mesh_sensor_series_get *value; + value = (struct bt_mesh_sensor_series_get *)get; + if (value->op_en) { + if (!value->raw_value_x1 || !value->raw_value_x2) { + BT_ERR("Invalid Sensor Series Get"); + return -EINVAL; + } + } + if (value->op_en) { + length = value->raw_value_x1->len + value->raw_value_x2->len; + } + length += (2 + 2 + 4); + break; + } + default: + BT_ERR("Invalid Sensor Get opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return sensor_act_state(common, get, length, true); +} + +int bt_mesh_sensor_client_set_state(bt_mesh_client_common_param_t *common, void *set) +{ + bt_mesh_sensor_client_t *client = NULL; + uint16_t length = 0U; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Sensor client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK: { + struct bt_mesh_sensor_cadence_set *value; + value = (struct bt_mesh_sensor_cadence_set *)set; + if (!value->status_trigger_delta_down || !value->status_trigger_delta_up || + !value->fast_cadence_low || !value->fast_cadence_high) { + BT_ERR("Invalid Sensor Cadence Set"); + return -EINVAL; + } + length = value->status_trigger_delta_down->len + \ + value->status_trigger_delta_up->len + \ + value->fast_cadence_low->len + \ + value->fast_cadence_high->len; + length += (1 + 2 + 1 + 1 + 4); + break; + } + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK: { + struct bt_mesh_sensor_setting_set *value; + value = (struct bt_mesh_sensor_setting_set *)set; + if (!value->sensor_setting_raw) { + BT_ERR("Invalid Sensor Setting Raw value"); + return -EINVAL; + } + length = (1 + 2 + 2 + value->sensor_setting_raw->len + 4); + break; + } + default: + BT_ERR("Invalid Sensor Set opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return sensor_act_state(common, set, length, need_ack); +} + +static int sensor_client_init(struct bt_mesh_model *model) +{ + sensor_internal_data_t *internal = NULL; + bt_mesh_sensor_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Sensor client model"); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)model->user_data; + if (!client) { + BT_ERR("No Sensor client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(sensor_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(sensor_op_pair); + client->op_pair = sensor_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&sensor_client_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +static int sensor_client_deinit(struct bt_mesh_model *model) +{ + bt_mesh_sensor_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Sensor client model"); + return -EINVAL; + } + + client = (bt_mesh_sensor_client_t *)model->user_data; + if (!client) { + BT_ERR("No Sensor client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&sensor_client_lock); + + return 0; +} +#endif /* CONFIG_BLE_MESH_DEINIT */ + +const struct bt_mesh_model_cb bt_mesh_sensor_client_cb = { + .init = sensor_client_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = sensor_client_deinit, +#endif /* CONFIG_BLE_MESH_DEINIT */ +}; + +#endif /* CONFIG_BLE_MESH_SENSOR_CLI */ diff --git a/lib/bt/esp_ble_mesh/models/client/time_scene_client.c b/lib/bt/esp_ble_mesh/models/client/time_scene_client.c new file mode 100644 index 00000000..8cdc4800 --- /dev/null +++ b/lib/bt/esp_ble_mesh/models/client/time_scene_client.c @@ -0,0 +1,681 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> +#include <errno.h> + +#include "btc_ble_mesh_time_scene_model.h" + +#include "mesh/config.h" +#include "mesh/model_opcode.h" + +#if CONFIG_BLE_MESH_TIME_SCENE_CLIENT +#include "mesh/time_scene_client.h" + +/* The followings are the macro definitions of Time Scene client + * model message length, and a message is composed of 3 parts: + * Opcode + Payload + MIC + */ +/* Time client messages length */ +#define BLE_MESH_TIME_SET_MSG_LEN (1 + 10 + 4) +#define BLE_MESH_TIME_ZONE_SET_MSG_LEN (2 + 6 + 4) +#define BLE_MESH_TAI_UTC_DELTA_SET_MSG_LEN (2 + 7 + 4) +#define BLE_MESH_TIME_ROLE_SET_MSG_LEN (2 + 1 + 4) + +/* Scene client messages length */ +#define BLE_MESH_SCENE_STORE_MSG_LEN (2 + 2 + 4) +#define BLE_MESH_SCENE_RECALL_MSG_LEN (2 + 5 + 4) +#define BLE_MESH_SCENE_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_SCENE_REGISTER_GET_MSG_LEN (2 + 0 + 4) +#define BLE_MESH_SCENE_DELETE_MSG_LEN (2 + 2 + 4) + +/* Scheduler client messages length */ +#define BLE_MESH_SCHEDULER_ACT_GET_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_SCHEDULER_ACT_SET_MSG_LEN (1 + 10 + 4) + +#define BLE_MESH_SCENE_GET_STATE_MSG_LEN (2 + 1 + 4) +#define BLE_MESH_SCENE_ACT_STATE_MSG_LEN (2 + 2 + 4) + +static const bt_mesh_client_op_pair_t time_scene_op_pair[] = { + { BLE_MESH_MODEL_OP_TIME_GET, BLE_MESH_MODEL_OP_TIME_STATUS }, + { BLE_MESH_MODEL_OP_TIME_SET, BLE_MESH_MODEL_OP_TIME_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ZONE_GET, BLE_MESH_MODEL_OP_TIME_ZONE_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ZONE_SET, BLE_MESH_MODEL_OP_TIME_ZONE_STATUS }, + { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET, BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS }, + { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET, BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ROLE_GET, BLE_MESH_MODEL_OP_TIME_ROLE_STATUS }, + { BLE_MESH_MODEL_OP_TIME_ROLE_SET, BLE_MESH_MODEL_OP_TIME_ROLE_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_STORE, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_RECALL, BLE_MESH_MODEL_OP_SCENE_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_GET, BLE_MESH_MODEL_OP_SCENE_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_REGISTER_GET, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS }, + { BLE_MESH_MODEL_OP_SCENE_DELETE, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS }, + { BLE_MESH_MODEL_OP_SCHEDULER_GET, BLE_MESH_MODEL_OP_SCHEDULER_STATUS }, + { BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET, BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS }, + { BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET, BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS }, +}; + +static bt_mesh_mutex_t time_scene_client_lock; + +static void timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_client_node_t *node = NULL; + struct bt_mesh_model *model = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + uint32_t opcode = 0U; + + BT_WARN("Receive time scene status message timeout"); + + bt_mesh_mutex_lock(&time_scene_client_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (node) { + memcpy(&ctx, &node->ctx, sizeof(ctx)); + opcode = node->opcode; + model = node->model; + bt_mesh_client_free_node(node); + bt_mesh_time_scene_client_cb_evt_to_btc( + opcode, BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_TIMEOUT, model, &ctx, NULL, 0); + } + } + + bt_mesh_mutex_unlock(&time_scene_client_lock); +} + +static void time_scene_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + bt_mesh_client_node_t *node = NULL; + uint8_t *val = NULL; + uint8_t evt = 0xFF; + size_t len = 0U; + + BT_DBG("len %d, bytes %s", buf->len, bt_hex(buf->data, buf->len)); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_TIME_STATUS: { + struct bt_mesh_time_status *status = NULL; + if (buf->len != 5 && buf->len != 10) { + BT_ERR("Invalid Time Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_time_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + memcpy(status->tai_seconds, buf->data, 5); + net_buf_simple_pull(buf, 5); + status->sub_second = net_buf_simple_pull_u8(buf); + status->uncertainty = net_buf_simple_pull_u8(buf); + uint16_t temp = net_buf_simple_pull_le16(buf); + status->time_authority = temp & BIT(0); + status->tai_utc_delta = temp >> 15; + status->time_zone_offset = net_buf_simple_pull_u8(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_time_status); + break; + } + case BLE_MESH_MODEL_OP_TIME_ZONE_STATUS: { + struct bt_mesh_time_zone_status *status = NULL; + if (buf->len != 7) { + BT_ERR("Invalid Time Zone Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_time_zone_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->time_zone_offset_curr = net_buf_simple_pull_u8(buf); + status->time_zone_offset_new = net_buf_simple_pull_u8(buf); + memcpy(status->tai_zone_change, buf->data, 5); + net_buf_simple_pull(buf, 5); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_time_zone_status); + break; + } + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS: { + struct bt_mesh_tai_utc_delta_status *status = NULL; + if (buf->len != 9) { + BT_ERR("Invalid TAI UTC Delta Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_tai_utc_delta_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + uint16_t temp = net_buf_simple_pull_le16(buf); + status->tai_utc_delta_curr = temp & BIT_MASK(15); + status->padding_1 = (temp >> 15) & BIT(0); + temp = net_buf_simple_pull_le16(buf); + status->tai_utc_delta_new = temp & BIT_MASK(15); + status->padding_2 = (temp >> 15) & BIT(0); + memcpy(status->tai_delta_change, buf->data, 5); + net_buf_simple_pull(buf, 5); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_tai_utc_delta_status); + break; + } + case BLE_MESH_MODEL_OP_TIME_ROLE_STATUS: { + struct bt_mesh_time_role_status *status = NULL; + if (buf->len != 1) { + BT_ERR("Invalid Time Role Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_time_role_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->time_role = net_buf_simple_pull_u8(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_time_role_status); + break; + } + case BLE_MESH_MODEL_OP_SCENE_STATUS: { + struct bt_mesh_scene_status *status = NULL; + if (buf->len != 3 && buf->len != 6) { + BT_ERR("Invalid Scene Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_scene_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->current_scene = net_buf_simple_pull_le16(buf); + if (buf->len) { + status->op_en = true; + status->target_scene = net_buf_simple_pull_le16(buf); + status->remain_time = net_buf_simple_pull_u8(buf); + } + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_scene_status); + break; + } + case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: { + struct bt_mesh_scene_register_status *status = NULL; + status = bt_mesh_calloc(sizeof(struct bt_mesh_scene_register_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->status_code = net_buf_simple_pull_u8(buf); + status->current_scene = net_buf_simple_pull_le16(buf); + status->scenes = bt_mesh_alloc_buf(buf->len); + if (!status->scenes) { + BT_ERR("%s, Out of memory", __func__); + bt_mesh_free(status); + return; + } + net_buf_simple_add_mem(status->scenes, buf->data, buf->len); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_scene_register_status); + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_STATUS: { + struct bt_mesh_scheduler_status *status = NULL; + if (buf->len != 2) { + BT_ERR("Invalid Scheduler Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_scheduler_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + status->schedules = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_scheduler_status); + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS: { + struct bt_mesh_scheduler_act_status *status = NULL; + if (buf->len != 10) { + BT_ERR("Invalid Scheduler Action Status length %d", buf->len); + return; + } + status = bt_mesh_calloc(sizeof(struct bt_mesh_scheduler_act_status)); + if (!status) { + BT_ERR("%s, Out of memory", __func__); + return; + } + memcpy(status, buf->data, offsetof(struct bt_mesh_scheduler_act_status, scene_number)); + net_buf_simple_pull(buf, offsetof(struct bt_mesh_scheduler_act_status, scene_number)); + status->scene_number = net_buf_simple_pull_le16(buf); + val = (uint8_t *)status; + len = sizeof(struct bt_mesh_scheduler_act_status); + break; + } + default: + BT_ERR("Invalid Time Scene Status opcode 0x%04x", ctx->recv_op); + return; + } + + buf->data = val; + buf->len = len; + + bt_mesh_mutex_lock(&time_scene_client_lock); + + node = bt_mesh_is_client_recv_publish_msg(model, ctx, buf, true); + if (!node) { + BT_DBG("Unexpected Time Scene Status 0x%04x", ctx->recv_op); + } else { + switch (node->opcode) { + case BLE_MESH_MODEL_OP_TIME_GET: + case BLE_MESH_MODEL_OP_TIME_ZONE_GET: + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET: + case BLE_MESH_MODEL_OP_TIME_ROLE_GET: + case BLE_MESH_MODEL_OP_SCENE_GET: + case BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: + case BLE_MESH_MODEL_OP_SCHEDULER_GET: + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: + evt = BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_GET_STATE; + break; + case BLE_MESH_MODEL_OP_TIME_SET: + case BLE_MESH_MODEL_OP_TIME_ZONE_SET: + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: + case BLE_MESH_MODEL_OP_TIME_ROLE_SET: + case BLE_MESH_MODEL_OP_SCENE_STORE: + case BLE_MESH_MODEL_OP_SCENE_RECALL: + case BLE_MESH_MODEL_OP_SCENE_DELETE: + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET: + evt = BTC_BLE_MESH_EVT_TIME_SCENE_CLIENT_SET_STATE; + break; + default: + break; + } + + if (!k_delayed_work_free(&node->timer)) { + uint32_t opcode = node->opcode; + bt_mesh_client_free_node(node); + bt_mesh_time_scene_client_cb_evt_to_btc(opcode, evt, model, ctx, val, len); + } + } + + bt_mesh_mutex_unlock(&time_scene_client_lock); + + switch (ctx->recv_op) { + case BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS: { + struct bt_mesh_scene_register_status *status; + status = (struct bt_mesh_scene_register_status *)val; + bt_mesh_free_buf(status->scenes); + break; + } + default: + break; + } + + bt_mesh_free(val); +} + +const struct bt_mesh_model_op bt_mesh_time_cli_op[] = { + { BLE_MESH_MODEL_OP_TIME_STATUS, 5, time_scene_status }, + { BLE_MESH_MODEL_OP_TIME_ZONE_STATUS, 7, time_scene_status }, + { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS, 9, time_scene_status }, + { BLE_MESH_MODEL_OP_TIME_ROLE_STATUS, 1, time_scene_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_scene_cli_op[] = { + { BLE_MESH_MODEL_OP_SCENE_STATUS, 3, time_scene_status }, + { BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS, 3, time_scene_status }, + BLE_MESH_MODEL_OP_END, +}; + +const struct bt_mesh_model_op bt_mesh_scheduler_cli_op[] = { + { BLE_MESH_MODEL_OP_SCHEDULER_STATUS, 2, time_scene_status }, + { BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS, 10, time_scene_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int time_scene_get_state(bt_mesh_client_common_param_t *common, void *value) +{ + NET_BUF_SIMPLE_DEFINE(msg, BLE_MESH_SCENE_GET_STATE_MSG_LEN); + + bt_mesh_model_msg_init(&msg, common->opcode); + + if (value) { + switch (common->opcode) { + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: { + struct bt_mesh_scheduler_act_get *get; + get = (struct bt_mesh_scheduler_act_get *)value; + net_buf_simple_add_u8(&msg, get->index); + break; + } + default: + BT_DBG("No parameters for Time Scene Get 0x%04x", common->opcode); + break; + } + } + + return bt_mesh_client_send_msg(common, &msg, true, timeout_handler); +} + +static int time_scene_set_state(bt_mesh_client_common_param_t *common, + void *value, uint16_t value_len, bool need_ack) +{ + struct net_buf_simple *msg = NULL; + int err = 0; + + msg = bt_mesh_alloc_buf(value_len); + if (!msg) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + bt_mesh_model_msg_init(msg, common->opcode); + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_TIME_SET: { + struct bt_mesh_time_set *set; + set = (struct bt_mesh_time_set *)value; + net_buf_simple_add_mem(msg, set->tai_seconds, 5); + net_buf_simple_add_u8(msg, set->sub_second); + net_buf_simple_add_u8(msg, set->uncertainty); + net_buf_simple_add_le16(msg, set->tai_utc_delta << 1 | set->time_authority); + net_buf_simple_add_u8(msg, set->time_zone_offset); + break; + } + case BLE_MESH_MODEL_OP_TIME_ZONE_SET: { + struct bt_mesh_time_zone_set *set; + set = (struct bt_mesh_time_zone_set *)value; + net_buf_simple_add_u8(msg, set->time_zone_offset_new); + net_buf_simple_add_mem(msg, set->tai_zone_change, 5); + break; + } + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: { + struct bt_mesh_tai_utc_delta_set *set; + set = (struct bt_mesh_tai_utc_delta_set *)value; + net_buf_simple_add_le16(msg, set->padding << 15 | set->tai_utc_delta_new); + net_buf_simple_add_mem(msg, set->tai_delta_change, 5); + break; + } + case BLE_MESH_MODEL_OP_TIME_ROLE_SET: { + struct bt_mesh_time_role_set *set; + set = (struct bt_mesh_time_role_set *)value; + net_buf_simple_add_u8(msg, set->time_role); + break; + } + case BLE_MESH_MODEL_OP_SCENE_STORE: + case BLE_MESH_MODEL_OP_SCENE_STORE_UNACK: { + struct bt_mesh_scene_store *set; + set = (struct bt_mesh_scene_store *)value; + net_buf_simple_add_le16(msg, set->scene_number); + break; + } + case BLE_MESH_MODEL_OP_SCENE_RECALL: + case BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK: { + struct bt_mesh_scene_recall *set; + set = (struct bt_mesh_scene_recall *)value; + net_buf_simple_add_le16(msg, set->scene_number); + net_buf_simple_add_u8(msg, set->tid); + if (set->op_en) { + net_buf_simple_add_u8(msg, set->trans_time); + net_buf_simple_add_u8(msg, set->delay); + } + break; + } + case BLE_MESH_MODEL_OP_SCENE_DELETE: + case BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK: { + struct bt_mesh_scene_delete *set; + set = (struct bt_mesh_scene_delete *)value; + net_buf_simple_add_le16(msg, set->scene_number); + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET: + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK: { + struct bt_mesh_scheduler_act_set *set; + set = (struct bt_mesh_scheduler_act_set *)value; + net_buf_simple_add_mem(msg, set, offsetof(struct bt_mesh_scheduler_act_set, scene_number)); + net_buf_simple_add_le16(msg, set->scene_number); + break; + } + default: + BT_ERR("Invalid Time Scene Set opcode 0x%04x", common->opcode); + err = -EINVAL; + goto end; + } + + err = bt_mesh_client_send_msg(common, msg, need_ack, timeout_handler); + +end: + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_time_scene_client_get_state(bt_mesh_client_common_param_t *common, void *get) +{ + bt_mesh_time_scene_client_t *client = NULL; + + if (!common || !common->model) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Time Scene client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_TIME_GET: + case BLE_MESH_MODEL_OP_TIME_ZONE_GET: + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET: + case BLE_MESH_MODEL_OP_TIME_ROLE_GET: + case BLE_MESH_MODEL_OP_SCENE_GET: + case BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: + case BLE_MESH_MODEL_OP_SCHEDULER_GET: + break; + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: + if (!get) { + BT_ERR("Invalid Scheduler Action Get"); + return -EINVAL; + } + break; + default: + BT_ERR("Invalid Time Scene Get opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return time_scene_get_state(common, get); +} + +int bt_mesh_time_scene_client_set_state(bt_mesh_client_common_param_t *common, void *set) +{ + bt_mesh_time_scene_client_t *client = NULL; + uint16_t length = 0U; + bool need_ack = false; + + if (!common || !common->model || !set) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)common->model->user_data; + if (!client || !client->internal_data) { + BT_ERR("Invalid Time Scene client data"); + return -EINVAL; + } + + switch (common->opcode) { + case BLE_MESH_MODEL_OP_TIME_SET: + need_ack = true; + length = BLE_MESH_TIME_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_TIME_ZONE_SET: + need_ack = true; + length = BLE_MESH_TIME_ZONE_SET_MSG_LEN; + break; + case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: { + struct bt_mesh_tai_utc_delta_set *value; + value = (struct bt_mesh_tai_utc_delta_set *)set; + if (value->padding) { + BT_ERR("Non-zero padding value is prohibited"); + return -EINVAL; + } + need_ack = true; + length = BLE_MESH_TAI_UTC_DELTA_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_TIME_ROLE_SET: { + struct bt_mesh_time_role_set *value; + value = (struct bt_mesh_time_role_set *)set; + if (value->time_role > 0x03) { + BT_ERR("Time role 0x%02x is prohibited", value->time_role); + return -EINVAL; + } + need_ack = true; + length = BLE_MESH_TIME_ROLE_SET_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCENE_STORE: + need_ack = true; + case BLE_MESH_MODEL_OP_SCENE_STORE_UNACK: { + struct bt_mesh_scene_store *value; + value = (struct bt_mesh_scene_store *)set; + if (!value->scene_number) { + BT_ERR("Scene Store scene number 0x0000 is prohibited"); + return -EINVAL; + } + length = BLE_MESH_SCENE_STORE_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCENE_RECALL: + need_ack = true; + case BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK: { + struct bt_mesh_scene_recall *value; + value = (struct bt_mesh_scene_recall *)set; + if (!value->scene_number) { + BT_ERR("Scene Recall scene number 0x0000 is prohibited"); + return -EINVAL; + } + if (value->op_en) { + if ((value->trans_time & 0x3F) > 0x3E) { + BT_ERR("Invalid Scene Recall transition time"); + return -EINVAL; + } + } + length = BLE_MESH_SCENE_RECALL_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCENE_DELETE: + need_ack = true; + case BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK: { + length = BLE_MESH_SCENE_DELETE_MSG_LEN; + break; + } + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET: + need_ack = true; + case BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK: { + struct bt_mesh_scheduler_act_set *value; + value = (struct bt_mesh_scheduler_act_set *)set; + if (value->year > 0x64) { + BT_ERR("Scheduler Register year 0x%02x is prohibited", value->year); + return -EINVAL; + } + if (value->hour > 0x19) { + BT_ERR("Scheduler Register hour 0x%02x is prohibited", value->hour); + return -EINVAL; + } + length = BLE_MESH_SCHEDULER_ACT_SET_MSG_LEN; + break; + } + default: + BT_ERR("Invalid Time Scene Set opcode 0x%04x", common->opcode); + return -EINVAL; + } + + return time_scene_set_state(common, set, length, need_ack); +} + +static int time_scene_client_init(struct bt_mesh_model *model) +{ + time_scene_internal_data_t *internal = NULL; + bt_mesh_time_scene_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Time Scene client model"); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)model->user_data; + if (!client) { + BT_ERR("No Time Scene client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(time_scene_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(time_scene_op_pair); + client->op_pair = time_scene_op_pair; + client->internal_data = internal; + + bt_mesh_mutex_create(&time_scene_client_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +static int time_scene_client_deinit(struct bt_mesh_model *model) +{ + bt_mesh_time_scene_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Time Scene client model"); + return -EINVAL; + } + + client = (bt_mesh_time_scene_client_t *)model->user_data; + if (!client) { + BT_ERR("No Time Scene client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&time_scene_client_lock); + + return 0; +} +#endif /* CONFIG_BLE_MESH_DEINIT */ + +const struct bt_mesh_model_cb bt_mesh_time_scene_client_cb = { + .init = time_scene_client_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = time_scene_client_deinit, +#endif /* CONFIG_BLE_MESH_DEINIT */ +}; + +#endif /* CONFIG_BLE_MESH_TIME_SCENE_CLIENT */ |
