#include "system/includes.h" #include "bt_common.h" #include "api/sig_mesh_api.h" #include "api/gen_onoff.h" #include "api/gen_onoff_srv.h" #include "api/gen_onoff_internal.h" #include "model_api.h" #include "model_utils.h" #define LOG_TAG "[Gen_onoff_srv]" #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_ONOFF_SRV) static void encode_status(struct net_buf_simple *buf, const struct bt_mesh_onoff_status *status) { bt_mesh_model_msg_init(buf, BT_MESH_ONOFF_OP_STATUS); net_buf_simple_add_u8(buf, !!status->present_on_off); if (status->remaining_time != 0) { net_buf_simple_add_u8(buf, status->target_on_off); 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 *rx_ctx, const struct bt_mesh_onoff_status *status) { BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_ONOFF_OP_STATUS, BT_MESH_ONOFF_MSG_MAXLEN_STATUS); encode_status(&msg, status); (void)bt_mesh_model_send(model, rx_ctx, &msg, NULL, NULL); } static int handle_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_onoff_srv *srv = model->rt->user_data; struct bt_mesh_onoff_status status = { 0 }; srv->handlers->get(srv, ctx, &status); rsp_status(model, ctx, &status); return 0; } static int onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, bool ack) { if (buf->len != BT_MESH_ONOFF_MSG_MINLEN_SET && buf->len != BT_MESH_ONOFF_MSG_MAXLEN_SET) { return -EMSGSIZE; } struct bt_mesh_onoff_srv *srv = model->rt->user_data; struct bt_mesh_onoff_status status = { 0 }; struct bt_mesh_model_transition transition; struct bt_mesh_onoff_set set; uint8_t on_off = net_buf_simple_pull_u8(buf); uint8_t tid = net_buf_simple_pull_u8(buf); if (on_off > 1) { return -EINVAL; } set.on_off = on_off; if (tid_check_and_update(&srv->prev_transaction, tid, ctx) != 0) { /* If this is the same transaction, we don't need to send it * to the app, but we still have to respond with a status. */ srv->handlers->get(srv, NULL, &status); goto respond; } if (buf->len == 2) { model_transition_buf_pull(buf, &transition); set.transition = &transition; } else if (!atomic_test_bit(&srv->flags, GEN_ONOFF_SRV_NO_DTT)) { bt_mesh_dtt_srv_transition_get(srv->model, &transition); set.transition = &transition; } else { set.transition = NULL; } srv->handlers->set(srv, ctx, &set, &status); if (IS_ENABLED(CONFIG_BT_MESH_SCENE_SRV)) { bt_mesh_scene_invalidate(srv->model); } (void)bt_mesh_onoff_srv_pub(srv, NULL, &status); respond: if (ack) { rsp_status(model, ctx, &status); } return 0; } static int handle_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return onoff_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 onoff_set(model, ctx, buf, false); } const struct bt_mesh_model_op _bt_mesh_onoff_srv_op[] = { { BT_MESH_ONOFF_OP_GET, BT_MESH_LEN_EXACT(BT_MESH_ONOFF_MSG_LEN_GET), handle_get, }, { BT_MESH_ONOFF_OP_SET, BT_MESH_LEN_MIN(BT_MESH_ONOFF_MSG_MINLEN_SET), handle_set, }, { BT_MESH_ONOFF_OP_SET_UNACK, BT_MESH_LEN_MIN(BT_MESH_ONOFF_MSG_MINLEN_SET), handle_set_unack, }, BT_MESH_MODEL_OP_END, }; /* .. include_startingpoint_scene_srv_rst_1 */ static ssize_t scene_store(struct bt_mesh_model *model, uint8_t data[]) { struct bt_mesh_onoff_srv *srv = model->rt->user_data; struct bt_mesh_onoff_status status = { 0 }; /* Only store the next stable on_off state: */ srv->handlers->get(srv, NULL, &status); data[0] = status.remaining_time ? status.target_on_off : status.present_on_off; return 1; } 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_onoff_srv *srv = model->rt->user_data; struct bt_mesh_onoff_status status = { 0 }; struct bt_mesh_onoff_set set = { .on_off = data[0], .transition = transition, }; srv->handlers->set(srv, NULL, &set, &status); } static void scene_recall_complete(struct bt_mesh_model *model) { struct bt_mesh_onoff_srv *srv = model->rt->user_data; struct bt_mesh_onoff_status status = { 0 }; srv->handlers->get(srv, NULL, &status); (void)bt_mesh_onoff_srv_pub(srv, NULL, &status); } // BT_MESH_SCENE_ENTRY_SIG(onoff) = { // .id.sig = BT_MESH_MODEL_ID_GEN_ONOFF_SRV, // .maxlen = 1, // .store = scene_store, // .recall = scene_recall, // .recall_complete = scene_recall_complete, // }; const struct bt_mesh_scene_entry bt_mesh_scene_entry_sig_onoff = { .id.sig = BT_MESH_MODEL_ID_GEN_ONOFF_SRV, .maxlen = 1, .store = scene_store, .recall = scene_recall, .recall_complete = scene_recall_complete, }; static int update_handler(struct bt_mesh_model *model) { struct bt_mesh_onoff_srv *srv = model->rt->user_data; struct bt_mesh_onoff_status status = { 0 }; srv->handlers->get(srv, NULL, &status); encode_status(model->pub->msg, &status); return 0; } static int bt_mesh_onoff_srv_init(struct bt_mesh_model *model) { struct bt_mesh_onoff_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_onoff_srv_reset(struct bt_mesh_model *model) { net_buf_simple_reset(model->pub->msg); } const struct bt_mesh_model_cb _bt_mesh_onoff_srv_cb = { .init = bt_mesh_onoff_srv_init, .reset = bt_mesh_onoff_srv_reset, }; int bt_mesh_onoff_srv_pub(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx, const struct bt_mesh_onoff_status *status) { BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_ONOFF_OP_STATUS, BT_MESH_ONOFF_MSG_MAXLEN_STATUS); encode_status(&msg, status); return bt_mesh_msg_send(srv->model, ctx, &msg); } #endif