1 /* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
2 *
3 * Copyright (c) 2018 Vikrant More
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include "ble_mesh.h"
9 #include "common.h"
10 #include "device_composition.h"
11 #include "state_binding.h"
12 #include "transition.h"
13
14 struct transition_data onoff_transition;
15
16 /* Function to calculate Remaining Time (Start) */
17
calculate_rt(struct transition_data * transition)18 void calculate_rt(struct transition_data *transition)
19 {
20 uint8_t steps, resolution;
21 int32_t duration_remainder;
22 int64_t now;
23
24 if (transition->type == MOVE) {
25 transition->rt = UNKNOWN_VALUE;
26 return;
27 }
28
29 if (transition->just_started) {
30 transition->rt = transition->tt;
31 } else {
32 now = k_uptime_get();
33 duration_remainder = transition->total_duration -
34 (now - transition->start_timestamp);
35
36 if (duration_remainder > 620000) {
37 /* > 620 seconds -> resolution = 0b11 [10 minutes] */
38 resolution = 0x03;
39 steps = duration_remainder / 600000;
40 } else if (duration_remainder > 62000) {
41 /* > 62 seconds -> resolution = 0b10 [10 seconds] */
42 resolution = 0x02;
43 steps = duration_remainder / 10000;
44 } else if (duration_remainder > 6200) {
45 /* > 6.2 seconds -> resolution = 0b01 [1 seconds] */
46 resolution = 0x01;
47 steps = duration_remainder / 1000;
48 } else if (duration_remainder > 0) {
49 /* <= 6.2 seconds -> resolution = 0b00 [100 ms] */
50 resolution = 0x00;
51 steps = duration_remainder / 100;
52 } else {
53 resolution = 0x00;
54 steps = 0x00;
55 }
56
57 transition->rt = (resolution << 6) | steps;
58 }
59 }
60
61 /* Function to calculate Remaining Time (End) */
62
set_transition_counter(struct transition_data * transition)63 static bool set_transition_counter(struct transition_data *transition)
64 {
65 uint8_t steps_multiplier, resolution;
66
67 resolution = (transition->tt >> 6);
68 steps_multiplier = (transition->tt & 0x3F);
69 if (steps_multiplier == 0U) {
70 return false;
71 }
72
73 switch (resolution) {
74 case 0: /* 100ms */
75 transition->total_duration = steps_multiplier * 100U;
76 break;
77 case 1: /* 1 second */
78 transition->total_duration = steps_multiplier * 1000U;
79 break;
80 case 2: /* 10 seconds */
81 transition->total_duration = steps_multiplier * 10000U;
82 break;
83 case 3: /* 10 minutes */
84 transition->total_duration = steps_multiplier * 600000U;
85 break;
86 }
87
88 transition->counter = ((float) transition->total_duration / 100);
89
90 if (transition->counter > DEVICE_SPECIFIC_RESOLUTION) {
91 transition->counter = DEVICE_SPECIFIC_RESOLUTION;
92 }
93
94 return true;
95 }
96
set_transition_values(uint8_t type)97 void set_transition_values(uint8_t type)
98 {
99 if (!set_transition_counter(ctl->transition)) {
100 return;
101 }
102
103 if (ctl->transition->type == MOVE) {
104 ctl->transition->quo_tt = ctl->transition->total_duration;
105 return;
106 }
107
108 ctl->transition->quo_tt = ctl->transition->total_duration /
109 ctl->transition->counter;
110
111 switch (type) {
112 case ONOFF:
113 case LEVEL_LIGHT:
114 case ACTUAL:
115 case LINEAR:
116 ctl->light->delta =
117 ((float) (ctl->light->current - ctl->light->target) /
118 ctl->transition->counter);
119 break;
120 case CTL_LIGHT:
121 ctl->light->delta =
122 ((float) (ctl->light->current - ctl->light->target) /
123 ctl->transition->counter);
124
125 ctl->temp->delta =
126 ((float) (ctl->temp->current - ctl->temp->target) /
127 ctl->transition->counter);
128
129 ctl->duv->delta =
130 ((float) (ctl->duv->current - ctl->duv->target) /
131 ctl->transition->counter);
132 break;
133 case LEVEL_TEMP:
134 ctl->temp->delta =
135 ((float) (ctl->temp->current - ctl->temp->target) /
136 ctl->transition->counter);
137 break;
138 case CTL_TEMP:
139 ctl->temp->delta =
140 ((float) (ctl->temp->current - ctl->temp->target) /
141 ctl->transition->counter);
142
143 ctl->duv->delta =
144 ((float) (ctl->duv->current - ctl->duv->target) /
145 ctl->transition->counter);
146 break;
147 default:
148 return;
149 }
150 }
151
152 /* Timers related handlers & threads (Start) */
onoff_work_handler(struct k_work * work)153 static void onoff_work_handler(struct k_work *work)
154 {
155 if (ctl->transition->just_started) {
156 ctl->transition->just_started = false;
157
158 if (ctl->transition->counter == 0U) {
159 update_light_state();
160 k_timer_stop(&ctl->transition->timer);
161 } else {
162 ctl->transition->start_timestamp = k_uptime_get();
163 }
164
165 return;
166 }
167
168 ctl->transition->counter--;
169 if (ctl->transition->counter) {
170 ctl->light->current -= ctl->light->delta;
171 update_light_state();
172 } else {
173 ctl->light->current = ctl->light->target;
174 update_light_state();
175 k_timer_stop(&ctl->transition->timer);
176 }
177 }
178
level_move_lightness_work_handler(void)179 static void level_move_lightness_work_handler(void)
180 {
181 int light;
182
183 light = 0;
184
185 if (ctl->light->current) {
186 light = ctl->light->current + ctl->light->delta;
187 } else {
188 if (ctl->light->delta < 0) {
189 light = UINT16_MAX + ctl->light->delta;
190 } else if (ctl->light->delta > 0) {
191 light = ctl->light->delta;
192 }
193 }
194
195 if (light > ctl->light->range_max) {
196 light = ctl->light->range_max;
197 } else if (light < ctl->light->range_min) {
198 light = ctl->light->range_min;
199 }
200
201 ctl->light->current = light;
202 update_light_state();
203
204 if (ctl->light->target == light) {
205 ctl->transition->counter = 0;
206 k_timer_stop(&ctl->transition->timer);
207 }
208 }
209
level_lightness_work_handler(struct k_work * work)210 static void level_lightness_work_handler(struct k_work *work)
211 {
212 if (ctl->transition->just_started) {
213 ctl->transition->just_started = false;
214
215 if (ctl->transition->counter == 0U) {
216 update_light_state();
217 k_timer_stop(&ctl->transition->timer);
218 } else {
219 ctl->transition->start_timestamp = k_uptime_get();
220 }
221
222 return;
223 }
224
225 if (ctl->transition->type == MOVE) {
226 level_move_lightness_work_handler();
227 return;
228 }
229
230 ctl->transition->counter--;
231 if (ctl->transition->counter) {
232 ctl->light->current -= ctl->light->delta;
233 update_light_state();
234 } else {
235 ctl->light->current = ctl->light->target;
236 update_light_state();
237 k_timer_stop(&ctl->transition->timer);
238 }
239 }
240
level_move_temp_work_handler(void)241 static void level_move_temp_work_handler(void)
242 {
243 int temp;
244
245 temp = 0;
246
247 if (ctl->temp->current) {
248 temp = ctl->temp->current + ctl->temp->delta;
249 } else {
250 if (ctl->temp->delta < 0) {
251 temp = UINT16_MAX + ctl->temp->delta;
252 } else if (ctl->temp->delta > 0) {
253 temp = ctl->temp->delta;
254 }
255 }
256
257 if (temp > ctl->temp->range_max) {
258 temp = ctl->temp->range_max;
259 } else if (temp < ctl->temp->range_min) {
260 temp = ctl->temp->range_min;
261 }
262
263 ctl->temp->current = temp;
264 update_light_state();
265
266 if (ctl->temp->target == temp) {
267 ctl->transition->counter = 0;
268 k_timer_stop(&ctl->transition->timer);
269 }
270 }
271
level_temp_work_handler(struct k_work * work)272 static void level_temp_work_handler(struct k_work *work)
273 {
274 if (ctl->transition->just_started) {
275 ctl->transition->just_started = false;
276
277 if (ctl->transition->counter == 0U) {
278 update_light_state();
279 k_timer_stop(&ctl->transition->timer);
280 } else {
281 ctl->transition->start_timestamp = k_uptime_get();
282 }
283
284 return;
285 }
286
287 if (ctl->transition->type == MOVE) {
288 level_move_temp_work_handler();
289 return;
290 }
291
292 ctl->transition->counter--;
293 if (ctl->transition->counter) {
294 ctl->temp->current -= ctl->temp->delta;
295 update_light_state();
296 } else {
297 ctl->temp->current = ctl->temp->target;
298 update_light_state();
299 k_timer_stop(&ctl->transition->timer);
300 }
301 }
302
light_lightness_actual_work_handler(struct k_work * work)303 static void light_lightness_actual_work_handler(struct k_work *work)
304 {
305 if (ctl->transition->just_started) {
306 ctl->transition->just_started = false;
307
308 if (ctl->transition->counter == 0U) {
309 update_light_state();
310 k_timer_stop(&ctl->transition->timer);
311 } else {
312 ctl->transition->start_timestamp = k_uptime_get();
313 }
314
315 return;
316 }
317
318 ctl->transition->counter--;
319 if (ctl->transition->counter) {
320 ctl->light->current -= ctl->light->delta;
321 update_light_state();
322 } else {
323 ctl->light->current = ctl->light->target;
324 update_light_state();
325 k_timer_stop(&ctl->transition->timer);
326 }
327 }
328
light_lightness_linear_work_handler(struct k_work * work)329 static void light_lightness_linear_work_handler(struct k_work *work)
330 {
331 if (ctl->transition->just_started) {
332 ctl->transition->just_started = false;
333
334 if (ctl->transition->counter == 0U) {
335 update_light_state();
336 k_timer_stop(&ctl->transition->timer);
337 } else {
338 ctl->transition->start_timestamp = k_uptime_get();
339 }
340
341 return;
342 }
343
344 ctl->transition->counter--;
345 if (ctl->transition->counter) {
346 ctl->light->current -= ctl->light->delta;
347 update_light_state();
348 } else {
349 ctl->light->current = ctl->light->target;
350 update_light_state();
351 k_timer_stop(&ctl->transition->timer);
352 }
353 }
354
light_ctl_work_handler(struct k_work * work)355 static void light_ctl_work_handler(struct k_work *work)
356 {
357 if (ctl->transition->just_started) {
358 ctl->transition->just_started = false;
359
360 if (ctl->transition->counter == 0U) {
361 update_light_state();
362 k_timer_stop(&ctl->transition->timer);
363 } else {
364 ctl->transition->start_timestamp = k_uptime_get();
365 }
366
367 return;
368 }
369
370 ctl->transition->counter--;
371 if (ctl->transition->counter) {
372 /* Lightness */
373 ctl->light->current -= ctl->light->delta;
374 /* Temperature */
375 ctl->temp->current -= ctl->temp->delta;
376 /* Delta_UV */
377 ctl->duv->current -= ctl->duv->delta;
378 update_light_state();
379 } else {
380 ctl->light->current = ctl->light->target;
381 ctl->temp->current = ctl->temp->target;
382 ctl->duv->current = ctl->duv->target;
383 update_light_state();
384 k_timer_stop(&ctl->transition->timer);
385 }
386 }
387
light_ctl_temp_work_handler(struct k_work * work)388 static void light_ctl_temp_work_handler(struct k_work *work)
389 {
390 if (ctl->transition->just_started) {
391 ctl->transition->just_started = false;
392
393 if (ctl->transition->counter == 0U) {
394 update_light_state();
395 k_timer_stop(&ctl->transition->timer);
396 } else {
397 ctl->transition->start_timestamp = k_uptime_get();
398 }
399
400 return;
401 }
402
403 ctl->transition->counter--;
404 if (ctl->transition->counter) {
405 /* Temperature */
406 ctl->temp->current -= ctl->temp->delta;
407 /* Delta_UV */
408 ctl->duv->current -= ctl->duv->delta;
409 update_light_state();
410 } else {
411 ctl->temp->current = ctl->temp->target;
412 ctl->duv->current = ctl->duv->target;
413 update_light_state();
414 k_timer_stop(&ctl->transition->timer);
415 }
416 }
417
418
419 K_WORK_DEFINE(onoff_work, onoff_work_handler);
420 K_WORK_DEFINE(level_lightness_work, level_lightness_work_handler);
421 K_WORK_DEFINE(level_temp_work, level_temp_work_handler);
422 K_WORK_DEFINE(light_lightness_actual_work, light_lightness_actual_work_handler);
423 K_WORK_DEFINE(light_lightness_linear_work, light_lightness_linear_work_handler);
424 K_WORK_DEFINE(light_ctl_work, light_ctl_work_handler);
425 K_WORK_DEFINE(light_ctl_temp_work, light_ctl_temp_work_handler);
426
onoff_tt_handler(struct k_timer * dummy)427 static void onoff_tt_handler(struct k_timer *dummy)
428 {
429 k_work_submit(&onoff_work);
430 }
431
level_lightness_tt_handler(struct k_timer * dummy)432 static void level_lightness_tt_handler(struct k_timer *dummy)
433 {
434 k_work_submit(&level_lightness_work);
435 }
436
level_temp_tt_handler(struct k_timer * dummy)437 static void level_temp_tt_handler(struct k_timer *dummy)
438 {
439 k_work_submit(&level_temp_work);
440 }
441
light_lightness_actual_tt_handler(struct k_timer * dummy)442 static void light_lightness_actual_tt_handler(struct k_timer *dummy)
443 {
444 k_work_submit(&light_lightness_actual_work);
445 }
446
light_lightness_linear_tt_handler(struct k_timer * dummy)447 static void light_lightness_linear_tt_handler(struct k_timer *dummy)
448 {
449 k_work_submit(&light_lightness_linear_work);
450 }
451
light_ctl_tt_handler(struct k_timer * dummy)452 static void light_ctl_tt_handler(struct k_timer *dummy)
453 {
454 k_work_submit(&light_ctl_work);
455 }
456
light_ctl_temp_tt_handler(struct k_timer * dummy)457 static void light_ctl_temp_tt_handler(struct k_timer *dummy)
458 {
459 k_work_submit(&light_ctl_temp_work);
460 }
461 /* Timers related handlers & threads (End) */
462
463 K_TIMER_DEFINE(dummy_timer, NULL, NULL);
464
465 /* Messages handlers (Start) */
onoff_handler(void)466 void onoff_handler(void)
467 {
468 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
469 update_light_state();
470 return;
471 }
472
473 k_timer_init(&ctl->transition->timer, onoff_tt_handler, NULL);
474
475 k_timer_start(&ctl->transition->timer,
476 K_MSEC(ctl->transition->delay * 5U),
477 K_MSEC(ctl->transition->quo_tt));
478 }
479
level_lightness_handler(void)480 void level_lightness_handler(void)
481 {
482 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
483 update_light_state();
484 return;
485 }
486
487 k_timer_init(&ctl->transition->timer,
488 level_lightness_tt_handler, NULL);
489
490 k_timer_start(&ctl->transition->timer,
491 K_MSEC(ctl->transition->delay * 5U),
492 K_MSEC(ctl->transition->quo_tt));
493 }
494
level_temp_handler(void)495 void level_temp_handler(void)
496 {
497 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
498 update_light_state();
499 return;
500 }
501
502 k_timer_init(&ctl->transition->timer, level_temp_tt_handler, NULL);
503
504 k_timer_start(&ctl->transition->timer,
505 K_MSEC(ctl->transition->delay * 5U),
506 K_MSEC(ctl->transition->quo_tt));
507 }
508
light_lightness_actual_handler(void)509 void light_lightness_actual_handler(void)
510 {
511 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
512 update_light_state();
513 return;
514 }
515
516 k_timer_init(&ctl->transition->timer,
517 light_lightness_actual_tt_handler, NULL);
518
519 k_timer_start(&ctl->transition->timer,
520 K_MSEC(ctl->transition->delay * 5U),
521 K_MSEC(ctl->transition->quo_tt));
522 }
523
light_lightness_linear_handler(void)524 void light_lightness_linear_handler(void)
525 {
526 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
527 update_light_state();
528 return;
529 }
530
531 k_timer_init(&ctl->transition->timer,
532 light_lightness_linear_tt_handler, NULL);
533
534 k_timer_start(&ctl->transition->timer,
535 K_MSEC(ctl->transition->delay * 5U),
536 K_MSEC(ctl->transition->quo_tt));
537 }
538
light_ctl_handler(void)539 void light_ctl_handler(void)
540 {
541 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
542 update_light_state();
543 return;
544 }
545
546 k_timer_init(&ctl->transition->timer, light_ctl_tt_handler, NULL);
547
548 k_timer_start(&ctl->transition->timer,
549 K_MSEC(ctl->transition->delay * 5U),
550 K_MSEC(ctl->transition->quo_tt));
551 }
552
light_ctl_temp_handler(void)553 void light_ctl_temp_handler(void)
554 {
555 if (ctl->transition->counter == 0U && ctl->transition->delay == 0) {
556 update_light_state();
557 return;
558 }
559
560 k_timer_init(&ctl->transition->timer,
561 light_ctl_temp_tt_handler, NULL);
562
563 k_timer_start(&ctl->transition->timer,
564 K_MSEC(ctl->transition->delay * 5U),
565 K_MSEC(ctl->transition->quo_tt));
566 }
567 /* Messages handlers (End) */
568