1 /* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
2 *
3 * SPDX-FileCopyrightText: 2018 Vikrant More
4 * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <errno.h>
10
11 #include "mesh_config.h"
12 #include "mesh_common.h"
13 #include "model_opcode.h"
14 #include "state_binding.h"
15 #include "state_transition.h"
16
17 #if CONFIG_BLE_MESH_SERVER_MODEL
18
19 #define MINDIFF (2.25e-308)
20
bt_mesh_sqrt(float square)21 static float bt_mesh_sqrt(float square)
22 {
23 float root = 0.0, last = 0.0, diff = 0.0;
24
25 root = square / 3.0;
26 diff = 1;
27
28 if (square <= 0) {
29 return 0;
30 }
31
32 do {
33 last = root;
34 root = (root + square / root) / 2.0;
35 diff = root - last;
36 } while (diff > MINDIFF || diff < -MINDIFF);
37
38 return root;
39 }
40
bt_mesh_ceiling(float num)41 static int32_t bt_mesh_ceiling(float num)
42 {
43 int32_t inum = (int32_t)num;
44
45 if (num == (float)inum) {
46 return inum;
47 }
48
49 return inum + 1;
50 }
51
bt_mesh_convert_lightness_actual_to_linear(uint16_t actual)52 uint16_t bt_mesh_convert_lightness_actual_to_linear(uint16_t actual)
53 {
54 float tmp = ((float) actual / UINT16_MAX);
55
56 return bt_mesh_ceiling(UINT16_MAX * tmp * tmp);
57 }
58
bt_mesh_convert_lightness_linear_to_actual(uint16_t linear)59 uint16_t bt_mesh_convert_lightness_linear_to_actual(uint16_t linear)
60 {
61 return (uint16_t) (UINT16_MAX * bt_mesh_sqrt(((float) linear / UINT16_MAX)));
62 }
63
bt_mesh_convert_temperature_to_gen_level(uint16_t temp,uint16_t min,uint16_t max)64 int16_t bt_mesh_convert_temperature_to_gen_level(uint16_t temp, uint16_t min, uint16_t max)
65 {
66 float tmp = (temp - min) * UINT16_MAX / (max - min);
67 return (int16_t) (tmp + INT16_MIN);
68 }
69
bt_mesh_covert_gen_level_to_temperature(int16_t level,uint16_t min,uint16_t max)70 uint16_t bt_mesh_covert_gen_level_to_temperature(int16_t level, uint16_t min, uint16_t max)
71 {
72 float diff = (float) (max - min) / UINT16_MAX;
73 uint16_t tmp = (uint16_t) ((level - INT16_MIN) * diff);
74 return (uint16_t) (min + tmp);
75 }
76
bt_mesh_convert_hue_to_level(uint16_t hue)77 int16_t bt_mesh_convert_hue_to_level(uint16_t hue)
78 {
79 return (int16_t) (hue + INT16_MIN);
80 }
81
bt_mesh_convert_level_to_hue(int16_t level)82 uint16_t bt_mesh_convert_level_to_hue(int16_t level)
83 {
84 return (uint16_t) (level - INT16_MIN);
85 }
86
bt_mesh_convert_saturation_to_level(uint16_t saturation)87 int16_t bt_mesh_convert_saturation_to_level(uint16_t saturation)
88 {
89 return (int16_t) (saturation + INT16_MIN);
90 }
91
bt_mesh_convert_level_to_saturation(int16_t level)92 uint16_t bt_mesh_convert_level_to_saturation(int16_t level)
93 {
94 return (uint16_t) (level - INT16_MIN);
95 }
96
bt_mesh_update_binding_state(struct bt_mesh_model * model,bt_mesh_server_state_type_t type,bt_mesh_server_state_value_t * value)97 int bt_mesh_update_binding_state(struct bt_mesh_model *model,
98 bt_mesh_server_state_type_t type,
99 bt_mesh_server_state_value_t *value)
100 {
101 if (model == NULL || model->user_data == NULL ||
102 value == NULL || type > BIND_STATE_MAX) {
103 BT_ERR("%s, Invalid parameter", __func__);
104 return -EINVAL;
105 }
106
107 switch (type) {
108 #if CONFIG_BLE_MESH_GENERIC_SERVER
109 case GENERIC_ONOFF_STATE: {
110 if (model->id != BLE_MESH_MODEL_ID_GEN_ONOFF_SRV) {
111 BT_ERR("Invalid Generic OnOff Server, model id 0x%04x", model->id);
112 return -EINVAL;
113 }
114
115 struct bt_mesh_gen_onoff_srv *srv = model->user_data;
116 bt_mesh_server_stop_transition(&srv->transition);
117 srv->state.onoff = value->gen_onoff.onoff;
118 gen_onoff_publish(model);
119 break;
120 }
121 case GENERIC_LEVEL_STATE: {
122 if (model->id != BLE_MESH_MODEL_ID_GEN_LEVEL_SRV) {
123 BT_ERR("Invalid Generic Level Server, model id 0x%04x", model->id);
124 return -EINVAL;
125 }
126
127 struct bt_mesh_gen_level_srv *srv = model->user_data;
128 bt_mesh_server_stop_transition(&srv->transition);
129 srv->state.level = value->gen_level.level;
130 gen_level_publish(model);
131 break;
132 }
133 case GENERIC_ONPOWERUP_STATE: {
134 if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV) {
135 BT_ERR("Invalid Generic Power OnOff Server, model id 0x%04x", model->id);
136 return -EINVAL;
137 }
138
139 struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
140 if (srv->state == NULL) {
141 BT_ERR("Invalid Generic Power OnOff Server state");
142 return -EINVAL;
143 }
144
145 srv->state->onpowerup = value->gen_onpowerup.onpowerup;
146 gen_onpowerup_publish(model);
147 break;
148 }
149 case GENERIC_POWER_ACTUAL_STATE: {
150 if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
151 BT_ERR("Invalid Generic Power Level Server, model id 0x%04x", model->id);
152 return -EINVAL;
153 }
154
155 struct bt_mesh_gen_power_level_srv *srv = model->user_data;
156 if (srv->state == NULL) {
157 BT_ERR("Invalid Generic Power Level Server state");
158 return -EINVAL;
159 }
160
161 bt_mesh_server_stop_transition(&srv->transition);
162 srv->state->power_actual = value->gen_power_actual.power;
163 /**
164 * Whenever the Generic Power Actual state is changed to a non-zero value
165 * as a result of a non-transactional message or a completed sequence of
166 * transactional messages, the value of the Generic Power Last state shall
167 * be set to the value of the Generic Power Actual state.
168 */
169 if (srv->state->power_actual) {
170 srv->state->power_last = srv->state->power_actual;
171 }
172 gen_power_level_publish(model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
173 break;
174 }
175 #endif /* CONFIG_BLE_MESH_GENERIC_SERVER */
176 #if CONFIG_BLE_MESH_LIGHTING_SERVER
177 case LIGHT_LIGHTNESS_ACTUAL_STATE: {
178 if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
179 BT_ERR("Invalid Light Lightness Server, model id 0x%04x", model->id);
180 return -EINVAL;
181 }
182
183 struct bt_mesh_light_lightness_srv *srv = model->user_data;
184 if (srv->state == NULL) {
185 BT_ERR("Invalid Light Lightness Server state");
186 return -EINVAL;
187 }
188
189 bt_mesh_server_stop_transition(&srv->actual_transition);
190 srv->state->lightness_actual = value->light_lightness_actual.lightness;
191 /**
192 * Whenever the Light Lightness Actual state is changed with a non-transactional
193 * message or a completed sequence of transactional messages to a non-zero value,
194 * the value of the Light Lightness Last shall be set to the value of the Light
195 * Lightness Actual.
196 */
197 if (srv->state->lightness_actual) {
198 srv->state->lightness_last = srv->state->lightness_actual;
199 }
200 light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
201 break;
202 }
203 case LIGHT_LIGHTNESS_LINEAR_STATE: {
204 if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
205 BT_ERR("Invalid Light Lightness Server, model id 0x%04x", model->id);
206 return -EINVAL;
207 }
208
209 struct bt_mesh_light_lightness_srv *srv = model->user_data;
210 if (srv->state == NULL) {
211 BT_ERR("Invalid Light Lightness Server state");
212 return -EINVAL;
213 }
214
215 bt_mesh_server_stop_transition(&srv->linear_transition);
216 srv->state->lightness_linear = value->light_lightness_linear.lightness;
217 light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
218 break;
219 }
220 case LIGHT_CTL_LIGHTNESS_STATE: {
221 if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_SRV) {
222 BT_ERR("Invalid Light CTL Server, model id 0x%04x", model->id);
223 return -EINVAL;
224 }
225
226 struct bt_mesh_light_ctl_srv *srv = model->user_data;
227 if (srv->state == NULL) {
228 BT_ERR("Invalid Light CTL Server state");
229 return -EINVAL;
230 }
231
232 bt_mesh_server_stop_transition(&srv->transition);
233 srv->state->lightness = value->light_ctl_lightness.lightness;
234 light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
235 break;
236 }
237 case LIGHT_CTL_TEMP_DELTA_UV_STATE: {
238 if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV) {
239 BT_ERR("Invalid Light CTL Temperature Server, model id 0x%04x", model->id);
240 return -EINVAL;
241 }
242
243 struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
244 if (srv->state == NULL) {
245 BT_ERR("Invalid Light CTL Temperature Server state");
246 return -EINVAL;
247 }
248
249 bt_mesh_server_stop_transition(&srv->transition);
250 srv->state->temperature = value->light_ctl_temp_delta_uv.temperature;
251 srv->state->delta_uv = value->light_ctl_temp_delta_uv.delta_uv;
252 light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
253 break;
254 }
255 case LIGHT_HSL_STATE: {
256 if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
257 BT_ERR("Invalid Light HSL Server, model id 0x%04x", model->id);
258 return -EINVAL;
259 }
260
261 struct bt_mesh_light_hsl_srv *srv = model->user_data;
262 if (srv->state == NULL) {
263 BT_ERR("Invalid Light HSL Server state");
264 return -EINVAL;
265 }
266
267 bt_mesh_server_stop_transition(&srv->transition);
268 srv->state->lightness = value->light_hsl.lightness;
269 srv->state->hue = value->light_hsl.hue;
270 srv->state->saturation = value->light_hsl.saturation;
271 light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
272 break;
273 }
274 case LIGHT_HSL_LIGHTNESS_STATE: {
275 if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
276 BT_ERR("Invalid Light HSL Server, model id 0x%04x", model->id);
277 return -EINVAL;
278 }
279
280 struct bt_mesh_light_hsl_srv *srv = model->user_data;
281 if (srv->state == NULL) {
282 BT_ERR("Invalid Light HSL Server state");
283 return -EINVAL;
284 }
285
286 bt_mesh_server_stop_transition(&srv->transition);
287 srv->state->lightness = value->light_hsl_lightness.lightness;
288 light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
289 break;
290 }
291 case LIGHT_HSL_HUE_STATE: {
292 if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV) {
293 BT_ERR("Invalid Light HSL Hue Server, model id 0x%04x", model->id);
294 return -EINVAL;
295 }
296
297 struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
298 if (srv->state == NULL) {
299 BT_ERR("Invalid Light HSL Hue Server state");
300 return -EINVAL;
301 }
302
303 bt_mesh_server_stop_transition(&srv->transition);
304 srv->state->hue = value->light_hsl_hue.hue;
305 light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
306 break;
307 }
308 case LIGHT_HSL_SATURATION_STATE: {
309 if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV) {
310 BT_ERR("Invalid Light HSL Saturation Server, model id 0x%04x", model->id);
311 return -EINVAL;
312 }
313
314 struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
315 if (srv->state == NULL) {
316 BT_ERR("Invalid Light HSL Saturation Server state");
317 return -EINVAL;
318 }
319
320 bt_mesh_server_stop_transition(&srv->transition);
321 srv->state->saturation = value->light_hsl_saturation.saturation;
322 light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
323 break;
324 }
325 case LIGHT_XYL_LIGHTNESS_STATE: {
326 if (model->id != BLE_MESH_MODEL_ID_LIGHT_XYL_SRV) {
327 BT_ERR("Invalid Light xyL Server, model id 0x%04x", model->id);
328 return -EINVAL;
329 }
330
331 struct bt_mesh_light_xyl_srv *srv = model->user_data;
332 if (srv->state == NULL) {
333 BT_ERR("Invalid Light xyL Server state");
334 return -EINVAL;
335 }
336
337 bt_mesh_server_stop_transition(&srv->transition);
338 srv->state->lightness = value->light_xyl_lightness.lightness;
339 light_xyl_publish(model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
340 break;
341 }
342 case LIGHT_LC_LIGHT_ONOFF_STATE: {
343 if (model->id != BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
344 BT_ERR("Invalid Light LC Server, model id 0x%04x", model->id);
345 return -EINVAL;
346 }
347
348 struct bt_mesh_light_lc_srv *srv = model->user_data;
349 if (srv->lc == NULL) {
350 BT_ERR("Invalid Light LC Server state");
351 return -EINVAL;
352 }
353
354 bt_mesh_server_stop_transition(&srv->transition);
355 srv->lc->state.light_onoff = value->light_lc_light_onoff.onoff;
356 light_lc_publish(model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
357 break;
358 }
359 #endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */
360 default:
361 BT_WARN("Unknown binding state type 0x%02x", type);
362 return -EINVAL;
363 }
364
365 return 0;
366 }
367
368 #endif /* CONFIG_BLE_MESH_SERVER_MODEL */
369