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