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