2019-10-12 02:41:21 -04:00
|
|
|
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
|
|
|
*
|
2021-10-26 04:24:54 -04:00
|
|
|
* SPDX-FileCopyrightText: 2018 Vikrant More
|
|
|
|
* SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
|
2019-10-12 02:41:21 -04:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
2023-08-25 02:28:44 -04:00
|
|
|
#include "mesh/config.h"
|
|
|
|
#include "mesh/common.h"
|
2023-08-28 04:09:37 -04:00
|
|
|
#include "mesh/model_common.h"
|
2023-08-25 02:28:44 -04:00
|
|
|
#include "mesh/model_opcode.h"
|
|
|
|
#include "mesh/state_binding.h"
|
|
|
|
#include "mesh/state_transition.h"
|
2019-10-12 02:41:21 -04:00
|
|
|
|
2020-10-16 04:10:28 -04:00
|
|
|
#if CONFIG_BLE_MESH_SERVER_MODEL
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
uint16_t bt_mesh_convert_lightness_actual_to_linear(uint16_t actual)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
|
|
|
float tmp = ((float) actual / UINT16_MAX);
|
|
|
|
|
2023-08-28 04:09:37 -04:00
|
|
|
return bt_mesh_ceil(UINT16_MAX * tmp * tmp);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
uint16_t bt_mesh_convert_lightness_linear_to_actual(uint16_t linear)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
2020-12-07 04:03:11 -05:00
|
|
|
return (uint16_t) (UINT16_MAX * bt_mesh_sqrt(((float) linear / UINT16_MAX)));
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
int16_t bt_mesh_convert_temperature_to_gen_level(uint16_t temp, uint16_t min, uint16_t max)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
|
|
|
float tmp = (temp - min) * UINT16_MAX / (max - min);
|
2020-12-07 04:03:11 -05:00
|
|
|
return (int16_t) (tmp + INT16_MIN);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
uint16_t bt_mesh_covert_gen_level_to_temperature(int16_t level, uint16_t min, uint16_t max)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
|
|
|
float diff = (float) (max - min) / UINT16_MAX;
|
2020-12-07 04:03:11 -05:00
|
|
|
uint16_t tmp = (uint16_t) ((level - INT16_MIN) * diff);
|
|
|
|
return (uint16_t) (min + tmp);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
int16_t bt_mesh_convert_hue_to_level(uint16_t hue)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
2020-12-07 04:03:11 -05:00
|
|
|
return (int16_t) (hue + INT16_MIN);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
uint16_t bt_mesh_convert_level_to_hue(int16_t level)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
2020-12-07 04:03:11 -05:00
|
|
|
return (uint16_t) (level - INT16_MIN);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
int16_t bt_mesh_convert_saturation_to_level(uint16_t saturation)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
2020-12-07 04:03:11 -05:00
|
|
|
return (int16_t) (saturation + INT16_MIN);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
2020-12-07 04:03:11 -05:00
|
|
|
uint16_t bt_mesh_convert_level_to_saturation(int16_t level)
|
2019-10-12 02:41:21 -04:00
|
|
|
{
|
2020-12-07 04:03:11 -05:00
|
|
|
return (uint16_t) (level - INT16_MIN);
|
2019-10-12 02:41:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int bt_mesh_update_binding_state(struct bt_mesh_model *model,
|
|
|
|
bt_mesh_server_state_type_t type,
|
|
|
|
bt_mesh_server_state_value_t *value)
|
|
|
|
{
|
|
|
|
if (model == NULL || model->user_data == NULL ||
|
2023-08-28 04:09:37 -04:00
|
|
|
value == NULL || type > BIND_STATE_MAX) {
|
2019-10-12 02:41:21 -04:00
|
|
|
BT_ERR("%s, Invalid parameter", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
2020-10-16 04:10:28 -04:00
|
|
|
#if CONFIG_BLE_MESH_GENERIC_SERVER
|
2019-10-12 02:41:21 -04:00
|
|
|
case GENERIC_ONOFF_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_GEN_ONOFF_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Generic OnOff Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_gen_onoff_srv *srv = model->user_data;
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state.onoff = value->gen_onoff.onoff;
|
|
|
|
gen_onoff_publish(model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GENERIC_LEVEL_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_GEN_LEVEL_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Generic Level Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_gen_level_srv *srv = model->user_data;
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state.level = value->gen_level.level;
|
|
|
|
gen_level_publish(model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GENERIC_ONPOWERUP_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Generic Power OnOff Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Generic Power OnOff Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
srv->state->onpowerup = value->gen_onpowerup.onpowerup;
|
|
|
|
gen_onpowerup_publish(model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GENERIC_POWER_ACTUAL_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Generic Power Level Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_gen_power_level_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Generic Power Level Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->power_actual = value->gen_power_actual.power;
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
gen_power_level_publish(model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
2020-10-16 04:10:28 -04:00
|
|
|
#endif /* CONFIG_BLE_MESH_GENERIC_SERVER */
|
|
|
|
#if CONFIG_BLE_MESH_LIGHTING_SERVER
|
2019-10-12 02:41:21 -04:00
|
|
|
case LIGHT_LIGHTNESS_ACTUAL_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light Lightness Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_lightness_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light Lightness Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->actual_transition);
|
|
|
|
srv->state->lightness_actual = value->light_lightness_actual.lightness;
|
2020-01-04 01:57:08 -05:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
2019-10-12 02:41:21 -04:00
|
|
|
light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_LIGHTNESS_LINEAR_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light Lightness Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_lightness_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light Lightness Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->linear_transition);
|
|
|
|
srv->state->lightness_linear = value->light_lightness_linear.lightness;
|
|
|
|
light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_CTL_LIGHTNESS_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light CTL Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_ctl_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light CTL Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->lightness = value->light_ctl_lightness.lightness;
|
|
|
|
light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_CTL_TEMP_DELTA_UV_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light CTL Temperature Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light CTL Temperature Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->temperature = value->light_ctl_temp_delta_uv.temperature;
|
|
|
|
srv->state->delta_uv = value->light_ctl_temp_delta_uv.delta_uv;
|
|
|
|
light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
2021-01-15 07:27:43 -05:00
|
|
|
case LIGHT_HSL_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
|
|
|
|
BT_ERR("Invalid Light HSL Server, model id 0x%04x", model->id);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_hsl_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
|
|
|
BT_ERR("Invalid Light HSL Server state");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->lightness = value->light_hsl.lightness;
|
|
|
|
srv->state->hue = value->light_hsl.hue;
|
|
|
|
srv->state->saturation = value->light_hsl.saturation;
|
|
|
|
light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
2019-10-12 02:41:21 -04:00
|
|
|
case LIGHT_HSL_LIGHTNESS_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light HSL Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_hsl_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light HSL Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->lightness = value->light_hsl_lightness.lightness;
|
|
|
|
light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_HSL_HUE_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light HSL Hue Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light HSL Hue Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->hue = value->light_hsl_hue.hue;
|
|
|
|
light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_HSL_SATURATION_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light HSL Saturation Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light HSL Saturation Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->saturation = value->light_hsl_saturation.saturation;
|
|
|
|
light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_XYL_LIGHTNESS_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_XYL_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light xyL Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_xyl_srv *srv = model->user_data;
|
|
|
|
if (srv->state == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light xyL Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->state->lightness = value->light_xyl_lightness.lightness;
|
|
|
|
light_xyl_publish(model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIGHT_LC_LIGHT_ONOFF_STATE: {
|
|
|
|
if (model->id != BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light LC Server, model id 0x%04x", model->id);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bt_mesh_light_lc_srv *srv = model->user_data;
|
|
|
|
if (srv->lc == NULL) {
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_ERR("Invalid Light LC Server state");
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_mesh_server_stop_transition(&srv->transition);
|
|
|
|
srv->lc->state.light_onoff = value->light_lc_light_onoff.onoff;
|
|
|
|
light_lc_publish(model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
2020-10-16 04:10:28 -04:00
|
|
|
#endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */
|
2019-10-12 02:41:21 -04:00
|
|
|
default:
|
2020-07-04 06:35:08 -04:00
|
|
|
BT_WARN("Unknown binding state type 0x%02x", type);
|
2019-10-12 02:41:21 -04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-16 04:10:28 -04:00
|
|
|
#endif /* CONFIG_BLE_MESH_SERVER_MODEL */
|