esp-idf/components/bt/esp_ble_mesh/models/server/state_transition.c

1041 lines
40 KiB
C

/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* SPDX-FileCopyrightText: 2018 Vikrant More
* SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "btc_ble_mesh_generic_model.h"
#include "btc_ble_mesh_lighting_model.h"
#include "btc_ble_mesh_time_scene_model.h"
#include "btc_ble_mesh_sensor_model.h"
#include "mesh/config.h"
#include "mesh/model_opcode.h"
#include "mesh/state_transition.h"
#if (CONFIG_BLE_MESH_GENERIC_SERVER || \
CONFIG_BLE_MESH_TIME_SCENE_SERVER || \
CONFIG_BLE_MESH_LIGHTING_SERVER)
/* Function to calculate Remaining Time (Start) */
void bt_mesh_server_calc_remain_time(struct bt_mesh_state_transition *transition)
{
uint8_t steps = 0U, resolution = 0U;
int32_t duration_remainder = 0;
int64_t now = 0;
if (transition->just_started) {
transition->remain_time = transition->trans_time;
} else {
now = k_uptime_get();
duration_remainder = transition->total_duration -
(now - transition->start_timestamp);
if (duration_remainder > 620000) {
/* > 620 seconds -> resolution = 0b11 [10 minutes] */
resolution = 0x03;
steps = duration_remainder / 600000;
} else if (duration_remainder > 62000) {
/* > 62 seconds -> resolution = 0b10 [10 seconds] */
resolution = 0x02;
steps = duration_remainder / 10000;
} else if (duration_remainder > 6200) {
/* > 6.2 seconds -> resolution = 0b01 [1 seconds] */
resolution = 0x01;
steps = duration_remainder / 1000;
} else if (duration_remainder > 0) {
/* <= 6.2 seconds -> resolution = 0b00 [100 ms] */
resolution = 0x00;
steps = duration_remainder / 100;
} else {
resolution = 0x00;
steps = 0x00;
}
transition->remain_time = (resolution << 6) | steps;
}
}
/* Function to calculate Remaining Time (End) */
static void tt_values_calculator(struct bt_mesh_state_transition *transition)
{
uint8_t steps_multiplier = 0U, resolution = 0U;
resolution = (transition->trans_time >> 6);
steps_multiplier = (transition->trans_time & 0x3F);
switch (resolution) {
case 0: /* 100ms */
transition->total_duration = steps_multiplier * 100;
break;
case 1: /* 1 second */
transition->total_duration = steps_multiplier * 1000;
break;
case 2: /* 10 seconds */
transition->total_duration = steps_multiplier * 10000;
break;
case 3: /* 10 minutes */
transition->total_duration = steps_multiplier * 600000;
break;
}
transition->counter = ((float) transition->total_duration / 100);
if (transition->counter > BLE_MESH_DEVICE_SPECIFIC_RESOLUTION) {
transition->counter = BLE_MESH_DEVICE_SPECIFIC_RESOLUTION;
}
}
static void transition_time_values(struct bt_mesh_state_transition *transition,
uint8_t trans_time, uint8_t delay)
{
transition->trans_time = trans_time;
transition->delay = delay;
if (trans_time == 0U) {
return;
}
tt_values_calculator(transition);
transition->quo_tt = transition->total_duration / transition->counter;
}
static void transition_timer_start(struct bt_mesh_state_transition *transition)
{
transition->start_timestamp = k_uptime_get();
k_delayed_work_submit_periodic(&transition->timer, K_MSEC(transition->quo_tt));
bt_mesh_atomic_set_bit(transition->flag, BLE_MESH_TRANS_TIMER_START);
}
static void transition_timer_stop(struct bt_mesh_state_transition *transition)
{
k_delayed_work_cancel(&transition->timer);
bt_mesh_atomic_clear_bit(transition->flag, BLE_MESH_TRANS_TIMER_START);
}
#if CONFIG_BLE_MESH_GENERIC_SERVER
void generic_onoff_tt_values(struct bt_mesh_gen_onoff_srv *srv,
uint8_t trans_time, uint8_t delay)
{
return transition_time_values(&srv->transition, trans_time, delay);
}
void generic_level_tt_values(struct bt_mesh_gen_level_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_level =
((float) (srv->state.level - srv->state.target_level) / srv->transition.counter);
}
void generic_power_level_tt_values(struct bt_mesh_gen_power_level_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_level =
((float) (srv->state->power_actual - srv->state->target_power_actual) / srv->transition.counter);
}
#endif /* CONFIG_BLE_MESH_GENERIC_SERVER */
#if CONFIG_BLE_MESH_LIGHTING_SERVER
void light_lightness_actual_tt_values(struct bt_mesh_light_lightness_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->actual_transition, trans_time, delay);
srv->tt_delta_lightness_actual =
((float) (srv->state->lightness_actual - srv->state->target_lightness_actual) / srv->actual_transition.counter);
}
void light_lightness_linear_tt_values(struct bt_mesh_light_lightness_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->linear_transition, trans_time, delay);
srv->tt_delta_lightness_linear =
((float) (srv->state->lightness_linear - srv->state->target_lightness_linear) / srv->linear_transition.counter);
}
void light_ctl_tt_values(struct bt_mesh_light_ctl_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_lightness =
((float) (srv->state->lightness - srv->state->target_lightness) / srv->transition.counter);
srv->tt_delta_temperature =
((float) (srv->state->temperature - srv->state->target_temperature) / srv->transition.counter);
srv->tt_delta_delta_uv =
((float) (srv->state->delta_uv - srv->state->target_delta_uv) / srv->transition.counter);
}
void light_ctl_temp_tt_values(struct bt_mesh_light_ctl_temp_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_temperature =
((float) (srv->state->temperature - srv->state->target_temperature) / srv->transition.counter);
srv->tt_delta_delta_uv =
((float) (srv->state->delta_uv - srv->state->target_delta_uv) / srv->transition.counter);
}
void light_hsl_tt_values(struct bt_mesh_light_hsl_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_lightness =
((float) (srv->state->lightness - srv->state->target_lightness) / srv->transition.counter);
srv->tt_delta_hue =
((float) (srv->state->hue - srv->state->target_hue) / srv->transition.counter);
srv->tt_delta_saturation =
((float) (srv->state->saturation - srv->state->target_saturation) / srv->transition.counter);
}
void light_hsl_hue_tt_values(struct bt_mesh_light_hsl_hue_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_hue =
((float) (srv->state->hue - srv->state->target_hue) / srv->transition.counter);
}
void light_hsl_sat_tt_values(struct bt_mesh_light_hsl_sat_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_saturation =
((float) (srv->state->saturation - srv->state->target_saturation) / srv->transition.counter);
}
void light_xyl_tt_values(struct bt_mesh_light_xyl_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
srv->tt_delta_lightness =
((float) (srv->state->lightness - srv->state->target_lightness) / srv->transition.counter);
srv->tt_delta_x =
((float) (srv->state->x - srv->state->target_x) / srv->transition.counter);
srv->tt_delta_y =
((float) (srv->state->y - srv->state->target_y) / srv->transition.counter);
}
void light_lc_tt_values(struct bt_mesh_light_lc_srv *srv,
uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
}
#endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */
#if CONFIG_BLE_MESH_TIME_SCENE_SERVER
void scene_tt_values(struct bt_mesh_scene_srv *srv, uint8_t trans_time, uint8_t delay)
{
transition_time_values(&srv->transition, trans_time, delay);
}
#endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */
/* Timers related handlers & threads (Start) */
#if CONFIG_BLE_MESH_GENERIC_SERVER
void generic_onoff_work_handler(struct k_work *work)
{
struct bt_mesh_gen_onoff_srv *srv = CONTAINER_OF(work,
struct bt_mesh_gen_onoff_srv,
transition.timer.work);
bt_mesh_gen_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_generic_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.gen_onoff_set.onoff = srv->state.onoff;
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
/**
* Because binary states cannot support transitions, when changing to
* 0x01 (On), the Generic OnOff state shall change immediately when
* the transition starts, and when changing to 0x00, the state shall
* change when the transition finishes.
*/
if (srv->state.target_onoff == BLE_MESH_STATE_ON) {
srv->state.onoff = BLE_MESH_STATE_ON;
change.gen_onoff_set.onoff = srv->state.onoff;
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
}
transition_timer_start(&srv->transition);
}
bt_mesh_generic_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state.onoff = srv->state.target_onoff;
if (srv->state.target_onoff != BLE_MESH_STATE_ON) {
change.gen_onoff_set.onoff = srv->state.onoff;
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
}
}
gen_onoff_publish(srv->model);
bt_mesh_generic_server_unlock();
}
void generic_level_work_handler(struct k_work *work)
{
struct bt_mesh_gen_level_srv *srv = CONTAINER_OF(work,
struct bt_mesh_gen_level_srv,
transition.timer.work);
bt_mesh_gen_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_generic_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
switch (ctx->recv_op) {
case BLE_MESH_MODEL_OP_GEN_LEVEL_SET:
case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK:
change.gen_level_set.level = srv->state.level;
break;
case BLE_MESH_MODEL_OP_GEN_DELTA_SET:
case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK:
change.gen_delta_set.level = srv->state.level;
break;
case BLE_MESH_MODEL_OP_GEN_MOVE_SET:
case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK:
change.gen_move_set.level = srv->state.level;
break;
}
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_generic_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state.level -= srv->tt_delta_level;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state.level = srv->state.target_level;
}
switch (ctx->recv_op) {
case BLE_MESH_MODEL_OP_GEN_LEVEL_SET:
case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK:
change.gen_level_set.level = srv->state.level;
break;
case BLE_MESH_MODEL_OP_GEN_DELTA_SET:
case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK:
change.gen_delta_set.level = srv->state.level;
break;
case BLE_MESH_MODEL_OP_GEN_MOVE_SET:
case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK:
change.gen_move_set.level = srv->state.level;
break;
}
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
gen_level_publish(srv->model);
bt_mesh_generic_server_unlock();
}
void generic_power_level_work_handler(struct k_work *work)
{
struct bt_mesh_gen_power_level_srv *srv = CONTAINER_OF(work,
struct bt_mesh_gen_power_level_srv,
transition.timer.work);
bt_mesh_gen_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_generic_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.gen_power_level_set.power = srv->state->power_actual;
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_generic_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->power_actual -= srv->tt_delta_level;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->power_actual = srv->state->target_power_actual;
/**
* Whenever the Generic Power Actual state is changed to a non-zero value
* as a result of a non-transactional message or a completed sequence of
* transactional messages, the value of the Generic Power Last state shall
* be set to the value of the Generic Power Actual state.
*/
if (srv->state->power_actual) {
srv->state->power_last = srv->state->power_actual;
}
}
change.gen_power_level_set.power = srv->state->power_actual;
bt_mesh_generic_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
gen_power_level_publish(srv->model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
bt_mesh_generic_server_unlock();
}
#endif /* CONFIG_BLE_MESH_GENERIC_SERVER */
#if CONFIG_BLE_MESH_LIGHTING_SERVER
void light_lightness_actual_work_handler(struct k_work *work)
{
struct bt_mesh_light_lightness_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_lightness_srv,
actual_transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->actual_transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->actual_transition.timer.work.user_data;
if (srv->actual_transition.just_started) {
srv->actual_transition.just_started = false;
if (srv->actual_transition.counter == 0U) {
change.lightness_set.lightness = srv->state->lightness_actual;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->actual_transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->actual_transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->actual_transition.counter != 0U) {
srv->actual_transition.counter--;
srv->state->lightness_actual -= srv->tt_delta_lightness_actual;
}
if (srv->actual_transition.counter == 0U) {
transition_timer_stop(&srv->actual_transition);
srv->state->lightness_actual = srv->state->target_lightness_actual;
/**
* Whenever the Light Lightness Actual state is changed with a non-
* transactional message or a completed sequence of transactional
* messages to a non-zero value, the value of the Light Lightness
* Last shall be set to the value of the Light Lightness Actual.
*/
if (srv->state->lightness_actual) {
srv->state->lightness_last = srv->state->lightness_actual;
}
}
change.lightness_set.lightness = srv->state->lightness_actual;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_lightness_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
bt_mesh_light_server_unlock();
}
void light_lightness_linear_work_handler(struct k_work *work)
{
struct bt_mesh_light_lightness_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_lightness_srv,
linear_transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->linear_transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->linear_transition.timer.work.user_data;
if (srv->linear_transition.just_started) {
srv->linear_transition.just_started = false;
if (srv->linear_transition.counter == 0U) {
change.lightness_linear_set.lightness = srv->state->lightness_linear;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->linear_transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->linear_transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->linear_transition.counter != 0U) {
srv->linear_transition.counter--;
srv->state->lightness_linear -= srv->tt_delta_lightness_linear;
}
if (srv->linear_transition.counter == 0U) {
transition_timer_stop(&srv->linear_transition);
srv->state->lightness_linear = srv->state->target_lightness_linear;
}
change.lightness_linear_set.lightness = srv->state->lightness_linear;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_lightness_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
bt_mesh_light_server_unlock();
}
void light_ctl_work_handler(struct k_work *work)
{
struct bt_mesh_light_ctl_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_ctl_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.ctl_set.lightness = srv->state->lightness;
change.ctl_set.temperature = srv->state->temperature;
change.ctl_set.delta_uv = srv->state->delta_uv;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->lightness -= srv->tt_delta_lightness;
srv->state->temperature -= srv->tt_delta_temperature;
srv->state->delta_uv -= srv->tt_delta_delta_uv;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->lightness = srv->state->target_lightness;
srv->state->temperature = srv->state->target_temperature;
srv->state->delta_uv = srv->state->target_delta_uv;
}
change.ctl_set.lightness = srv->state->lightness;
change.ctl_set.temperature = srv->state->temperature;
change.ctl_set.delta_uv = srv->state->delta_uv;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_ctl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
bt_mesh_light_server_unlock();
}
void light_ctl_temp_work_handler(struct k_work *work)
{
struct bt_mesh_light_ctl_temp_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_ctl_temp_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.ctl_temp_set.temperature = srv->state->temperature;
change.ctl_temp_set.delta_uv = srv->state->delta_uv;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->temperature -= srv->tt_delta_temperature;
srv->state->delta_uv -= srv->tt_delta_delta_uv;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->temperature = srv->state->target_temperature;
srv->state->delta_uv = srv->state->target_delta_uv;
}
change.ctl_temp_set.temperature = srv->state->temperature;
change.ctl_temp_set.delta_uv = srv->state->delta_uv;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_ctl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
bt_mesh_light_server_unlock();
}
void light_hsl_work_handler(struct k_work *work)
{
struct bt_mesh_light_hsl_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_hsl_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.hsl_set.lightness = srv->state->lightness;
change.hsl_set.hue = srv->state->hue;
change.hsl_set.saturation = srv->state->saturation;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->lightness -= srv->tt_delta_lightness;
srv->state->hue -= srv->tt_delta_hue;
srv->state->saturation -= srv->tt_delta_saturation;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->lightness = srv->state->target_lightness;
srv->state->hue = srv->state->target_hue;
srv->state->saturation = srv->state->target_saturation;
}
change.hsl_set.lightness = srv->state->lightness;
change.hsl_set.hue = srv->state->hue;
change.hsl_set.saturation = srv->state->saturation;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
bt_mesh_light_server_unlock();
}
void light_hsl_hue_work_handler(struct k_work *work)
{
struct bt_mesh_light_hsl_hue_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_hsl_hue_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.hsl_hue_set.hue = srv->state->hue;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->hue -= srv->tt_delta_hue;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->hue = srv->state->target_hue;
}
change.hsl_hue_set.hue = srv->state->hue;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
bt_mesh_light_server_unlock();
}
void light_hsl_sat_work_handler(struct k_work *work)
{
struct bt_mesh_light_hsl_sat_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_hsl_sat_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.hsl_saturation_set.saturation = srv->state->saturation;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->saturation -= srv->tt_delta_saturation;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->saturation = srv->state->target_saturation;
}
change.hsl_saturation_set.saturation = srv->state->saturation;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
bt_mesh_light_server_unlock();
}
void light_xyl_work_handler(struct k_work *work)
{
struct bt_mesh_light_xyl_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_xyl_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.xyl_set.lightness = srv->state->lightness;
change.xyl_set.x = srv->state->x;
change.xyl_set.y = srv->state->y;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
srv->state->lightness -= srv->tt_delta_lightness;
srv->state->x -= srv->tt_delta_x;
srv->state->y -= srv->tt_delta_y;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->lightness = srv->state->target_lightness;
srv->state->x = srv->state->target_x;
srv->state->y = srv->state->target_y;
}
change.xyl_set.lightness = srv->state->lightness;
change.xyl_set.x = srv->state->x;
change.xyl_set.y = srv->state->y;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
light_xyl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
bt_mesh_light_server_unlock();
}
void light_lc_work_handler(struct k_work *work)
{
struct bt_mesh_light_lc_srv *srv = CONTAINER_OF(work,
struct bt_mesh_light_lc_srv,
transition.timer.work);
bt_mesh_light_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_light_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.lc_light_onoff_set.onoff = srv->lc->state.light_onoff;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
/**
* Because binary states cannot support transitions, when changing to
* 0x01 (On), the Generic OnOff state shall change immediately when
* the transition starts, and when changing to 0x00, the state shall
* change when the transition finishes.
*/
if (srv->lc->state.target_light_onoff == BLE_MESH_STATE_ON) {
srv->lc->state.light_onoff = BLE_MESH_STATE_ON;
bt_mesh_light_server_state_change_t change = {
.lc_light_onoff_set.onoff = srv->lc->state.light_onoff,
};
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
}
transition_timer_start(&srv->transition);
}
bt_mesh_light_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->lc->state.light_onoff = srv->lc->state.target_light_onoff;
if (srv->lc->state.light_onoff != BLE_MESH_STATE_ON) {
change.lc_light_onoff_set.onoff = srv->lc->state.light_onoff;
bt_mesh_lighting_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
}
}
light_lc_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
bt_mesh_light_server_unlock();
}
#endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */
#if CONFIG_BLE_MESH_TIME_SCENE_SERVER
void scene_recall_work_handler(struct k_work *work)
{
struct bt_mesh_scene_srv *srv = CONTAINER_OF(work,
struct bt_mesh_scene_srv,
transition.timer.work);
bt_mesh_time_scene_server_state_change_t change = {0};
struct bt_mesh_msg_ctx *ctx = NULL;
if (srv == NULL || srv->state == NULL ||
srv->transition.timer.work.user_data == NULL) {
BT_ERR("%s, Invalid parameter", __func__);
return;
}
bt_mesh_time_scene_server_lock();
ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work.user_data;
if (srv->transition.just_started) {
srv->transition.just_started = false;
if (srv->transition.counter == 0U) {
change.scene_recall.scene_number = srv->state->current_scene;
bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
} else {
transition_timer_start(&srv->transition);
}
bt_mesh_time_scene_server_unlock();
return;
}
if (srv->transition.counter != 0U) {
srv->transition.counter--;
}
if (srv->transition.counter == 0U) {
transition_timer_stop(&srv->transition);
srv->state->current_scene = srv->state->target_scene;
srv->state->in_progress = false;
srv->state->target_scene = INVALID_SCENE_NUMBER;
}
change.scene_recall.scene_number = srv->state->current_scene;
bt_mesh_time_scene_server_cb_evt_to_btc(BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE,
srv->model, ctx, (const uint8_t *)&change, sizeof(change));
scene_publish(srv->model, ctx, BLE_MESH_MODEL_OP_SCENE_STATUS);
bt_mesh_time_scene_server_unlock();
}
#endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */
/* Timers related handlers & threads (End) */
void bt_mesh_server_stop_transition(struct bt_mesh_state_transition *transition)
{
memset(transition, 0x0, offsetof(struct bt_mesh_state_transition, flag));
if (bt_mesh_atomic_test_and_clear_bit(transition->flag, BLE_MESH_TRANS_TIMER_START)) {
k_delayed_work_cancel(&transition->timer);
}
}
void bt_mesh_server_start_transition(struct bt_mesh_state_transition *transition)
{
k_delayed_work_submit(&transition->timer, K_MSEC(5 * transition->delay));
if (transition->delay) {
bt_mesh_atomic_set_bit(transition->flag, BLE_MESH_TRANS_TIMER_START);
}
}
/* Messages handlers (End) */
#endif /* (CONFIG_BLE_MESH_GENERIC_SERVER || \
CONFIG_BLE_MESH_TIME_SCENE_SERVER || \
CONFIG_BLE_MESH_LIGHTING_SERVER) */