// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "btc_ble_mesh_time_scene_model.h" #include "access.h" #include "transport.h" #include "model_opcode.h" #include "state_transition.h" static bt_mesh_mutex_t time_scene_server_lock; static void bt_mesh_time_scene_server_mutex_new(void) { if (!time_scene_server_lock.mutex) { bt_mesh_mutex_create(&time_scene_server_lock); } } static void bt_mesh_time_scene_server_mutex_free(void) { bt_mesh_mutex_free(&time_scene_server_lock); } void bt_mesh_time_scene_server_lock(void) { bt_mesh_mutex_lock(&time_scene_server_lock); } void bt_mesh_time_scene_server_unlock(void) { bt_mesh_mutex_unlock(&time_scene_server_lock); } /* message handlers (Start) */ /* Time Server & Time Setup Server message handlers */ static void send_time_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, bool publish, u16_t opcode) { struct net_buf_simple *msg = NULL; u8_t zero[5] = {0}; u8_t length = 1 + 10; if (ctx == NULL && publish == false) { BT_ERR("%s, Invalid parameter", __func__); return; } if (publish == false) { msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE); if (msg == NULL) { BT_ERR("%s, Failed to allocate memory", __func__); return; } } else { msg = bt_mesh_server_get_pub_msg(model, length); if (msg == NULL) { return; } } bt_mesh_model_msg_init(msg, opcode); switch (opcode) { case BLE_MESH_MODEL_OP_TIME_STATUS: if (model->id == BLE_MESH_MODEL_ID_TIME_SRV) { struct bt_mesh_time_srv *srv = model->user_data; net_buf_simple_add_mem(msg, srv->state->time.tai_seconds, TAI_SECONDS_LEN); if (memcmp(srv->state->time.tai_seconds, zero, TAI_SECONDS_LEN)) { net_buf_simple_add_u8(msg, srv->state->time.subsecond); /** * Set the Uncertainty field to a value that is a sum of the value of * the Uncertainty state and an estimated time it will take the message * to be processed before being sent on the radio interface. * * TODO: how to estimate the processing time? */ net_buf_simple_add_u8(msg, srv->state->time.uncertainty); net_buf_simple_add_le16(msg, (srv->state->time.tai_utc_delta_curr << 1) | srv->state->time.time_authority); net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr); } } else if (model->id == BLE_MESH_MODEL_ID_TIME_SETUP_SRV) { struct bt_mesh_time_setup_srv *srv = model->user_data; net_buf_simple_add_mem(msg, srv->state->time.tai_seconds, TAI_SECONDS_LEN); if (memcmp(srv->state->time.tai_seconds, zero, TAI_SECONDS_LEN)) { net_buf_simple_add_u8(msg, srv->state->time.subsecond); net_buf_simple_add_u8(msg, srv->state->time.uncertainty); net_buf_simple_add_le16(msg, (srv->state->time.tai_utc_delta_curr << 1) | srv->state->time.time_authority); net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr); } } break; case BLE_MESH_MODEL_OP_TIME_ZONE_STATUS: if (model->id == BLE_MESH_MODEL_ID_TIME_SRV) { struct bt_mesh_time_srv *srv = model->user_data; net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr); net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_new); net_buf_simple_add_mem(msg, srv->state->time.tai_zone_change, TAI_OF_ZONE_CHANGE_LEN); } else if (model->id == BLE_MESH_MODEL_ID_TIME_SETUP_SRV) { struct bt_mesh_time_setup_srv *srv = model->user_data; net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr); net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_new); net_buf_simple_add_mem(msg, srv->state->time.tai_zone_change, TAI_OF_ZONE_CHANGE_LEN); } break; case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS: if (model->id == BLE_MESH_MODEL_ID_TIME_SRV) { struct bt_mesh_time_srv *srv = model->user_data; net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_curr); net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_new); net_buf_simple_add_mem(msg, srv->state->time.tai_delta_change, TAI_OF_DELTA_CHANGE_LEN); } else if (model->id == BLE_MESH_MODEL_ID_TIME_SETUP_SRV) { struct bt_mesh_time_setup_srv *srv = model->user_data; net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_curr); net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_new); net_buf_simple_add_mem(msg, srv->state->time.tai_delta_change, TAI_OF_DELTA_CHANGE_LEN); } break; case BLE_MESH_MODEL_OP_TIME_ROLE_STATUS: { struct bt_mesh_time_setup_srv *srv = model->user_data; net_buf_simple_add_u8(msg, srv->state->time_role); break; } default: BT_WARN("%s, Unknown Time status opcode 0x%04x", __func__, opcode); if (publish == false) { bt_mesh_free_buf(msg); } return; } if (publish == false) { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); bt_mesh_free_buf(msg); } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } return; } static void time_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_server_rsp_ctrl *rsp_ctrl = NULL; u8_t zero[5] = {0}; u16_t opcode = 0U, val = 0U; u8_t prev_ttl = 0U; if (model->user_data == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } switch (model->id) { case BLE_MESH_MODEL_ID_TIME_SRV: { struct bt_mesh_time_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, Invalid Time Server state", __func__); return; } rsp_ctrl = &srv->rsp_ctrl; break; } case BLE_MESH_MODEL_ID_TIME_SETUP_SRV: { struct bt_mesh_time_setup_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, Invalid Time Setup Server state", __func__); return; } rsp_ctrl = &srv->rsp_ctrl; break; } default: BT_ERR("%s, Invalid Time Server 0x%04x", __func__, model->id); return; } if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { if (ctx->recv_op != BLE_MESH_MODEL_OP_TIME_STATUS) { bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); return; } } switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_TIME_GET: opcode = BLE_MESH_MODEL_OP_TIME_STATUS; break; case BLE_MESH_MODEL_OP_TIME_STATUS: { struct bt_mesh_time_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, Invalid Time Server state", __func__); return; } if (srv->state->time_role != TIME_RELAY && srv->state->time_role != TIME_CLINET) { /** * If the value of the Time Role state of the element is 0x00 (None) or * 0x01 (Time Authority), the message shall be ignored. */ return; } if (rsp_ctrl->status_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_status_msg_t status = {0}; memcpy(status.time_status.tai_seconds, buf->data, TAI_SECONDS_LEN); net_buf_simple_pull(buf, TAI_SECONDS_LEN); if (memcmp(status.time_status.tai_seconds, zero, TAI_SECONDS_LEN)) { if (buf->len != TAI_SECONDS_LEN) { BT_ERR("%s, Invalid Time Status length %d", __func__, buf->len + TAI_SECONDS_LEN); return; } status.time_status.subsecond = net_buf_simple_pull_u8(buf); status.time_status.uncertainty = net_buf_simple_pull_u8(buf); val = net_buf_simple_pull_le16(buf); status.time_status.time_authority = val & BIT(0); status.time_status.tai_utc_delta = (val >> 1) & BIT_MASK(15); status.time_status.time_zone_offset = net_buf_simple_pull_u8(buf); } bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_STATUS_MSG, model, ctx, (const u8_t *)&status, sizeof(status)); return; } memcpy(srv->state->time.tai_seconds, buf->data, TAI_SECONDS_LEN); net_buf_simple_pull(buf, TAI_SECONDS_LEN); /** * If the TAI Seconds field is 0x0000000000 the Subsecond, Uncertainty, * Time Authority, TAI-UTC Delta and Time Zone Offset fields shall be * omitted; otherwise these fields shall be present. */ if (memcmp(srv->state->time.tai_seconds, zero, TAI_SECONDS_LEN)) { if (buf->len != TAI_SECONDS_LEN) { BT_ERR("%s, Invalid Time Status length %d", __func__, buf->len + TAI_SECONDS_LEN); return; } srv->state->time.subsecond = net_buf_simple_pull_u8(buf); srv->state->time.uncertainty = net_buf_simple_pull_u8(buf); val = net_buf_simple_pull_le16(buf); srv->state->time.tai_utc_delta_curr = (val >> 1) & BIT_MASK(15); srv->state->time.time_zone_offset_curr = net_buf_simple_pull_u8(buf); } bt_mesh_time_scene_server_state_change_t change = {0}; memcpy(change.time_status.tai_seconds, srv->state->time.tai_seconds, TAI_SECONDS_LEN); change.time_status.subsecond = srv->state->time.subsecond; change.time_status.uncertainty = srv->state->time.uncertainty; change.time_status.time_authority = srv->state->time.time_authority; change.time_status.tai_utc_delta_curr = srv->state->time.subsecond; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change)); if (model->pub == NULL || model->pub->msg == NULL || model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) { return; } prev_ttl = model->pub->ttl; if (srv->state->time_role == TIME_RELAY) { /** * Shall publish a Time Status message using TTL = 0 if the value of the * Time Role state is 0x02 (Time Relay) and the Publish Address for the * Time Server model is not set to unassigned address. */ model->pub->ttl = 0U; } send_time_status(model, NULL, true, BLE_MESH_MODEL_OP_TIME_STATUS); /* Restore model publication ttl value */ model->pub->ttl = prev_ttl; return; } case BLE_MESH_MODEL_OP_TIME_ZONE_GET: opcode = BLE_MESH_MODEL_OP_TIME_ZONE_STATUS; break; case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET: opcode = BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS; break; case BLE_MESH_MODEL_OP_TIME_ROLE_GET: opcode = BLE_MESH_MODEL_OP_TIME_ROLE_STATUS; break; default: BT_WARN("%s, Unknown Time Get opcode 0x%04x", __func__, ctx->recv_op); return; } send_time_status(model, ctx, false, opcode); return; } static void time_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_time_setup_srv *srv = model->user_data; bt_mesh_time_scene_server_state_change_t change = {0}; u16_t opcode = 0U, val = 0U; u8_t role = 0U; if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_TIME_SET: if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = {0}; memcpy(set.time_set.tai_seconds, buf->data, TAI_SECONDS_LEN); net_buf_simple_pull(buf, TAI_SECONDS_LEN); set.time_set.subsecond = net_buf_simple_pull_u8(buf); set.time_set.uncertainty = net_buf_simple_pull_u8(buf); val = net_buf_simple_pull_le16(buf); set.time_set.time_authority = val & BIT(0); set.time_set.tai_utc_delta = (val >> 1) & BIT_MASK(15); set.time_set.time_zone_offset = net_buf_simple_pull_u8(buf); bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } memcpy(srv->state->time.tai_seconds, buf->data, TAI_SECONDS_LEN); net_buf_simple_pull(buf, TAI_SECONDS_LEN); srv->state->time.subsecond = net_buf_simple_pull_u8(buf); srv->state->time.uncertainty = net_buf_simple_pull_u8(buf); val = net_buf_simple_pull_le16(buf); srv->state->time.time_authority = val & BIT(0); srv->state->time.tai_utc_delta_curr = (val >> 1) & BIT_MASK(15); srv->state->time.time_zone_offset_curr = net_buf_simple_pull_u8(buf); opcode = BLE_MESH_MODEL_OP_TIME_STATUS; break; case BLE_MESH_MODEL_OP_TIME_ZONE_SET: if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = {0}; set.time_zone_set.time_zone_offset_new = net_buf_simple_pull_u8(buf); memcpy(set.time_zone_set.tai_zone_change, buf->data, TAI_OF_ZONE_CHANGE_LEN); net_buf_simple_pull(buf, TAI_OF_ZONE_CHANGE_LEN); bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } srv->state->time.time_zone_offset_new = net_buf_simple_pull_u8(buf); memcpy(srv->state->time.tai_zone_change, buf->data, TAI_OF_ZONE_CHANGE_LEN); net_buf_simple_pull(buf, TAI_OF_ZONE_CHANGE_LEN); opcode = BLE_MESH_MODEL_OP_TIME_ZONE_STATUS; break; case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: val = net_buf_simple_pull_le16(buf); if ((val >> 15) & BIT(0)) { BT_ERR("%s, Invalid Padding value 1", __func__); return; } if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = {0}; set.tai_utc_delta_set.tai_utc_delta_new = val & BIT_MASK(15); memcpy(set.tai_utc_delta_set.tai_delta_change, buf->data, TAI_OF_DELTA_CHANGE_LEN); net_buf_simple_pull(buf, TAI_OF_DELTA_CHANGE_LEN); bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } srv->state->time.tai_utc_delta_new = val & BIT_MASK(15); memcpy(srv->state->time.tai_delta_change, buf->data, TAI_OF_DELTA_CHANGE_LEN); net_buf_simple_pull(buf, TAI_OF_DELTA_CHANGE_LEN); opcode = BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS; break; case BLE_MESH_MODEL_OP_TIME_ROLE_SET: role = net_buf_simple_pull_u8(buf); if (role > TIME_CLINET) { BT_ERR("%s, Invalid Time Role 0x%02x", __func__, role); return; } if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = { .time_role_set.time_role = role, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } srv->state->time_role = role; opcode = BLE_MESH_MODEL_OP_TIME_ROLE_STATUS; break; default: BT_ERR("%s, Unknown Time Set opcode 0x%04x", __func__, ctx->recv_op); return; } switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_TIME_SET: memcpy(change.time_set.tai_seconds, srv->state->time.tai_seconds, TAI_SECONDS_LEN); change.time_set.subsecond = srv->state->time.subsecond; change.time_set.uncertainty = srv->state->time.uncertainty; change.time_set.time_authority = srv->state->time.time_authority; change.time_set.tai_utc_delta_curr = srv->state->time.subsecond; break; case BLE_MESH_MODEL_OP_TIME_ZONE_SET: change.time_zone_set.time_zone_offset_new = srv->state->time.time_zone_offset_new; memcpy(change.time_zone_set.tai_zone_change, srv->state->time.tai_zone_change, TAI_OF_ZONE_CHANGE_LEN); break; case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET: change.tai_utc_delta_set.tai_utc_delta_new = srv->state->time.tai_utc_delta_new; memcpy(change.tai_utc_delta_set.tai_delta_change, srv->state->time.tai_delta_change, TAI_OF_DELTA_CHANGE_LEN); break; case BLE_MESH_MODEL_OP_TIME_ROLE_SET: change.time_role_set.role = srv->state->time_role; break; default: return; } bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change)); /* Send corresponding time status message */ send_time_status(model, ctx, false, opcode); return; } /* Scene Server & Scene Setup Server message handlers */ static void send_scene_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, bool publish) { struct bt_mesh_scene_srv *srv = model->user_data; struct net_buf_simple *msg = NULL; u8_t length = 1 + 6; if (publish == false) { msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE); if (msg == NULL) { BT_ERR("%s, Failed to allocate memory", __func__); return; } } else { msg = bt_mesh_server_get_pub_msg(model, length); if (msg == NULL) { return; } } bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SCENE_STATUS); /** * If the message is sent as a reply to the Scene Recall message, the * Status Code field identifies the result of the related operation; * otherwise, the Status Code field shall be set to Success. */ if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_GET) { net_buf_simple_add_u8(msg, SCENE_SUCCESS); } else { net_buf_simple_add_u8(msg, srv->state->status_code); } net_buf_simple_add_le16(msg, srv->state->current_scene); /** * When an element is in the process of changing the Scene state, the * Target Scene field identifies the target Scene Number of the target * Scene state the element is to reach. * When an element is not in the process of changing the Scene state, * the Target Scene field shall be omitted. */ if (srv->transition.counter) { bt_mesh_server_calc_remain_time(&srv->transition); net_buf_simple_add_le16(msg, srv->state->target_scene); net_buf_simple_add_u8(msg, srv->transition.remain_time); } if (publish == false) { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); bt_mesh_free_buf(msg); } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } return; } static void send_scene_register_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, u8_t status_code, bool publish) { struct bt_mesh_scene_setup_srv *srv = model->user_data; struct scene_register *scene = NULL; struct net_buf_simple *msg = NULL; u16_t total_len = 9U; int i; if (ctx == NULL && publish == false) { BT_ERR("%s, Invalid parameter", __func__); return; } if (publish == false) { msg = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)); if (msg == NULL) { BT_ERR("%s, Failed to allocate memory", __func__); return; } } else { msg = bt_mesh_server_get_pub_msg(model, 5); if (msg == NULL) { return; } } bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS); net_buf_simple_add_u8(msg, status_code); net_buf_simple_add_le16(msg, srv->state->current_scene); for (i = 0; i < srv->state->scene_count; i++) { scene = &srv->state->scenes[i]; if (scene->scene_number != INVALID_SCENE_NUMBER) { total_len += SCENE_NUMBER_LEN; if ((publish == false && total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) || (publish == true && total_len > msg->size + BLE_MESH_SERVER_TRANS_MIC_SIZE)) { /* Add this in case the message is too long */ BT_WARN("Too large scene register status"); break; } net_buf_simple_add_le16(msg, scene->scene_number); } } if (publish == false) { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL)); bt_mesh_free_buf(msg); } else { BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model)); } return; } static void scene_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_scene_srv *srv = model->user_data; if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); return; } switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_SCENE_GET: send_scene_status(model, ctx, false); return; case BLE_MESH_MODEL_OP_SCENE_REGISTER_GET: /** * When a Scene Server receives a Scene Register Get message, it shall * respond with a Scene Register Status message, setting the Status * Code field to Success. */ send_scene_register_status(model, ctx, SCENE_SUCCESS, false); return; default: BT_WARN("%s, Unknown Scene Get opcode 0x%04x", __func__, ctx->recv_op); return; } } void scene_publish(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, u16_t opcode) { struct bt_mesh_scene_srv *srv = model->user_data; if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } send_scene_status(model, ctx, true); return; } static void scene_recall(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_scene_srv *srv = model->user_data; struct scene_register *scene = NULL; u8_t tid = 0U, trans_time = 0U, delay = 0U; u16_t scene_number = 0U; bool optional = false; s64_t now = 0; int i; if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } scene_number = net_buf_simple_pull_le16(buf); if (scene_number == INVALID_SCENE_NUMBER) { BT_ERR("%s, Invalid Scene Number 0x0000", __func__); return; } tid = net_buf_simple_pull_u8(buf); if (bt_mesh_server_get_optional(model, ctx, buf, &trans_time, &delay, &optional)) { return; } if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = { .scene_recall.op_en = optional, .scene_recall.scene_number = scene_number, .scene_recall.tid = tid, .scene_recall.trans_time = trans_time, .scene_recall.delay = delay, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } for (i = 0; i < srv->state->scene_count; i++) { scene = &srv->state->scenes[i]; if (scene->scene_number == scene_number) { break; } } if (i == srv->state->scene_count) { BT_WARN("%s, Scene Number 0x%04x not exist", __func__, scene_number); srv->state->status_code = SCENE_NOT_FOUND; if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) { send_scene_status(model, ctx, false); } send_scene_status(model, ctx, true); return; } srv->state->status_code = SCENE_SUCCESS; /* Mesh Model Spec doesn't mention about this operation. */ if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) { if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) { send_scene_status(model, ctx, false); } send_scene_status(model, ctx, true); /* In this condition, no event will be callback to application layer */ return; } bt_mesh_time_scene_server_lock(); bt_mesh_server_stop_transition(&srv->transition); bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now); srv->state->in_progress = false; /** * When the scene transition is not in progress, the value of the Target * Scene state shall be set to 0x0000. */ srv->state->target_scene = INVALID_SCENE_NUMBER; /** * If the target state is equal to the current state, the transition * shall not be started and is considered complete. */ if (srv->state->current_scene != scene_number) { scene_tt_values(srv, trans_time, delay); } else { if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) { send_scene_status(model, ctx, false); } send_scene_status(model, ctx, true); bt_mesh_time_scene_server_state_change_t change = { .scene_recall.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change)); bt_mesh_time_scene_server_unlock(); return; } /* Copy the ctx of the received message */ if (srv->transition.timer.work._reserved) { memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx)); } /* For Instantaneous Transition */ if (srv->transition.counter == 0U) { srv->state->current_scene = scene_number; } else { /** * When a scene transition is in progress, the value of the Current * Scene state shall be set to 0x0000. */ srv->state->in_progress = true; srv->state->current_scene = INVALID_SCENE_NUMBER; srv->state->target_scene = scene_number; } srv->transition.just_started = true; if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) { send_scene_status(model, ctx, false); } send_scene_status(model, ctx, true); bt_mesh_time_scene_server_unlock(); bt_mesh_server_start_transition(&srv->transition); return; } static void scene_action(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_scene_setup_srv *srv = model->user_data; struct scene_register *scene = NULL; u16_t scene_number = 0U; int i; if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } scene_number = net_buf_simple_pull_le16(buf); if (scene_number == INVALID_SCENE_NUMBER) { BT_ERR("%s, Invalid Scene number 0x0000", __func__); return; } switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_SCENE_STORE: case BLE_MESH_MODEL_OP_SCENE_STORE_UNACK: { if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = { .scene_store.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } /* Try to find a matching Scene Number */ for (i = 0; i < srv->state->scene_count; i++) { scene = &srv->state->scenes[i]; if (scene->scene_number == scene_number) { srv->state->status_code = SCENE_SUCCESS; srv->state->current_scene = scene_number; break; } } /* Try to find a unset entry if no matching Scene Number is found */ if (i == srv->state->scene_count) { BT_DBG("%s, No matching Scene Number 0x%04x found", __func__, scene_number); for (i = 0; i < srv->state->scene_count; i++) { scene = &srv->state->scenes[i]; if (scene->scene_number == INVALID_SCENE_NUMBER) { scene->scene_number = scene_number; srv->state->status_code = SCENE_SUCCESS; srv->state->current_scene = scene_number; break; } } if (i == srv->state->scene_count) { BT_WARN("%s, Scene Register full", __func__); srv->state->status_code = SCENE_REG_FULL; /* Get the Scene Number of the currently active scene */ for (i = 0; i < srv->state->scene_count; i++) { scene = &srv->state->scenes[i]; if (scene->scene_number != INVALID_SCENE_NUMBER) { srv->state->current_scene = scene->scene_number; break; } } if (i == srv->state->scene_count) { /* A value of 0x0000 when no scene is active */ srv->state->current_scene = INVALID_SCENE_NUMBER; } } } if (srv->state->in_progress == true) { /** * When the scene transition is in progress and a new Scene Number is * stored in the Scene Register as a result of Scene Store operation, * the Target Scene state shall be set to the new Scene Number. */ srv->state->target_scene = scene_number; } if (srv->state->status_code == SCENE_SUCCESS) { bt_mesh_time_scene_server_state_change_t change = { .scene_store.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change)); } break; } case BLE_MESH_MODEL_OP_SCENE_DELETE: case BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK: { if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = { .scene_delete.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } for (i = 0; i < srv->state->scene_count; i++) { scene = &srv->state->scenes[i]; if (scene->scene_number == scene_number) { scene->scene_number = INVALID_SCENE_NUMBER; break; } } if (i == srv->state->scene_count) { BT_WARN("%s, Scene Number 0x%04x not exist", __func__, scene_number); /** * When a Scene Server receives a Scene Delete message with the Scene * Number value that does not match a Scene Number stored within the * Scene Register state, it shall respond with the Scene Register * Status message, setting the Status Code field to Success. */ } srv->state->status_code = SCENE_SUCCESS; if (srv->state->current_scene == scene_number) { /** * When the Current Scene Number is deleted from a Scene Register state * as a result of Scene Delete operation, the Current Scene state shall * be set to 0x0000. */ srv->state->current_scene = INVALID_SCENE_NUMBER; } else { /** * MMDL/SR/SCES/BV-02-C requires response with Current Scene set to the * latest Scene Number, but this is not mentioned in the spec. * * TODO: Do we need a timestamp for each newly added scene? */ for (i = srv->state->scene_count; i > 0; i--) { scene = &srv->state->scenes[i - 1]; if (scene->scene_number != INVALID_SCENE_NUMBER) { srv->state->current_scene = scene->scene_number; break; } } if (i == 0) { /* A value of 0x0000 when no scene is active */ srv->state->current_scene = INVALID_SCENE_NUMBER; } } if (srv->state->target_scene == scene_number && srv->state->in_progress == true) { /** * When the scene transition is in progress and the target Scene Number * is deleted from a Scene Register state as a result of Scene Delete * operation, the Target Scene state shall be set to 0x0000. */ srv->state->target_scene = INVALID_SCENE_NUMBER; /** * When a scene is deleted when a scene transition to the deleted Scene * Number is in progress, the scene transition shall be terminated, but * individual model transitions shall not be terminated. */ struct bt_mesh_scene_srv *scene_srv = NULL; struct bt_mesh_model *scene_model = NULL; scene_model = bt_mesh_model_find(bt_mesh_model_elem(model), BLE_MESH_MODEL_ID_SCENE_SRV); if (scene_model == NULL) { BT_ERR("%s, Scene Server is not present in the element", __func__); break; } scene_srv = scene_model->user_data; if (scene_srv == NULL || scene_srv->state == NULL) { BT_ERR("%s, Invalid Scene Server parameter", __func__); break; } if (srv->state != scene_srv->state) { /** * Add this in case the Scene Setup Server is extending the Scene * Server in another element. */ BT_WARN("%s, Different Scene state in Scene Server & Scene Setup Server", __func__); break; } scene_srv->state->in_progress = false; bt_mesh_server_stop_transition(&scene_srv->transition); } bt_mesh_time_scene_server_state_change_t change = { .scene_delete.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change)); break; } default: BT_ERR("%s, Unknown Scene setup action opcode 0x%04x", __func__, ctx->recv_op); return; } if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_STORE || ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_DELETE) { send_scene_register_status(model, ctx, srv->state->status_code, false); } send_scene_register_status(model, NULL, srv->state->status_code, true); return; } static u16_t get_schedule_reg_bit(struct bt_mesh_scheduler_state *state) { u16_t val = 0U; int i; for (i = 0; i < state->schedule_count; i++) { if (state->schedules[i].in_use) { val |= (1 << i); } } return val; } static u64_t get_schedule_reg_state(struct bt_mesh_scheduler_state *state, u8_t index) { struct schedule_register *reg = &state->schedules[index]; u64_t val = 0U; val = ((u64_t)(reg->year) << 4) | index; val |= ((u64_t)(reg->day) << 23) | ((u64_t)(reg->month) << 11); val |= ((u64_t)(reg->minute) << 33) | ((u64_t)(reg->hour) << 28); val |= ((u64_t)(reg->day_of_week) << 45) | ((u64_t)(reg->second) << 39); val |= ((u64_t)(reg->trans_time) << 56) | ((u64_t)(reg->action) << 52); return val; } static void send_scheduler_act_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, u8_t index) { NET_BUF_SIMPLE_DEFINE(msg, 1 + 10 + BLE_MESH_SERVER_TRANS_MIC_SIZE); u64_t value = 0U; bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS); switch (model->id) { case BLE_MESH_MODEL_ID_SCHEDULER_SRV: { struct bt_mesh_scheduler_srv *srv = model->user_data; value = get_schedule_reg_state(srv->state, index); net_buf_simple_add_le32(&msg, (u32_t)value); net_buf_simple_add_le32(&msg, (u32_t)(value >> 32)); net_buf_simple_add_le16(&msg, srv->state->schedules[index].scene_number); break; } case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV: { struct bt_mesh_scheduler_setup_srv *srv = model->user_data; value = get_schedule_reg_state(srv->state, index); net_buf_simple_add_le32(&msg, (u32_t)value); net_buf_simple_add_le32(&msg, (u32_t)(value >> 32)); net_buf_simple_add_le16(&msg, srv->state->schedules[index].scene_number); break; } default: BT_ERR("%s, Invalid Scheduler Server 0x%04x", __func__, model->id); return; } BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL)); return; } static void scheduler_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_scheduler_srv *srv = model->user_data; NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE); if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } switch (ctx->recv_op) { case BLE_MESH_MODEL_OP_SCHEDULER_GET: { if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0); return; } bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_SCHEDULER_STATUS); net_buf_simple_add_le16(&msg, get_schedule_reg_bit(srv->state)); BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL)); return; } case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: { u8_t index = net_buf_simple_pull_u8(buf); if (index > SCHEDULE_ENTRY_MAX_INDEX) { BT_ERR("%s, Invalid Scheduler Register Entry index 0x%02x", __func__, index); return; } if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_get_msg_t get = { .scheduler_act_get.index = index, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get)); return; } send_scheduler_act_status(model, ctx, index); return; } default: BT_WARN("%s, Unknown Scheduler Get opcode 0x%04x", __func__, ctx->recv_op); return; } } static void scheduler_act_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { /** * A recommended implementation of the Scheduler should calculate the value * of the TAI Seconds of the next scheduled event and put it in a queue of * scheduled events sorted by time. Every second, the first event in the * queue is compared with the value of the Time state. The first event is * executed if it is less than or equal to the Time state and then removed * from the queue. After execution, the Repeat Flag shall be checked, and * the next occurrence of the scheduled event is calculated and put in the * queue. */ struct bt_mesh_scheduler_setup_srv *srv = model->user_data; u8_t index = 0U, year = 0U, day = 0U, hour = 0U, minute = 0U, second = 0U, day_of_week = 0U, action = 0U, trans_time = 0U; u16_t month = 0U, scene_number = 0U; u64_t value = 0U; if (srv == NULL || srv->state == NULL) { BT_ERR("%s, Invalid model user_data", __func__); return; } value = net_buf_simple_pull_le32(buf); value |= ((u64_t)net_buf_simple_pull_le32(buf) << 32); index = value & BIT_MASK(4); year = (value >> 4) & BIT_MASK(7); month = (value >> 11) & BIT_MASK(12); day = (value >> 23) & BIT_MASK(5); hour = (value >> 28) & BIT_MASK(5); minute = (value >> 33) & BIT_MASK(6); second = (value >> 39) & BIT_MASK(6); day_of_week = (value >> 45) & BIT_MASK(7); action = (value >> 52) & BIT_MASK(4); trans_time = (value >> 56) & BIT_MASK(8); if (index > SCHEDULE_ENTRY_MAX_INDEX) { BT_ERR("%s, Invalid Scheduler Register Entry index 0x%02x", __func__, index); return; } if (year > SCHEDULE_YEAR_ANY_YEAR) { BT_ERR("%s, Invalid Scheduler Register year 0x%02x", __func__, year); return; } if (hour > SCHEDULE_HOUR_ONCE_A_DAY) { BT_ERR("%s, Invalid Scheduler Register hour 0x%02x", __func__, hour); return; } if (action > SCHEDULE_ACT_SCENE_RECALL && action != SCHEDULE_ACT_NO_ACTION) { BT_ERR("%s, Invalid Scheduler Register action 0x%02x", __func__, action); return; } scene_number = net_buf_simple_pull_le16(buf); if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) { bt_mesh_time_scene_server_recv_set_msg_t set = { .scheduler_act_set.index = index, .scheduler_act_set.year = year, .scheduler_act_set.month = month, .scheduler_act_set.day = day, .scheduler_act_set.hour = hour, .scheduler_act_set.minute = minute, .scheduler_act_set.second = second, .scheduler_act_set.day_of_week = day_of_week, .scheduler_act_set.action = action, .scheduler_act_set.trans_time = trans_time, .scheduler_act_set.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set)); return; } srv->state->schedules[index].in_use = true; srv->state->schedules[index].year = year; srv->state->schedules[index].month = month; srv->state->schedules[index].day = day; srv->state->schedules[index].hour = hour; srv->state->schedules[index].minute = minute; srv->state->schedules[index].second = second; srv->state->schedules[index].day_of_week = day_of_week; srv->state->schedules[index].action = action; srv->state->schedules[index].trans_time = trans_time; srv->state->schedules[index].scene_number = scene_number; bt_mesh_time_scene_server_state_change_t change = { .scheduler_act_set.index = index, .scheduler_act_set.year = year, .scheduler_act_set.month = month, .scheduler_act_set.day = day, .scheduler_act_set.hour = hour, .scheduler_act_set.minute = minute, .scheduler_act_set.second = second, .scheduler_act_set.day_of_week = day_of_week, .scheduler_act_set.action = action, .scheduler_act_set.trans_time = trans_time, .scheduler_act_set.scene_number = scene_number, }; bt_mesh_time_scene_server_cb_evt_to_btc( BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change)); if (ctx->recv_op == BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET) { send_scheduler_act_status(model, ctx, index); } return; } /* message handlers (End) */ /* Mapping of message handlers for Time Server (0x1200) */ const struct bt_mesh_model_op time_srv_op[] = { { BLE_MESH_MODEL_OP_TIME_GET, 0, time_get }, { BLE_MESH_MODEL_OP_TIME_STATUS, 5, time_get }, { BLE_MESH_MODEL_OP_TIME_ZONE_GET, 0, time_get }, { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET, 0, time_get }, BLE_MESH_MODEL_OP_END, }; /* Mapping of message handlers for Time Setup Server (0x1201) */ const struct bt_mesh_model_op time_setup_srv_op[] = { { BLE_MESH_MODEL_OP_TIME_SET, 10, time_set }, { BLE_MESH_MODEL_OP_TIME_ZONE_SET, 6, time_set }, { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET, 7, time_set }, { BLE_MESH_MODEL_OP_TIME_ROLE_GET, 0, time_get }, { BLE_MESH_MODEL_OP_TIME_ROLE_SET, 1, time_set }, BLE_MESH_MODEL_OP_END, }; /* Mapping of message handlers for Scene Server (0x1203) */ const struct bt_mesh_model_op scene_srv_op[] = { { BLE_MESH_MODEL_OP_SCENE_GET, 0, scene_get }, { BLE_MESH_MODEL_OP_SCENE_RECALL, 3, scene_recall }, { BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK, 3, scene_recall }, { BLE_MESH_MODEL_OP_SCENE_REGISTER_GET, 0, scene_get }, BLE_MESH_MODEL_OP_END, }; /* Mapping of message handlers for Scene Setup Server (0x1204) */ const struct bt_mesh_model_op scene_setup_srv_op[] = { { BLE_MESH_MODEL_OP_SCENE_STORE, 2, scene_action }, { BLE_MESH_MODEL_OP_SCENE_STORE_UNACK, 2, scene_action }, { BLE_MESH_MODEL_OP_SCENE_DELETE, 2, scene_action }, { BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK, 2, scene_action }, BLE_MESH_MODEL_OP_END, }; /* Mapping of message handlers for Scheduler Server (0x1206) */ const struct bt_mesh_model_op scheduler_srv_op[] = { { BLE_MESH_MODEL_OP_SCHEDULER_GET, 0, scheduler_get }, { BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET, 1, scheduler_get }, BLE_MESH_MODEL_OP_END, }; /* Mapping of message handlers for Scheduler Setup Server (0x1207) */ const struct bt_mesh_model_op scheduler_setup_srv_op[] = { { BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET, 10, scheduler_act_set }, { BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK, 10, scheduler_act_set }, BLE_MESH_MODEL_OP_END, }; static int check_scene_server_init(struct bt_mesh_scenes_state *state) { int i; if (state->scene_count == 0U || state->scenes == NULL) { BT_ERR("%s, Invalid Scene state", __func__); return -EINVAL; } for (i = 0; i < state->scene_count; i++) { if (state->scenes[i].scene_value == NULL) { BT_ERR("%s, Invalid Scene value, index %d", __func__, i); return -EINVAL; } } return 0; } static int time_scene_server_init(struct bt_mesh_model *model) { if (model->user_data == NULL) { BT_ERR("%s, No Time Scene Server context provided, model_id 0x%04x", __func__, model->id); return -EINVAL; } switch (model->id) { case BLE_MESH_MODEL_ID_TIME_SRV: { struct bt_mesh_time_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Time State", __func__); return -EINVAL; } srv->model = model; break; } case BLE_MESH_MODEL_ID_TIME_SETUP_SRV: { struct bt_mesh_time_setup_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Time State", __func__); return -EINVAL; } srv->model = model; break; } case BLE_MESH_MODEL_ID_SCENE_SRV: { struct bt_mesh_scene_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Scene State", __func__); return -EINVAL; } if (check_scene_server_init(srv->state)) { return -EINVAL; } if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) { bt_mesh_server_alloc_ctx(&srv->transition.timer.work); k_delayed_work_init(&srv->transition.timer, scene_recall_work_handler); } srv->model = model; break; } case BLE_MESH_MODEL_ID_SCENE_SETUP_SRV: { struct bt_mesh_scene_setup_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Scene State", __func__); return -EINVAL; } if (check_scene_server_init(srv->state)) { return -EINVAL; } srv->model = model; break; } case BLE_MESH_MODEL_ID_SCHEDULER_SRV: { struct bt_mesh_scheduler_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Scheduler State", __func__); return -EINVAL; } if (srv->state->schedule_count == 0U || srv->state->schedules == NULL) { BT_ERR("%s, NULL Register Schedule", __func__); return -EINVAL; } srv->model = model; break; } case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV: { struct bt_mesh_scheduler_setup_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Scheduler State", __func__); return -EINVAL; } if (srv->state->schedule_count == 0U || srv->state->schedules == NULL) { BT_ERR("%s, NULL Register Schedule", __func__); return -EINVAL; } srv->model = model; break; } default: BT_WARN("%s, Unknown Time Scene Server Model, model_id 0x%04x", __func__, model->id); return -EINVAL; } bt_mesh_time_scene_server_mutex_new(); return 0; } int bt_mesh_time_srv_init(struct bt_mesh_model *model, bool primary) { if (model->pub == NULL) { BT_ERR("%s, Time Server has no publication support", __func__); return -EINVAL; } /** * When this model is present on an Element, the corresponding Time Setup * Server model shall also be present. */ struct bt_mesh_elem *element = bt_mesh_model_elem(model); if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_TIME_SETUP_SRV) == NULL) { BT_WARN("%s, Time Setup Server is not present", __func__); /* Just give a warning here, continue with the initialization */ } return time_scene_server_init(model); } int bt_mesh_time_setup_srv_init(struct bt_mesh_model *model, bool primary) { /* This model does not support subscribing nor publishing */ if (model->pub) { BT_ERR("%s, Time Setup Server shall not support publication", __func__); return -EINVAL; } return time_scene_server_init(model); } int bt_mesh_scene_srv_init(struct bt_mesh_model *model, bool primary) { if (model->pub == NULL) { BT_ERR("%s, Scene Server has no publication support", __func__); return -EINVAL; } /* The model may be present only on the Primary element of a node. */ if (primary == false) { BT_WARN("%s, Scene Server is not on the Primary element", __func__); /* Just give a warning here, continue with the initialization */ } /** * When this model is present on an Element, the corresponding Scene Setup * Server model shall also be present. */ struct bt_mesh_elem *element = bt_mesh_model_elem(model); if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_SCENE_SETUP_SRV) == NULL) { BT_WARN("%s, Scene Setup Server is not present", __func__); /* Just give a warning here, continue with the initialization */ } return time_scene_server_init(model); } int bt_mesh_scene_setup_srv_init(struct bt_mesh_model *model, bool primary) { /* The model may be present only on the Primary element of a node. */ if (primary == false) { BT_WARN("%s, Scene Setup Server is not on the Primary element", __func__); /* Just give a warning here, continue with the initialization */ } return time_scene_server_init(model); } int bt_mesh_scheduler_srv_init(struct bt_mesh_model *model, bool primary) { if (model->pub == NULL) { BT_ERR("%s, Scheduler Server has no publication support", __func__); return -EINVAL; } /* The model may be present only on the Primary element of a node. */ if (primary == false) { BT_WARN("%s, Scheduler Server is not on the Primary element", __func__); /* Just give a warning here, continue with the initialization */ } /** * When this model is present on an Element, the corresponding Scheduler * Setup Server model shall also be present. The model requires the Time * Server model shall be present on the element. */ struct bt_mesh_elem *element = bt_mesh_model_elem(model); if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV) == NULL) { BT_WARN("%s, Scheduler Setup Server is not present", __func__); /* Just give a warning here, continue with the initialization */ } if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_TIME_SRV) == NULL) { BT_WARN("%s, Time Server is not present", __func__); /* Just give a warning here, continue with the initialization */ } return time_scene_server_init(model); } int bt_mesh_scheduler_setup_srv_init(struct bt_mesh_model *model, bool primary) { /* The model may be present only on the Primary element of a node. */ if (primary == false) { BT_WARN("%s, Scheduler Setup Server is not on the Primary element", __func__); /* Just give a warning here, continue with the initialization */ } return time_scene_server_init(model); } static int time_scene_server_deinit(struct bt_mesh_model *model) { if (model->user_data == NULL) { BT_ERR("%s, No Time Scene Server context provided, model_id 0x%04x", __func__, model->id); return -EINVAL; } switch (model->id) { case BLE_MESH_MODEL_ID_SCENE_SRV: { struct bt_mesh_scene_srv *srv = model->user_data; if (srv->state == NULL) { BT_ERR("%s, NULL Scene State", __func__); return -EINVAL; } if (check_scene_server_init(srv->state)) { return -EINVAL; } if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) { bt_mesh_server_free_ctx(&srv->transition.timer.work); k_delayed_work_free(&srv->transition.timer); } break; } default: BT_WARN("%s, Unknown Time Scene Server Model, model_id 0x%04x", __func__, model->id); return -EINVAL; } bt_mesh_time_scene_server_mutex_free(); return 0; } int bt_mesh_time_srv_deinit(struct bt_mesh_model *model, bool primary) { if (model->pub == NULL) { BT_ERR("%s, Time Server has no publication support", __func__); return -EINVAL; } return time_scene_server_deinit(model); } int bt_mesh_time_setup_srv_deinit(struct bt_mesh_model *model, bool primary) { if (model->pub) { BT_ERR("%s, Time Setup Server shall not support publication", __func__); return -EINVAL; } return time_scene_server_deinit(model); } int bt_mesh_scene_srv_deinit(struct bt_mesh_model *model, bool primary) { if (model->pub == NULL) { BT_ERR("%s, Scene Server has no publication support", __func__); return -EINVAL; } return time_scene_server_deinit(model); } int bt_mesh_scene_setup_srv_deinit(struct bt_mesh_model *model, bool primary) { return time_scene_server_deinit(model); } int bt_mesh_scheduler_srv_deinit(struct bt_mesh_model *model, bool primary) { if (model->pub == NULL) { BT_ERR("%s, Scheduler Server has no publication support", __func__); return -EINVAL; } return time_scene_server_deinit(model); } int bt_mesh_scheduler_setup_srv_deinit(struct bt_mesh_model *model, bool primary) { return time_scene_server_deinit(model); }