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