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.
1500 lines
56 KiB
C
1500 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);
|
|
}
|