#include "system/includes.h" #include "bt_common.h" #include "api/sig_mesh_api.h" #include "api/gen_lvl_srv.h" #include "api/gen_lvl.h" #include "model_api.h" #include "model_types.h" #include "model_utils.h" #define LOG_TAG "[Gen_Level]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE /* #define LOG_DUMP_ENABLE */ #define LOG_CLI_ENABLE #include "debug.h" #if (CONFIG_BT_MESH_GEN_LEVEL_SRV) struct level_state { s16 level; u8_t led_gpio_pin; }; struct level_state light_level_state = { .level = -32768, .led_gpio_pin = IO_PORTB_07, }; static void encode_status(const struct bt_mesh_lvl_status *status, struct net_buf_simple *buf) { bt_mesh_model_msg_init(buf, BT_MESH_LVL_OP_STATUS); net_buf_simple_add_le16(buf, status->current); if (status->remaining_time == 0) { return; } net_buf_simple_add_le16(buf, status->target); net_buf_simple_add_u8(buf, model_transition_encode(status->remaining_time)); } static void rsp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const struct bt_mesh_lvl_status *status) { BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_LVL_OP_STATUS, BT_MESH_LVL_MSG_MAXLEN_STATUS); encode_status(status, &rsp); bt_mesh_model_send(model, ctx, &rsp, NULL, 0); } static int handle_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; log_debug(">>> %s", __func__); #if (CONFIG_MESH_MODEL == SIG_MESH_BASIC_LIGHTNESS_CTRL_NLC) srv->handlers->get(srv, ctx, &status); #endif rsp_status(model, ctx, &status); return 0; } static int set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, bool ack) { if (buf->len != BT_MESH_LVL_MSG_MINLEN_SET && buf->len != BT_MESH_LVL_MSG_MAXLEN_SET) { return -EMSGSIZE; } struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_model_transition transition; struct bt_mesh_lvl_status status = { 0 }; struct bt_mesh_lvl_set set; set.lvl = net_buf_simple_pull_le16(buf); set.new_transaction = !tid_check_and_update( &srv->tid, net_buf_simple_pull_u8(buf), ctx); set.transition = model_transition_get(srv->model, &transition, buf); log_debug(">>> %s", __func__); #if (CONFIG_MESH_MODEL == SIG_MESH_BASIC_LIGHTNESS_CTRL_NLC) srv->handlers->set(srv, ctx, &set, &status); #endif if (IS_ENABLED(CONFIG_BT_MESH_SCENE_SRV)) { bt_mesh_scene_invalidate(srv->model); } if (ack) { rsp_status(model, ctx, &status); } (void)bt_mesh_lvl_srv_pub(srv, NULL, &status); return 0; } static int delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, bool ack) { if (buf->len != BT_MESH_LVL_MSG_MINLEN_DELTA_SET && buf->len != BT_MESH_LVL_MSG_MAXLEN_DELTA_SET) { return -EMSGSIZE; } struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; struct bt_mesh_lvl_delta_set delta_set; struct bt_mesh_model_transition transition; delta_set.delta = net_buf_simple_pull_le32(buf); delta_set.new_transaction = !tid_check_and_update( &srv->tid, net_buf_simple_pull_u8(buf), ctx); delta_set.transition = model_transition_get(srv->model, &transition, buf); log_debug(">>> %s", __func__); #if (CONFIG_MESH_MODEL == SIG_MESH_BASIC_LIGHTNESS_CTRL_NLC) srv->handlers->delta_set(srv, ctx, &delta_set, &status); #endif if (IS_ENABLED(CONFIG_BT_MESH_SCENE_SRV)) { bt_mesh_scene_invalidate(srv->model); } if (ack) { rsp_status(model, ctx, &status); } (void)bt_mesh_lvl_srv_pub(srv, NULL, &status); return 0; } static int move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, bool ack) { if (buf->len != BT_MESH_LVL_MSG_MINLEN_MOVE_SET && buf->len != BT_MESH_LVL_MSG_MAXLEN_MOVE_SET) { return -EMSGSIZE; } struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; struct bt_mesh_model_transition transition; struct bt_mesh_lvl_move_set move_set; move_set.delta = net_buf_simple_pull_le16(buf); move_set.new_transaction = !tid_check_and_update( &srv->tid, net_buf_simple_pull_u8(buf), ctx); move_set.transition = model_transition_get(srv->model, &transition, buf); /* If transition.time is 0, we shouldn't move. Align these two * parameters to simplify application logic for this case: */ if ((!move_set.transition || move_set.transition->time == 0) || move_set.delta == 0) { move_set.delta = 0; move_set.transition = NULL; } log_debug(">>> %s", __func__); #if (CONFIG_MESH_MODEL == SIG_MESH_BASIC_LIGHTNESS_CTRL_NLC) srv->handlers->move_set(srv, ctx, &move_set, &status); #endif if (IS_ENABLED(CONFIG_BT_MESH_SCENE_SRV)) { bt_mesh_scene_invalidate(srv->model); } if (ack) { rsp_status(model, ctx, &status); } (void)bt_mesh_lvl_srv_pub(srv, ctx, &status); return 0; } /* Message handlers */ static int handle_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return set(model, ctx, buf, true); } static int handle_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return set(model, ctx, buf, false); } static int handle_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return delta_set(model, ctx, buf, true); } static int handle_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return delta_set(model, ctx, buf, false); } static int handle_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return move_set(model, ctx, buf, true); } static int handle_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return move_set(model, ctx, buf, false); } const struct bt_mesh_model_op _bt_mesh_lvl_srv_op[] = { { BT_MESH_LVL_OP_GET, BT_MESH_LEN_EXACT(BT_MESH_LVL_MSG_LEN_GET), handle_get, }, { BT_MESH_LVL_OP_SET, BT_MESH_LEN_MIN(BT_MESH_LVL_MSG_MINLEN_SET), handle_set, }, { BT_MESH_LVL_OP_SET_UNACK, BT_MESH_LEN_MIN(BT_MESH_LVL_MSG_MINLEN_SET), handle_set_unack, }, { BT_MESH_LVL_OP_DELTA_SET, BT_MESH_LEN_MIN(BT_MESH_LVL_MSG_MINLEN_DELTA_SET), handle_delta_set, }, { BT_MESH_LVL_OP_DELTA_SET_UNACK, BT_MESH_LEN_MIN(BT_MESH_LVL_MSG_MINLEN_DELTA_SET), handle_delta_set_unack, }, { BT_MESH_LVL_OP_MOVE_SET, BT_MESH_LEN_MIN(BT_MESH_LVL_MSG_MINLEN_MOVE_SET), handle_move_set, }, { BT_MESH_LVL_OP_MOVE_SET_UNACK, BT_MESH_LEN_MIN(BT_MESH_LVL_MSG_MINLEN_MOVE_SET), handle_move_set_unack, }, BT_MESH_MODEL_OP_END, }; static ssize_t scene_store(struct bt_mesh_model *model, uint8_t data[]) { struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; srv->handlers->get(srv, NULL, &status); sys_put_le16(status.remaining_time ? status.target : status.current, &data[0]); return 2; } static void scene_recall(struct bt_mesh_model *model, const uint8_t data[], size_t len, struct bt_mesh_model_transition *transition) { struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; struct bt_mesh_lvl_set set = { .lvl = sys_get_le16(data), .new_transaction = true, .transition = transition, }; srv->handlers->set(srv, NULL, &set, &status); } static void scene_recall_complete(struct bt_mesh_model *model) { struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; srv->handlers->get(srv, NULL, &status); (void)bt_mesh_lvl_srv_pub(srv, NULL, &status); } // BT_MESH_SCENE_ENTRY_SIG(lvl) = { // .id.sig = BT_MESH_MODEL_ID_GEN_LEVEL_SRV, // .maxlen = 2, // .store = scene_store, // .recall = scene_recall, // .recall_complete = scene_recall_complete, // }; const struct bt_mesh_scene_entry bt_mesh_scene_entry_sig_lvl = { .id.sig = BT_MESH_MODEL_ID_GEN_LEVEL_SRV, .maxlen = 2, .store = scene_store, .recall = scene_recall, }; static int update_handler(struct bt_mesh_model *model) { struct bt_mesh_lvl_srv *srv = model->rt->user_data; struct bt_mesh_lvl_status status = { 0 }; #if (CONFIG_MESH_MODEL == SIG_MESH_BASIC_LIGHTNESS_CTRL_NLC) srv->handlers->get(srv, NULL, &status); #endif encode_status(&status, model->pub->msg); return 0; } static int bt_mesh_lvl_srv_init(struct bt_mesh_model *model) { struct bt_mesh_lvl_srv *srv = model->rt->user_data; srv->model = model; srv->pub.msg = &srv->pub_buf; srv->pub.update = update_handler; net_buf_simple_init_with_data(&srv->pub_buf, srv->pub_data, sizeof(srv->pub_data)); return 0; } static void bt_mesh_lvl_srv_reset(struct bt_mesh_model *model) { net_buf_simple_reset(model->pub->msg); } const struct bt_mesh_model_cb _bt_mesh_lvl_srv_cb = { .init = bt_mesh_lvl_srv_init, .reset = bt_mesh_lvl_srv_reset, }; int bt_mesh_lvl_srv_pub(struct bt_mesh_lvl_srv *srv, struct bt_mesh_msg_ctx *ctx, const struct bt_mesh_lvl_status *status) { if (!srv->pub.addr) { return 0; } BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_LVL_OP_STATUS, BT_MESH_LVL_MSG_MAXLEN_STATUS); encode_status(status, &msg); return bt_mesh_msg_send(srv->model, ctx, &msg); } #endif