summaryrefslogtreecommitdiff
path: root/lib/bt/esp_ble_mesh/models/client
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-03-28 14:32:49 +1100
committerjacqueline <me@jacqueline.id.au>2024-03-28 14:32:49 +1100
commitee29c25b29eaa4fac4e897442634b69ecc8d8125 (patch)
tree8c5f1a140463f20f104316fa3492984e191154e9 /lib/bt/esp_ble_mesh/models/client
parent239e6d89507a24c849385f4bfa93ac4ad58e5de5 (diff)
downloadtangara-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')
-rw-r--r--lib/bt/esp_ble_mesh/models/client/client_common.c492
-rw-r--r--lib/bt/esp_ble_mesh/models/client/generic_client.c1185
-rw-r--r--lib/bt/esp_ble_mesh/models/client/include/mesh/client_common.h119
-rw-r--r--lib/bt/esp_ble_mesh/models/client/include/mesh/generic_client.h408
-rw-r--r--lib/bt/esp_ble_mesh/models/client/include/mesh/lighting_client.h440
-rw-r--r--lib/bt/esp_ble_mesh/models/client/include/mesh/sensor_client.h155
-rw-r--r--lib/bt/esp_ble_mesh/models/client/include/mesh/time_scene_client.h225
-rw-r--r--lib/bt/esp_ble_mesh/models/client/lighting_client.c1375
-rw-r--r--lib/bt/esp_ble_mesh/models/client/sensor_client.c625
-rw-r--r--lib/bt/esp_ble_mesh/models/client/time_scene_client.c681
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, &param->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, &param->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(&param->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, &param->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 */