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