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 "common.h"
9 #include "ble_mesh.h"
10 #include "device_composition.h"
11 #include "state_binding.h"
12 #include "transition.h"
13
14 u8_t enable_transition;
15 u8_t default_tt;
16
17 struct ble_npl_callout onoff_work;
18 struct ble_npl_callout level_lightness_work;
19 struct ble_npl_callout level_temp_work;
20 struct ble_npl_callout light_lightness_actual_work;
21 struct ble_npl_callout light_lightness_linear_work;
22 struct ble_npl_callout light_ctl_work;
23 struct ble_npl_callout light_ctl_temp_work;
24
25 struct ble_npl_callout onoff_transition_timer;
26 struct ble_npl_callout level_lightness_transition_timer;
27 struct ble_npl_callout level_temp_transition_timer;
28 struct ble_npl_callout light_lightness_actual_transition_timer;
29 struct ble_npl_callout light_lightness_linear_transition_timer;
30 struct ble_npl_callout light_ctl_transition_timer;
31 struct ble_npl_callout light_ctl_temp_transition_timer;
32
tt_counter_calculator(u8_t * tt,u32_t * cal_tt)33 static u32_t tt_counter_calculator(u8_t *tt, u32_t *cal_tt)
34 {
35 u8_t steps_multiplier, resolution;
36 u32_t tt_counter;
37
38 resolution = ((*tt) >> 6);
39 steps_multiplier = (*tt) & 0x3F;
40
41 switch (resolution) {
42 case 0: /* 100ms */
43 *cal_tt = steps_multiplier * 100;
44 break;
45 case 1: /* 1 second */
46 *cal_tt = steps_multiplier * 1000;
47 break;
48 case 2: /* 10 seconds */
49 *cal_tt = steps_multiplier * 10000;
50 break;
51 case 3: /* 10 minutes */
52 *cal_tt = steps_multiplier * 600000;
53 break;
54 }
55
56 tt_counter = ((float) *cal_tt / 100);
57
58 if (tt_counter > DEVICE_SPECIFIC_RESOLUTION) {
59 tt_counter = DEVICE_SPECIFIC_RESOLUTION;
60 }
61
62 if (tt_counter != 0) {
63 *cal_tt = *cal_tt / tt_counter;
64 }
65
66 return tt_counter;
67 }
68
onoff_tt_values(struct generic_onoff_state * state)69 void onoff_tt_values(struct generic_onoff_state *state)
70 {
71 state->tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
72 }
73
level_tt_values(struct generic_level_state * state)74 void level_tt_values(struct generic_level_state *state)
75 {
76 u32_t tt_counter;
77
78 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
79 state->tt_counter = tt_counter;
80
81 if (tt_counter == 0) {
82 tt_counter = 1;
83 }
84
85 state->tt_delta = ((float) (state->level - state->target_level) /
86 tt_counter);
87 }
88
delta_level_tt_values(struct generic_level_state * state)89 void delta_level_tt_values(struct generic_level_state *state)
90 {
91 u32_t tt_counter;
92
93 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
94 state->tt_counter_delta = tt_counter;
95
96 if (tt_counter == 0) {
97 tt_counter = 1;
98 }
99
100 state->tt_delta = ((float) state->last_delta / tt_counter);
101
102 state->tt_delta *= -1;
103 }
104
move_level_tt_values(struct generic_level_state * state)105 void move_level_tt_values(struct generic_level_state *state)
106 {
107 u32_t tt_counter;
108
109 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
110 state->tt_counter_move = tt_counter;
111
112 if (tt_counter == 0) {
113 tt_counter = 1;
114 }
115
116 state->tt_delta = ((float) state->last_delta / tt_counter);
117
118 state->tt_delta *= -1;
119 }
120
light_lightnes_actual_tt_values(struct light_lightness_state * state)121 void light_lightnes_actual_tt_values(struct light_lightness_state *state)
122 {
123 u32_t tt_counter;
124
125 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
126 state->tt_counter_actual = tt_counter;
127
128 if (tt_counter == 0) {
129 tt_counter = 1;
130 }
131
132 state->tt_delta_actual =
133 ((float) (state->actual - state->target_actual) /
134 tt_counter);
135 }
136
light_lightnes_linear_tt_values(struct light_lightness_state * state)137 void light_lightnes_linear_tt_values(struct light_lightness_state *state)
138 {
139 u32_t tt_counter;
140
141 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
142 state->tt_counter_linear = tt_counter;
143
144 if (tt_counter == 0) {
145 tt_counter = 1;
146 }
147
148 state->tt_delta_linear =
149 ((float) (state->linear - state->target_linear) /
150 tt_counter);
151 }
152
light_ctl_tt_values(struct light_ctl_state * state)153 void light_ctl_tt_values(struct light_ctl_state *state)
154 {
155 u32_t tt_counter;
156
157 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
158 state->tt_counter = tt_counter;
159
160 if (tt_counter == 0) {
161 tt_counter = 1;
162 }
163
164 state->tt_lightness_delta =
165 ((float) (state->lightness - state->target_lightness) /
166 tt_counter);
167
168 state->tt_temp_delta =
169 ((float) (state->temp - state->target_temp) /
170 tt_counter);
171
172 state->tt_duv_delta =
173 ((float) (state->delta_uv - state->target_delta_uv) /
174 tt_counter);
175 }
176
light_ctl_temp_tt_values(struct light_ctl_state * state)177 void light_ctl_temp_tt_values(struct light_ctl_state *state)
178 {
179 u32_t tt_counter;
180
181 tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
182 state->tt_counter_temp = tt_counter;
183
184 if (tt_counter == 0) {
185 tt_counter = 1;
186 }
187
188 state->tt_temp_delta = ((float) (state->temp - state->target_temp) /
189 tt_counter);
190
191 state->tt_duv_delta =
192 ((float) (state->delta_uv - state->target_delta_uv) /
193 tt_counter);
194 }
195
196 /* Timers related handlers & threads (Start) */
onoff_work_handler(struct ble_npl_event * work)197 static void onoff_work_handler(struct ble_npl_event *work)
198 {
199 struct generic_onoff_state *state = &gen_onoff_srv_root_user_data;
200
201 if (enable_transition != ONOFF_TT) {
202 ble_npl_callout_stop(&onoff_transition_timer);
203 return;
204 }
205
206 if (state->tt_counter != 0) {
207 state->tt_counter--;
208
209 if (state->target_onoff == STATE_ON) {
210 state->onoff = STATE_ON;
211
212 state_binding(ONOFF, IGNORE_TEMP);
213 update_light_state();
214
215 enable_transition = DISABLE_TRANSITION;
216 }
217 }
218
219 if (state->tt_counter == 0) {
220 state->onoff = state->target_onoff;
221
222 state_binding(ONOFF, IGNORE_TEMP);
223 update_light_state();
224
225 ble_npl_callout_stop(&onoff_transition_timer);
226 }
227 }
228
level_lightness_work_handler(struct ble_npl_event * work)229 static void level_lightness_work_handler(struct ble_npl_event *work)
230 {
231 u32_t *tt_counter;
232 struct generic_level_state *state = &gen_level_srv_root_user_data;
233
234 tt_counter = NULL;
235
236 switch (enable_transition) {
237 case LEVEL_TT:
238 tt_counter = &state->tt_counter;
239 break;
240 case LEVEL_TT_DELTA:
241 tt_counter = &state->tt_counter_delta;
242 break;
243 case LEVEL_TT_MOVE:
244 tt_counter = &state->tt_counter_move;
245 break;
246 default:
247 ble_npl_callout_stop(&level_lightness_transition_timer);
248 return;
249 }
250
251 if (*tt_counter != 0) {
252 s32_t lightness;
253
254 (*tt_counter)--;
255
256 lightness = state->level - state->tt_delta;
257
258 if (lightness > INT16_MAX) {
259 lightness = INT16_MAX;
260 } else if (lightness < INT16_MIN) {
261 lightness = INT16_MIN;
262 }
263
264 if (state->level != lightness) {
265 state->level = lightness;
266
267 state_binding(LEVEL, IGNORE_TEMP);
268 update_light_state();
269 } else {
270 enable_transition = DISABLE_TRANSITION;
271 }
272 }
273
274 if (*tt_counter == 0) {
275 state->level = state->target_level;
276
277 state_binding(LEVEL, IGNORE_TEMP);
278 update_light_state();
279
280 ble_npl_callout_stop(&level_lightness_transition_timer);
281 }
282 }
283
level_temp_work_handler(struct ble_npl_event * work)284 static void level_temp_work_handler(struct ble_npl_event *work)
285 {
286 u32_t *tt_counter;
287 struct generic_level_state *state = &gen_level_srv_s0_user_data;
288
289 tt_counter = NULL;
290
291 switch (enable_transition) {
292 case LEVEL_TT:
293 tt_counter = &state->tt_counter;
294 break;
295 case LEVEL_TT_DELTA:
296 tt_counter = &state->tt_counter_delta;
297 break;
298 case LEVEL_TT_MOVE:
299 tt_counter = &state->tt_counter_move;
300 break;
301 default:
302 ble_npl_callout_stop(&level_temp_transition_timer);
303 return;
304 }
305
306 if (*tt_counter != 0) {
307 s32_t temp;
308
309 (*tt_counter)--;
310
311 temp = state->level - state->tt_delta;
312
313 if (temp > INT16_MAX) {
314 temp = INT16_MAX;
315 } else if (temp < INT16_MIN) {
316 temp = INT16_MIN;
317 }
318
319 if (state->level != temp) {
320 state->level = temp;
321
322 state_binding(IGNORE, LEVEL_TEMP);
323 update_light_state();
324 } else {
325 enable_transition = DISABLE_TRANSITION;
326 }
327 }
328
329 if (*tt_counter == 0) {
330 state->level = state->target_level;
331
332 state_binding(IGNORE, LEVEL_TEMP);
333 update_light_state();
334
335 ble_npl_callout_stop(&level_temp_transition_timer);
336 }
337 }
338
light_lightness_actual_work_handler(struct ble_npl_event * work)339 static void light_lightness_actual_work_handler(struct ble_npl_event *work)
340 {
341 struct light_lightness_state *state = &light_lightness_srv_user_data;
342
343 if (enable_transition != LIGTH_LIGHTNESS_ACTUAL_TT) {
344 ble_npl_callout_stop(&light_lightness_actual_transition_timer);
345 return;
346 }
347
348 if (state->tt_counter_actual != 0) {
349 u32_t actual;
350
351 state->tt_counter_actual--;
352
353 actual = state->actual - state->tt_delta_actual;
354
355 if (state->actual != actual) {
356 state->actual = actual;
357
358 state_binding(ACTUAL, IGNORE_TEMP);
359 update_light_state();
360 } else {
361 enable_transition = DISABLE_TRANSITION;
362 }
363 }
364
365 if (state->tt_counter_actual == 0) {
366 state->actual = state->target_actual;
367
368 state_binding(ACTUAL, IGNORE_TEMP);
369 update_light_state();
370
371 ble_npl_callout_stop(&light_lightness_actual_transition_timer);
372 }
373 }
374
light_lightness_linear_work_handler(struct ble_npl_event * work)375 static void light_lightness_linear_work_handler(struct ble_npl_event *work)
376 {
377 struct light_lightness_state *state = &light_lightness_srv_user_data;
378
379 if (enable_transition != LIGTH_LIGHTNESS_LINEAR_TT) {
380 ble_npl_callout_stop(&light_lightness_linear_transition_timer);
381 return;
382 }
383
384 if (state->tt_counter_linear != 0) {
385 u32_t linear;
386
387 state->tt_counter_linear--;
388
389 linear = state->linear - state->tt_delta_linear;
390
391 if (state->linear != linear) {
392 state->linear = linear;
393
394 state_binding(LINEAR, IGNORE_TEMP);
395 update_light_state();
396 } else {
397 enable_transition = DISABLE_TRANSITION;
398 }
399 }
400
401 if (state->tt_counter_linear == 0) {
402 state->linear = state->target_linear;
403
404 state_binding(LINEAR, IGNORE_TEMP);
405 update_light_state();
406
407 ble_npl_callout_stop(&light_lightness_linear_transition_timer);
408 }
409 }
410
light_ctl_work_handler(struct ble_npl_event * work)411 static void light_ctl_work_handler(struct ble_npl_event *work)
412 {
413 struct light_ctl_state *state = &light_ctl_srv_user_data;
414
415 if (enable_transition != LIGTH_CTL_TT) {
416 ble_npl_callout_stop(&light_ctl_transition_timer);
417 return;
418 }
419
420 if (state->tt_counter != 0) {
421 u32_t lightness, temp;
422 s32_t delta_uv;
423
424 state->tt_counter--;
425
426 /* Lightness */
427 lightness = state->lightness - state->tt_lightness_delta;
428
429 /* Temperature */
430 temp = state->temp - state->tt_temp_delta;
431
432 /* Delta_UV */
433 delta_uv = state->delta_uv - state->tt_duv_delta;
434
435 if (delta_uv > INT16_MAX) {
436 delta_uv = INT16_MAX;
437 } else if (delta_uv < INT16_MIN) {
438 delta_uv = INT16_MIN;
439 }
440
441 if (state->lightness != lightness || state->temp != temp ||
442 state->delta_uv != delta_uv) {
443 state->lightness = lightness;
444 state->temp = temp;
445 state->delta_uv = delta_uv;
446
447 state_binding(CTL, CTL_TEMP);
448 update_light_state();
449 } else {
450 enable_transition = DISABLE_TRANSITION;
451 }
452 }
453
454 if (state->tt_counter == 0) {
455 state->lightness = state->target_lightness;
456 state->temp = state->target_temp;
457 state->delta_uv = state->target_delta_uv;
458
459 state_binding(CTL, CTL_TEMP);
460 update_light_state();
461
462 ble_npl_callout_stop(&light_ctl_transition_timer);
463 }
464 }
465
light_ctl_temp_work_handler(struct ble_npl_event * work)466 static void light_ctl_temp_work_handler(struct ble_npl_event *work)
467 {
468 struct light_ctl_state *state = &light_ctl_srv_user_data;
469
470 if (enable_transition != LIGHT_CTL_TEMP_TT) {
471 ble_npl_callout_stop(&light_ctl_temp_transition_timer);
472 return;
473 }
474
475 if (state->tt_counter_temp != 0) {
476 s32_t delta_uv;
477 u32_t temp;
478
479 state->tt_counter_temp--;
480
481 /* Temperature */
482 temp = state->temp - state->tt_temp_delta;
483
484 /* Delta UV */
485 delta_uv = state->delta_uv - state->tt_duv_delta;
486
487 if (delta_uv > INT16_MAX) {
488 delta_uv = INT16_MAX;
489 } else if (delta_uv < INT16_MIN) {
490 delta_uv = INT16_MIN;
491 }
492
493 if (state->temp != temp || state->delta_uv != delta_uv) {
494 state->temp = temp;
495 state->delta_uv = delta_uv;
496
497 state_binding(IGNORE, CTL_TEMP);
498 update_light_state();
499 } else {
500 enable_transition = DISABLE_TRANSITION;
501 }
502 }
503
504 if (state->tt_counter_temp == 0) {
505 state->temp = state->target_temp;
506 state->delta_uv = state->target_delta_uv;
507
508 state_binding(IGNORE, CTL_TEMP);
509 update_light_state();
510
511 ble_npl_callout_stop(&light_ctl_temp_transition_timer);
512 }
513 }
514
onoff_tt_handler(struct ble_npl_event * ev)515 static void onoff_tt_handler(struct ble_npl_event *ev)
516 {
517 struct generic_onoff_state *state = ble_npl_event_get_arg(ev);
518
519 assert(state != NULL);
520 ble_npl_callout_reset(&onoff_work, 0);
521 ble_npl_callout_reset(&onoff_transition_timer, K_MSEC(state->cal_tt));
522 }
523
level_lightness_tt_handler(struct ble_npl_event * ev)524 static void level_lightness_tt_handler(struct ble_npl_event *ev)
525 {
526 struct generic_level_state *state = ble_npl_event_get_arg(ev);
527
528 assert(state != NULL);
529 ble_npl_callout_reset(&level_lightness_work, 0);
530 ble_npl_callout_reset(&level_lightness_transition_timer, K_MSEC(state->cal_tt));
531 }
532
level_temp_tt_handler(struct ble_npl_event * ev)533 static void level_temp_tt_handler(struct ble_npl_event *ev)
534 {
535 struct generic_level_state *state = ble_npl_event_get_arg(ev);
536
537 assert(state != NULL);
538 ble_npl_callout_reset(&level_temp_work, 0);
539 ble_npl_callout_reset(&level_temp_transition_timer, K_MSEC(state->cal_tt));
540 }
541
light_lightness_actual_tt_handler(struct ble_npl_event * ev)542 static void light_lightness_actual_tt_handler(struct ble_npl_event *ev)
543 {
544 struct light_lightness_state *state = ble_npl_event_get_arg(ev);
545
546 assert(state != NULL);
547 ble_npl_callout_reset(&light_lightness_actual_work, 0);
548 ble_npl_callout_reset(&light_lightness_actual_transition_timer, K_MSEC(state->cal_tt));
549 }
550
light_lightness_linear_tt_handler(struct ble_npl_event * ev)551 static void light_lightness_linear_tt_handler(struct ble_npl_event *ev)
552 {
553 struct light_lightness_state *state = ble_npl_event_get_arg(ev);
554
555 assert(state != NULL);
556 ble_npl_callout_reset(&light_lightness_linear_work, 0);
557 ble_npl_callout_reset(&light_lightness_linear_transition_timer, K_MSEC(state->cal_tt));
558 }
559
light_ctl_tt_handler(struct ble_npl_event * ev)560 static void light_ctl_tt_handler(struct ble_npl_event *ev)
561 {
562 struct light_ctl_state *state = ble_npl_event_get_arg(ev);
563
564 assert(state != NULL);
565 ble_npl_callout_reset(&light_ctl_work, 0);
566 ble_npl_callout_reset(&light_ctl_transition_timer, K_MSEC(state->cal_tt));
567 }
568
light_ctl_temp_tt_handler(struct ble_npl_event * ev)569 static void light_ctl_temp_tt_handler(struct ble_npl_event *ev)
570 {
571 struct light_ctl_state *state = ble_npl_event_get_arg(ev);
572
573 assert(state != NULL);
574 ble_npl_callout_reset(&light_ctl_temp_work, 0);
575 ble_npl_callout_reset(&light_ctl_temp_transition_timer, K_MSEC(state->cal_tt));
576 }
577 /* Timers related handlers & threads (End) */
578
579 /* Messages handlers (Start) */
onoff_handler(struct generic_onoff_state * state)580 void onoff_handler(struct generic_onoff_state *state)
581 {
582 enable_transition = ONOFF_TT;
583
584 ble_npl_callout_set_arg(&onoff_transition_timer, state);
585 ble_npl_callout_reset(&onoff_transition_timer, K_MSEC(5 * state->delay));
586 }
587
level_lightness_handler(struct generic_level_state * state)588 void level_lightness_handler(struct generic_level_state *state)
589 {
590 ble_npl_callout_set_arg(&level_lightness_transition_timer, state);
591 ble_npl_callout_reset(&level_lightness_transition_timer,
592 K_MSEC(5 * state->delay));
593 }
594
level_temp_handler(struct generic_level_state * state)595 void level_temp_handler(struct generic_level_state *state)
596 {
597 ble_npl_callout_set_arg(&level_temp_transition_timer, state);
598 ble_npl_callout_reset(&level_temp_transition_timer, K_MSEC(5 * state->delay));
599 }
600
light_lightness_actual_handler(struct light_lightness_state * state)601 void light_lightness_actual_handler(struct light_lightness_state *state)
602 {
603 enable_transition = LIGTH_LIGHTNESS_ACTUAL_TT;
604
605 ble_npl_callout_set_arg(&light_lightness_actual_transition_timer, state);
606 ble_npl_callout_reset(&light_lightness_actual_transition_timer,
607 K_MSEC(5 * state->delay));
608 }
609
light_lightness_linear_handler(struct light_lightness_state * state)610 void light_lightness_linear_handler(struct light_lightness_state *state)
611 {
612 enable_transition = LIGTH_LIGHTNESS_LINEAR_TT;
613
614 ble_npl_callout_set_arg(&light_lightness_linear_transition_timer, state);
615 ble_npl_callout_reset(&light_lightness_linear_transition_timer,
616 K_MSEC(5 * state->delay));
617 }
618
light_ctl_handler(struct light_ctl_state * state)619 void light_ctl_handler(struct light_ctl_state *state)
620 {
621 enable_transition = LIGTH_CTL_TT;
622
623 ble_npl_callout_set_arg(&light_ctl_transition_timer, state);
624 ble_npl_callout_reset(&light_ctl_transition_timer, K_MSEC(5 * state->delay));
625 }
626
light_ctl_temp_handler(struct light_ctl_state * state)627 void light_ctl_temp_handler(struct light_ctl_state *state)
628 {
629 enable_transition = LIGHT_CTL_TEMP_TT;
630
631 ble_npl_callout_set_arg(&light_ctl_temp_transition_timer, state);
632 ble_npl_callout_reset(&light_ctl_temp_transition_timer,
633 K_MSEC(5 * state->delay));
634 }
635 /* Messages handlers (End) */
636
transition_timers_init(void)637 void transition_timers_init(void)
638 {
639 ble_npl_callout_init(&onoff_work, ble_npl_eventq_dflt_get(),
640 onoff_work_handler, NULL);
641
642 ble_npl_callout_init(&level_lightness_work, ble_npl_eventq_dflt_get(),
643 level_lightness_work_handler, NULL);
644 ble_npl_callout_init(&level_temp_work, ble_npl_eventq_dflt_get(),
645 level_temp_work_handler, NULL);
646
647 ble_npl_callout_init(&light_lightness_actual_work, ble_npl_eventq_dflt_get(),
648 light_lightness_actual_work_handler, NULL);
649 ble_npl_callout_init(&light_lightness_linear_work, ble_npl_eventq_dflt_get(),
650 light_lightness_linear_work_handler, NULL);
651
652 ble_npl_callout_init(&light_ctl_work, ble_npl_eventq_dflt_get(),
653 light_ctl_work_handler, NULL);
654 ble_npl_callout_init(&light_ctl_temp_work, ble_npl_eventq_dflt_get(),
655 light_ctl_temp_work_handler, NULL);
656
657 ble_npl_callout_init(&onoff_transition_timer, ble_npl_eventq_dflt_get(),
658 onoff_tt_handler, NULL);
659
660 ble_npl_callout_init(&level_lightness_transition_timer, ble_npl_eventq_dflt_get(),
661 level_lightness_tt_handler, NULL);
662 ble_npl_callout_init(&level_temp_transition_timer, ble_npl_eventq_dflt_get(),
663 level_temp_tt_handler, NULL);
664
665 ble_npl_callout_init(&light_lightness_actual_transition_timer, ble_npl_eventq_dflt_get(),
666 light_lightness_actual_tt_handler, NULL);
667 ble_npl_callout_init(&light_lightness_linear_transition_timer, ble_npl_eventq_dflt_get(),
668 light_lightness_linear_tt_handler, NULL);
669
670 ble_npl_callout_init(&light_ctl_transition_timer, ble_npl_eventq_dflt_get(),
671 light_ctl_tt_handler, NULL);
672 ble_npl_callout_init(&light_ctl_temp_transition_timer, ble_npl_eventq_dflt_get(),
673 light_ctl_temp_tt_handler, NULL);
674
675 ble_npl_callout_init(&light_ctl_temp_transition_timer, ble_npl_eventq_dflt_get(),
676 light_ctl_temp_tt_handler, NULL);
677
678 }