OVMS3-idf/components/bt/esp_ble_mesh/mesh_models/server/time_scene_server.c
lly 2983f6edb1 ble_mesh: Spit mesh_util.h into different header files
Split mesh_util.h into mesh_byteorder.h, mesh_compiler.h,
mesh_ffs.h and mesh_util.h based on the classification of
Zephyr, which will make further porting more clear.
2020-05-13 03:40:30 +00:00

1501 lines
56 KiB
C

// 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 <errno.h>
#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 */
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);
}