A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 * Additional work by Martin Ritter (2007) and Thomas Martitz (2008)
12 * for backlight thread fading
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "config.h"
24#if !defined(BOOTLOADER)
25#include "settings.h"
26#include "action.h"
27#endif
28#include <stdlib.h>
29#include "cpu.h"
30#include "kernel.h"
31#include "thread.h"
32#include "i2c.h"
33#include "debug.h"
34#include "rtc.h"
35#include "usb.h"
36#include "power.h"
37#include "system.h"
38#include "button.h"
39#include "timer.h"
40#include "backlight.h"
41#include "lcd.h"
42#include "screendump.h"
43
44#ifdef HAVE_REMOTE_LCD
45#include "lcd-remote.h"
46#endif
47
48#ifndef SIMULATOR
49/*
50 Device specific implementation:
51 bool backlight_hw_init(void);
52 void backlight_hw_on(void);
53 void backlight_hw_off(void);
54 void backlight_hw_brightness(int brightness);
55*/
56#include "backlight-target.h"
57#else
58#include "backlight-sim.h"
59#endif
60
61#if defined(HAVE_BACKLIGHT) && defined(BACKLIGHT_FULL_INIT)
62
63#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
64 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
65#include "backlight-sw-fading.h"
66#endif
67
68#define BACKLIGHT_FADE_IN_THREAD \
69 (CONFIG_BACKLIGHT_FADING & (BACKLIGHT_FADING_SW_SETTING \
70 |BACKLIGHT_FADING_SW_HW_REG \
71 |BACKLIGHT_FADING_PWM) )
72
73#define BACKLIGHT_THREAD_TIMEOUT HZ
74
75enum {
76 BACKLIGHT_ON,
77 BACKLIGHT_OFF,
78 BACKLIGHT_TMO_CHANGED,
79#ifdef HAVE_BACKLIGHT_BRIGHTNESS
80 BACKLIGHT_BRIGHTNESS_CHANGED,
81#endif
82#ifdef HAVE_REMOTE_LCD
83 REMOTE_BACKLIGHT_ON,
84 REMOTE_BACKLIGHT_OFF,
85 REMOTE_BACKLIGHT_TMO_CHANGED,
86#endif
87#if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
88 BACKLIGHT_FADE_FINISH,
89#endif
90#ifdef HAVE_LCD_SLEEP
91 LCD_SLEEP,
92#endif
93#ifdef HAVE_BUTTON_LIGHT
94 BUTTON_LIGHT_ON,
95 BUTTON_LIGHT_OFF,
96 BUTTON_LIGHT_TMO_CHANGED,
97#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
98 BUTTON_LIGHT_BRIGHTNESS_CHANGED,
99#endif
100#endif /* HAVE_BUTTON_LIGHT */
101#ifdef BACKLIGHT_DRIVER_CLOSE
102 BACKLIGHT_QUIT,
103#endif
104};
105
106static void backlight_thread(void);
107static long backlight_stack[DEFAULT_STACK_SIZE/sizeof(long)];
108static const char backlight_thread_name[] = "backlight";
109static struct event_queue backlight_queue SHAREDBSS_ATTR;
110static bool ignore_backlight_on = false;
111static int backlight_ignored_timer = 0;
112#ifdef BACKLIGHT_DRIVER_CLOSE
113static unsigned int backlight_thread_id = 0;
114#endif
115
116#ifdef HAVE_BACKLIGHT_BRIGHTNESS
117int backlight_brightness = DEFAULT_BRIGHTNESS_SETTING;
118#endif
119static int backlight_timer SHAREDBSS_ATTR;
120static int backlight_timeout_normal = 5*HZ;
121#if CONFIG_CHARGING
122static int backlight_timeout_plugged = 5*HZ;
123#endif
124static int backlight_on_button_hold = 0;
125static void backlight_handle_timeout(void);
126
127#ifdef HAVE_BUTTON_LIGHT
128static int buttonlight_timer;
129static int buttonlight_timeout = 5*HZ;
130static bool ignore_buttonlight_on = false;
131static int buttonlight_ignored_timer = 0;
132
133/* Update state of buttonlight according to timeout setting */
134static void buttonlight_update_state(void)
135{
136 buttonlight_timer = buttonlight_timeout;
137
138 /* Buttonlight == OFF in the setting? */
139 if (buttonlight_timer < 0)
140 {
141 buttonlight_timer = 0; /* Disable the timeout */
142 buttonlight_hw_off();
143 }
144 else
145 buttonlight_hw_on();
146}
147
148/* external interface */
149
150void buttonlight_on(void)
151{
152 if(!ignore_buttonlight_on)
153 {
154 queue_remove_from_head(&backlight_queue, BUTTON_LIGHT_ON);
155 queue_post(&backlight_queue, BUTTON_LIGHT_ON, 0);
156 }
157}
158
159void buttonlight_on_ignore(bool value, int timeout)
160{
161 ignore_buttonlight_on = value;
162 buttonlight_ignored_timer = timeout;
163}
164
165void buttonlight_off(void)
166{
167 queue_post(&backlight_queue, BUTTON_LIGHT_OFF, 0);
168}
169
170void buttonlight_set_timeout(int value)
171{
172 buttonlight_timeout = HZ * value;
173 queue_post(&backlight_queue, BUTTON_LIGHT_TMO_CHANGED, 0);
174}
175
176int buttonlight_get_current_timeout(void)
177{
178 return buttonlight_timeout;
179}
180
181#endif /* HAVE_BUTTON_LIGHT */
182
183#ifdef HAVE_REMOTE_LCD
184static int remote_backlight_timer;
185static int remote_backlight_timeout_normal = 5*HZ;
186#if CONFIG_CHARGING
187static int remote_backlight_timeout_plugged = 5*HZ;
188#endif
189#ifdef HAS_REMOTE_BUTTON_HOLD
190static int remote_backlight_on_button_hold = 0;
191#endif
192#endif /* HAVE_REMOTE_LCD */
193
194#ifdef HAVE_LCD_SLEEP
195#ifdef HAVE_LCD_SLEEP_SETTING
196static int lcd_sleep_timeout = 10*HZ;
197#else
198/* Target defines needed value */
199#define lcd_sleep_timeout LCD_SLEEP_TIMEOUT
200#endif
201
202static int lcd_sleep_timer SHAREDDATA_ATTR = 0;
203
204static void backlight_lcd_sleep_countdown(bool start)
205{
206 if (!start)
207 {
208 /* Cancel the LCD sleep countdown */
209 lcd_sleep_timer = 0;
210 return;
211 }
212
213 /* Start LCD sleep countdown */
214 if (lcd_sleep_timeout <= 0)
215 {
216 lcd_sleep_timer = 0;
217 if (lcd_sleep_timeout == 0) /* Setting == Always */
218 {
219 /* Ensure lcd_sleep() is called from backlight_thread() */
220#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_PWM)
221 queue_post(&backlight_queue, LCD_SLEEP, 0);
222#else
223 lcd_sleep();
224#endif
225 }
226 }
227 else
228 {
229 lcd_sleep_timer = lcd_sleep_timeout;
230 }
231}
232#endif /* HAVE_LCD_SLEEP */
233
234#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
235 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
236static int backlight_fading_type = (FADING_UP|FADING_DOWN);
237static int backlight_fading_state = NOT_FADING;
238#endif
239
240
241/* backlight fading */
242#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_PWM)
243#define BL_PWM_INTERVAL 5 /* Cycle interval in ms */
244#define BL_PWM_BITS 8
245#define BL_PWM_COUNT (1<<BL_PWM_BITS)
246
247/* s15.16 fixed point variables */
248static int32_t bl_fade_in_step = ((BL_PWM_INTERVAL*BL_PWM_COUNT)<<16)/300;
249static int32_t bl_fade_out_step = ((BL_PWM_INTERVAL*BL_PWM_COUNT)<<16)/2000;
250static int32_t bl_dim_fraction = 0;
251
252static int bl_dim_target = 0;
253static int bl_dim_current = 0;
254static enum {DIM_STATE_START, DIM_STATE_MAIN} bl_dim_state = DIM_STATE_START;
255static bool bl_timer_active = false;
256
257static void backlight_isr(void)
258{
259 int timer_period = (TIMER_FREQ*BL_PWM_INTERVAL/1000);
260 bool idle = false;
261
262 switch (bl_dim_state)
263 {
264 /* New cycle */
265 case DIM_STATE_START:
266 bl_dim_current = bl_dim_fraction >> 16;
267
268 if (bl_dim_current > 0 && bl_dim_current < BL_PWM_COUNT)
269 {
270 _backlight_on_isr();
271 timer_period = (timer_period * bl_dim_current) >> BL_PWM_BITS;
272 bl_dim_state = DIM_STATE_MAIN;
273 }
274 else
275 {
276 if (bl_dim_current)
277 _backlight_on_isr();
278 else
279 _backlight_off_isr();
280 if (bl_dim_current == bl_dim_target)
281 idle = true;
282 }
283 if (bl_dim_current < bl_dim_target)
284 {
285 bl_dim_fraction = MIN(bl_dim_fraction + bl_fade_in_step,
286 (BL_PWM_COUNT<<16));
287 }
288 else if (bl_dim_current > bl_dim_target)
289 {
290 bl_dim_fraction = MAX(bl_dim_fraction - bl_fade_out_step, 0);
291 }
292 break;
293
294 /* Dim main screen */
295 case DIM_STATE_MAIN:
296 _backlight_off_isr();
297 timer_period = (timer_period * (BL_PWM_COUNT - bl_dim_current))
298 >> BL_PWM_BITS;
299 bl_dim_state = DIM_STATE_START;
300 break ;
301 }
302 if (idle)
303 {
304#if defined(_BACKLIGHT_FADE_BOOST) || defined(_BACKLIGHT_FADE_ENABLE)
305 queue_post(&backlight_queue, BACKLIGHT_FADE_FINISH, 0);
306#endif
307 timer_unregister();
308 bl_timer_active = false;
309
310#ifdef HAVE_LCD_SLEEP
311 if (bl_dim_current == 0)
312 backlight_lcd_sleep_countdown(true);
313#endif
314 }
315 else
316 timer_set_period(timer_period);
317}
318
319static void backlight_switch(void)
320{
321 if (bl_dim_target > (BL_PWM_COUNT/2))
322 {
323 _backlight_on_normal();
324 bl_dim_fraction = (BL_PWM_COUNT<<16);
325 }
326 else
327 {
328 _backlight_off_normal();
329 bl_dim_fraction = 0;
330
331#ifdef HAVE_LCD_SLEEP
332 backlight_lcd_sleep_countdown(true);
333#endif
334 }
335}
336
337static void backlight_release_timer(void)
338{
339#ifdef _BACKLIGHT_FADE_BOOST
340 cpu_boost(false);
341#endif
342 timer_unregister();
343 bl_timer_active = false;
344 backlight_switch();
345}
346
347static void backlight_dim(int value)
348{
349 /* protect from extraneous calls with the same target value */
350 if (value == bl_dim_target)
351 return;
352
353 bl_dim_target = value;
354
355 if (bl_timer_active)
356 return ;
357
358 if (timer_register(0, backlight_release_timer, 2, backlight_isr
359 IF_COP(, CPU)))
360 {
361#ifdef _BACKLIGHT_FADE_BOOST
362 /* Prevent cpu frequency changes while dimming. */
363 cpu_boost(true);
364#endif
365 bl_timer_active = true;
366 }
367 else
368 backlight_switch();
369}
370
371static void backlight_setup_fade_up(void)
372{
373 if (bl_fade_in_step > 0)
374 {
375#ifdef _BACKLIGHT_FADE_ENABLE
376 _backlight_hw_enable(true);
377#endif
378 backlight_dim(BL_PWM_COUNT);
379 }
380 else
381 {
382 bl_dim_target = BL_PWM_COUNT;
383 bl_dim_fraction = (BL_PWM_COUNT<<16);
384 _backlight_on_normal();
385 }
386}
387
388static void backlight_setup_fade_down(void)
389{
390 if (bl_fade_out_step > 0)
391 {
392 backlight_dim(0);
393 }
394 else
395 {
396 bl_dim_target = bl_dim_fraction = 0;
397 _backlight_off_normal();
398#ifdef HAVE_LCD_SLEEP
399 backlight_lcd_sleep_countdown(true);
400#endif
401 }
402}
403
404void backlight_set_fade_in(int value)
405{
406 if (value > 0)
407 bl_fade_in_step = ((BL_PWM_INTERVAL*BL_PWM_COUNT)<<16) / value;
408 else
409 bl_fade_in_step = 0;
410}
411
412void backlight_set_fade_out(int value)
413{
414 if (value > 0)
415 bl_fade_out_step = ((BL_PWM_INTERVAL*BL_PWM_COUNT)<<16) / value;
416 else
417 bl_fade_out_step = 0;
418}
419
420#elif (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
421 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
422
423void backlight_set_fade_out(bool value)
424{
425 if(value) /* on */
426 backlight_fading_type |= FADING_DOWN;
427 else
428 backlight_fading_type &= FADING_UP;
429}
430
431void backlight_set_fade_in(bool value)
432{
433 if(value) /* on */
434 backlight_fading_type |= FADING_UP;
435 else
436 backlight_fading_type &= FADING_DOWN;
437}
438
439static void backlight_setup_fade_up(void)
440{
441 if (backlight_fading_type & FADING_UP)
442 {
443 if (backlight_fading_state == NOT_FADING)
444 {
445 /* make sure the backlight is at lowest level */
446 backlight_hw_on();
447 }
448 backlight_fading_state = FADING_UP;
449 }
450 else
451 {
452 backlight_fading_state = NOT_FADING;
453 _backlight_fade_update_state(backlight_brightness);
454 backlight_hw_on();
455 backlight_hw_brightness(backlight_brightness);
456 }
457}
458
459static void backlight_setup_fade_down(void)
460{
461 if (backlight_fading_type & FADING_DOWN)
462 {
463 backlight_fading_state = FADING_DOWN;
464 }
465 else
466 {
467 backlight_fading_state = NOT_FADING;
468 _backlight_fade_update_state(MIN_BRIGHTNESS_SETTING-1);
469 backlight_hw_off();
470#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
471 /* write the lowest brightness level to the hardware so that
472 * fading up is glitch free */
473 backlight_hw_brightness(MIN_BRIGHTNESS_SETTING);
474#endif
475#ifdef HAVE_LCD_SLEEP
476 backlight_lcd_sleep_countdown(true);
477#endif
478 }
479}
480#endif /* CONFIG_BACKLIGHT_FADING */
481
482static inline void do_backlight_off(void)
483{
484 backlight_timer = 0;
485#if BACKLIGHT_FADE_IN_THREAD
486 backlight_setup_fade_down();
487#else
488 backlight_hw_off();
489 /* targets that have fading need to start the countdown when done with
490 * fading */
491#ifdef HAVE_LCD_SLEEP
492 backlight_lcd_sleep_countdown(true);
493#endif
494#endif
495}
496
497/* Update state of backlight according to timeout setting */
498static void backlight_update_state(void)
499{
500
501 int timeout = backlight_get_current_timeout();
502
503 /* Backlight == OFF in the setting? */
504 if (UNLIKELY(timeout < 0))
505 {
506 do_backlight_off();
507#if defined(HAVE_TRANSFLECTIVE_LCD) && defined(HAVE_LCD_SLEEP)
508 /* LCD must be enabled to allow "passive" operation (backlight always off) */
509 lcd_awake();
510#endif
511#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
512 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
513 /* necessary step to issue fading down when the setting is selected */
514 if (queue_empty(&backlight_queue))
515 queue_post(&backlight_queue, SYS_TIMEOUT, 0);
516#endif
517 }
518 else
519 {
520 backlight_timer = timeout;
521
522#ifdef HAVE_LCD_SLEEP
523 backlight_lcd_sleep_countdown(false); /* wake up lcd */
524#endif
525
526#if BACKLIGHT_FADE_IN_THREAD
527 backlight_setup_fade_up();
528#else
529 backlight_hw_on();
530#endif
531 }
532}
533
534#ifdef HAVE_REMOTE_LCD
535/* Update state of remote backlight according to timeout setting */
536static void remote_backlight_update_state(void)
537{
538 int timeout = remote_backlight_get_current_timeout();
539 /* Backlight == OFF in the setting? */
540 if (timeout < 0)
541 {
542 remote_backlight_timer = 0; /* Disable the timeout */
543 remote_backlight_hw_off();
544 }
545 else
546 {
547 remote_backlight_timer = timeout;
548 remote_backlight_hw_on();
549 }
550}
551#endif /* HAVE_REMOTE_LCD */
552
553static void backlight_queue_wait(struct queue_event *ev)
554{
555#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
556 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
557 if (backlight_fading_state != NOT_FADING)
558 queue_wait_w_tmo(&backlight_queue, ev, FADE_DELAY);
559 else
560#endif
561 queue_wait_w_tmo(&backlight_queue, ev, BACKLIGHT_THREAD_TIMEOUT);
562}
563
564void backlight_thread(void)
565{
566 struct queue_event ev;
567 bool locked = false;
568
569 while(1)
570 {
571 backlight_queue_wait(&ev);
572 switch(ev.id)
573 { /* These events must always be processed */
574#ifdef _BACKLIGHT_FADE_BOOST
575 case BACKLIGHT_FADE_FINISH:
576 cpu_boost(false);
577 break;
578#endif
579#ifdef _BACKLIGHT_FADE_ENABLE
580 case BACKLIGHT_FADE_FINISH:
581 _backlight_hw_enable((bl_dim_current|bl_dim_target) != 0);
582 break;
583#endif
584
585#ifndef SIMULATOR
586 /* Here for now or else the aggressive init messes up scrolling */
587#ifdef HAVE_REMOTE_LCD
588 case SYS_REMOTE_PLUGGED:
589 lcd_remote_on();
590 lcd_remote_update();
591 break;
592
593 case SYS_REMOTE_UNPLUGGED:
594 lcd_remote_off();
595 break;
596#elif defined HAVE_REMOTE_LCD_AS_MAIN
597 case SYS_REMOTE_PLUGGED:
598 lcd_on();
599 lcd_update();
600 break;
601
602 case SYS_REMOTE_UNPLUGGED:
603 lcd_off();
604 break;
605#endif /* HAVE_REMOTE_LCD/ HAVE_REMOTE_LCD_AS_MAIN */
606#endif /* !SIMULATOR */
607 case SYS_USB_CONNECTED:
608 usb_acknowledge(SYS_USB_CONNECTED_ACK);
609 break;
610
611#ifdef BACKLIGHT_DRIVER_CLOSE
612 /* Get out of here */
613 case BACKLIGHT_QUIT:
614 return;
615#endif
616 }
617 if (locked)
618 continue;
619
620 switch(ev.id)
621 { /* These events are only processed if backlight isn't locked */
622#ifdef HAVE_REMOTE_LCD
623 case REMOTE_BACKLIGHT_TMO_CHANGED:
624 case REMOTE_BACKLIGHT_ON:
625 remote_backlight_update_state();
626 break;
627
628 case REMOTE_BACKLIGHT_OFF:
629 remote_backlight_timer = 0; /* Disable the timeout */
630 remote_backlight_hw_off();
631 break;
632#endif /* HAVE_REMOTE_LCD */
633
634 case BACKLIGHT_TMO_CHANGED:
635 case BACKLIGHT_ON:
636 backlight_update_state();
637 break;
638
639 case BACKLIGHT_OFF:
640 do_backlight_off();
641 break;
642#ifdef HAVE_BACKLIGHT_BRIGHTNESS
643 case BACKLIGHT_BRIGHTNESS_CHANGED:
644 backlight_brightness = (int)ev.data;
645 backlight_hw_brightness((int)ev.data);
646#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
647 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
648 /* receive backlight brightness */
649 _backlight_fade_update_state((int)ev.data);
650#endif
651 break;
652#endif /* HAVE_BACKLIGHT_BRIGHTNESS */
653#ifdef HAVE_LCD_SLEEP
654 case LCD_SLEEP:
655 lcd_sleep();
656 break;
657#endif
658#ifdef HAVE_BUTTON_LIGHT
659 case BUTTON_LIGHT_TMO_CHANGED:
660 case BUTTON_LIGHT_ON:
661 buttonlight_update_state();
662 break;
663
664 case BUTTON_LIGHT_OFF:
665 buttonlight_timer = 0;
666 buttonlight_hw_off();
667 break;
668#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
669 case BUTTON_LIGHT_BRIGHTNESS_CHANGED:
670 buttonlight_hw_brightness((int)ev.data);
671 break;
672#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
673#endif /* HAVE_BUTTON_LIGHT */
674
675 case SYS_REBOOT:
676 case SYS_POWEROFF: /* Lock backlight on poweroff so it doesn't */
677 locked = true; /* go off before power is actually cut. */
678#if !defined(BOOTLOADER)
679#if defined(HAVE_LCD_SLEEP) /* bugfix ipod Video, 6G crashes if screen off at shutdown */
680 lcd_awake();
681#endif
682 if (!global_settings.show_shutdown_message)
683 break;
684#endif
685 /* else fall through */
686#if CONFIG_CHARGING
687 case SYS_CHARGER_CONNECTED:
688 case SYS_CHARGER_DISCONNECTED:
689#endif
690 backlight_update_state();
691#ifdef HAVE_REMOTE_LCD
692 remote_backlight_update_state();
693#endif
694 break;
695 case SYS_TIMEOUT:
696 backlight_handle_timeout();
697 break;
698 }
699 } /* end while */
700}
701
702static void backlight_timeout_handler(void)
703{
704 if(backlight_timer > 0)
705 {
706 backlight_timer -= BACKLIGHT_THREAD_TIMEOUT;
707 if(backlight_timer <= 0)
708 {
709 do_backlight_off();
710 }
711 }
712#ifdef HAVE_LCD_SLEEP
713 else if(lcd_sleep_timer > 0)
714 {
715 lcd_sleep_timer -= BACKLIGHT_THREAD_TIMEOUT;
716 if(lcd_sleep_timer <= 0)
717 {
718 lcd_sleep();
719 }
720 }
721#endif /* HAVE_LCD_SLEEP */
722#ifdef HAVE_REMOTE_LCD
723 if(remote_backlight_timer > 0)
724 {
725 remote_backlight_timer -= BACKLIGHT_THREAD_TIMEOUT;
726 if(remote_backlight_timer <= 0)
727 {
728 remote_backlight_hw_off();
729 }
730 }
731#endif /* HAVE_REMOVE_LCD */
732#ifdef HAVE_BUTTON_LIGHT
733 if (buttonlight_timer > 0)
734 {
735 buttonlight_timer -= BACKLIGHT_THREAD_TIMEOUT;
736 if (buttonlight_timer <= 0)
737 {
738 buttonlight_hw_off();
739 }
740 }
741 if (buttonlight_ignored_timer > 0)
742 {
743 buttonlight_ignored_timer -= BACKLIGHT_THREAD_TIMEOUT;
744 if (buttonlight_ignored_timer <= 0)
745 ignore_buttonlight_on = false;
746 }
747#endif /* HAVE_BUTTON_LIGHT */
748 if (backlight_ignored_timer > 0)
749 {
750 backlight_ignored_timer -= BACKLIGHT_THREAD_TIMEOUT;
751 if (backlight_ignored_timer <= 0)
752 ignore_backlight_on = false;
753 }
754}
755
756static void backlight_handle_timeout(void)
757{
758#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_SETTING) \
759 || (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_SW_HW_REG)
760 if (backlight_fading_state != NOT_FADING)
761 {
762 if ((_backlight_fade_step(backlight_fading_state)))
763 { /* finished fading */
764#ifdef HAVE_LCD_SLEEP
765 if (backlight_fading_state == FADING_DOWN)
766 { /* start sleep countdown */
767 backlight_lcd_sleep_countdown(true);
768 }
769#endif
770 backlight_fading_state = NOT_FADING;
771 }
772 }
773 else
774#endif /* CONFIG_BACKLIGHT_FADING */
775 backlight_timeout_handler();
776}
777
778void backlight_init(void)
779{
780 queue_init(&backlight_queue, true);
781
782 if (backlight_hw_init())
783 {
784#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_FADING_PWM)
785 /* If backlight is already on, don't fade in. */
786 bl_dim_target = BL_PWM_COUNT;
787 bl_dim_fraction = (BL_PWM_COUNT<<16);
788#endif
789 }
790 /* Leave all lights as set by the bootloader here. The settings load will
791 * call the appropriate backlight_set_*() functions, only changing light
792 * status if necessary. */
793#ifdef BACKLIGHT_DRIVER_CLOSE
794 backlight_thread_id =
795#endif
796 create_thread(backlight_thread, backlight_stack,
797 sizeof(backlight_stack), 0, backlight_thread_name
798 IF_PRIO(, PRIORITY_USER_INTERFACE)
799 IF_COP(, CPU));
800}
801
802#ifdef BACKLIGHT_DRIVER_CLOSE
803void backlight_close(void)
804{
805 unsigned int thread = backlight_thread_id;
806
807 /* Wait for thread to exit */
808 if (thread == 0)
809 return;
810
811 backlight_thread_id = 0;
812
813 queue_post(&backlight_queue, BACKLIGHT_QUIT, 0);
814 thread_wait(thread);
815}
816#endif /* BACKLIGHT_DRIVER_CLOSE */
817
818void backlight_on(void)
819{
820 if(!ignore_backlight_on)
821 {
822 queue_remove_from_head(&backlight_queue, BACKLIGHT_ON);
823 queue_post(&backlight_queue, BACKLIGHT_ON, 0);
824 }
825}
826
827void backlight_on_ignore(bool value, int timeout)
828{
829 ignore_backlight_on = value;
830 backlight_ignored_timer = timeout;
831}
832
833void backlight_off(void)
834{
835 queue_post(&backlight_queue, BACKLIGHT_OFF, 0);
836}
837
838/* returns true when the backlight is on,
839 * and optionally when it's set to always off. */
840bool is_backlight_on(bool ignore_always_off)
841{
842 int timeout = backlight_get_current_timeout();
843 return (backlight_timer > 0) /* countdown */
844 || (timeout == 0) /* always on */
845 || ((timeout < 0) && !ignore_always_off);
846}
847
848/* return value in ticks; 0 means always on, <0 means always off */
849int backlight_get_current_timeout(void)
850{
851 if ((backlight_on_button_hold != 0)
852#if (defined(HAVE_REMOTE_LCD_AS_MAIN) && defined(HAS_REMOTE_BUTTON_HOLD))
853 && remote_button_hold()
854#elif defined(HAS_BUTTON_HOLD)
855 && button_hold()
856#else
857 && is_keys_locked()
858#endif
859 )
860 return (backlight_on_button_hold == 2) ? 0 : -1;
861 /* always on or always off */
862 else
863#if CONFIG_CHARGING
864 if (power_input_present())
865 return backlight_timeout_plugged;
866 else
867#endif
868 return backlight_timeout_normal;
869}
870
871void backlight_set_timeout(int value)
872{
873 backlight_timeout_normal = HZ * value;
874 queue_post(&backlight_queue, BACKLIGHT_TMO_CHANGED, 0);
875}
876
877#if CONFIG_CHARGING
878void backlight_set_timeout_plugged(int value)
879{
880 backlight_timeout_plugged = HZ * value;
881 queue_post(&backlight_queue, BACKLIGHT_TMO_CHANGED, 0);
882}
883#endif /* CONFIG_CHARGING */
884
885#ifdef HAS_BUTTON_HOLD
886/* Hold button change event handler. */
887void backlight_hold_changed(bool hold_button)
888{
889 if (!hold_button || (backlight_on_button_hold > 0))
890 {
891 /* if unlocked or override in effect */
892
893 /*backlight_on(); REMOVED*/
894 queue_remove_from_head(&backlight_queue, BACKLIGHT_ON);
895 queue_post(&backlight_queue, BACKLIGHT_ON, 0);
896 }
897}
898#endif /* HAS_BUTTON_HOLD */
899
900void backlight_set_on_button_hold(int index)
901{
902 if ((unsigned)index >= 3)
903 /* if given a weird value, use default */
904 index = 0;
905
906 backlight_on_button_hold = index;
907 queue_post(&backlight_queue, BACKLIGHT_TMO_CHANGED, 0);
908}
909
910#ifdef HAVE_LCD_SLEEP_SETTING
911void lcd_set_sleep_after_backlight_off(int timeout_seconds)
912{
913 lcd_sleep_timeout = HZ * timeout_seconds;
914
915 if (is_backlight_on(true))
916 /* Timer will be set when bl turns off or bl set to on. */
917 return;
918
919 /* Backlight is Off */
920 if (lcd_sleep_timeout < 0)
921 lcd_sleep_timer = 0; /* Never */
922 else if (lcd_sleep_timeout == 0)
923 lcd_sleep_timer = 1; /* Always - sleep next tick */
924 else
925 lcd_sleep_timer = lcd_sleep_timeout; /* other */
926}
927#endif /* HAVE_LCD_SLEEP_SETTING */
928
929#ifdef HAVE_REMOTE_LCD
930void remote_backlight_on(void)
931{
932 queue_post(&backlight_queue, REMOTE_BACKLIGHT_ON, 0);
933}
934
935void remote_backlight_off(void)
936{
937 queue_post(&backlight_queue, REMOTE_BACKLIGHT_OFF, 0);
938}
939
940void remote_backlight_set_timeout(int value)
941{
942 remote_backlight_timeout_normal = HZ * value;
943 queue_post(&backlight_queue, REMOTE_BACKLIGHT_TMO_CHANGED, 0);
944}
945
946#if CONFIG_CHARGING
947void remote_backlight_set_timeout_plugged(int value)
948{
949 remote_backlight_timeout_plugged = HZ * value;
950 queue_post(&backlight_queue, REMOTE_BACKLIGHT_TMO_CHANGED, 0);
951}
952#endif /* CONFIG_CHARGING */
953
954#ifdef HAS_REMOTE_BUTTON_HOLD
955/* Remote hold button change event handler. */
956void remote_backlight_hold_changed(bool rc_hold_button)
957{
958 if (!rc_hold_button || (remote_backlight_on_button_hold > 0))
959 /* if unlocked or override */
960 remote_backlight_on();
961}
962
963void remote_backlight_set_on_button_hold(int index)
964{
965 if ((unsigned)index >= 3)
966 /* if given a weird value, use default */
967 index = 0;
968
969 remote_backlight_on_button_hold = index;
970 queue_post(&backlight_queue, REMOTE_BACKLIGHT_TMO_CHANGED, 0);
971}
972#endif /* HAS_REMOTE_BUTTON_HOLD */
973
974/* return value in ticks; 0 means always on, <0 means always off */
975int remote_backlight_get_current_timeout(void)
976{
977#ifdef HAS_REMOTE_BUTTON_HOLD
978 if (remote_button_hold() && (remote_backlight_on_button_hold != 0))
979 return (remote_backlight_on_button_hold == 2)
980 ? 0 : -1; /* always on or always off */
981 else
982#endif
983#if CONFIG_CHARGING
984 if (power_input_present())
985 return remote_backlight_timeout_plugged;
986 else
987#endif
988 return remote_backlight_timeout_normal;
989}
990
991/* returns true when the backlight is on, and
992 * optionally when it's set to always off */
993bool is_remote_backlight_on(bool ignore_always_off)
994{
995 int timeout = remote_backlight_get_current_timeout();
996 return (remote_backlight_timer > 0) /* countdown */
997 || (timeout == 0) /* always on */
998 || ((timeout < 0) && !ignore_always_off);
999}
1000
1001#endif /* HAVE_REMOTE_LCD */
1002
1003#ifdef HAVE_BACKLIGHT_BRIGHTNESS
1004void backlight_set_brightness(int val)
1005{
1006 if (val < MIN_BRIGHTNESS_SETTING)
1007 val = MIN_BRIGHTNESS_SETTING;
1008 else if (val > MAX_BRIGHTNESS_SETTING)
1009 val = MAX_BRIGHTNESS_SETTING;
1010
1011 queue_post(&backlight_queue, BACKLIGHT_BRIGHTNESS_CHANGED, val);
1012}
1013#endif /* HAVE_BACKLIGHT_BRIGHTNESS */
1014
1015#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
1016void buttonlight_set_brightness(int val)
1017{
1018 if (val < MIN_BRIGHTNESS_SETTING)
1019 val = MIN_BRIGHTNESS_SETTING;
1020 else if (val > MAX_BRIGHTNESS_SETTING)
1021 val = MAX_BRIGHTNESS_SETTING;
1022
1023 queue_post(&backlight_queue, BUTTON_LIGHT_BRIGHTNESS_CHANGED, val);
1024}
1025#endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */
1026
1027#else /* !defined(HAVE_BACKLIGHT) || !defined(BACKLIGHT_FULL_INIT)
1028 -- no backlight, empty dummy functions */
1029
1030#if defined(HAVE_BACKLIGHT) && !defined(BACKLIGHT_FULL_INIT)
1031void backlight_init(void)
1032{
1033 (void)backlight_hw_init();
1034 backlight_hw_on();
1035}
1036#endif
1037
1038void backlight_on(void) {}
1039void backlight_off(void) {}
1040void backlight_set_timeout(int value) {(void)value;}
1041
1042bool is_backlight_on(bool ignore_always_off)
1043{
1044 (void)ignore_always_off;
1045 return true;
1046}
1047#ifdef HAVE_REMOTE_LCD
1048void remote_backlight_on(void) {}
1049void remote_backlight_off(void) {}
1050void remote_backlight_set_timeout(int value) {(void)value;}
1051
1052bool is_remote_backlight_on(bool ignore_always_off)
1053{
1054 (void)ignore_always_off;
1055 return true;
1056}
1057#endif /* HAVE_REMOTE_LCD */
1058#ifdef HAVE_BACKLIGHT_BRIGHTNESS
1059void backlight_set_brightness(int val) { (void)val; }
1060#endif
1061
1062#ifdef HAVE_BUTTON_LIGHT
1063void buttonlight_on(void) {}
1064#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
1065void buttonlight_set_brightness(int val) { (void)val; }
1066#endif
1067#endif /* HAVE_BUTTON_LIGHT */
1068
1069#endif /* defined(HAVE_BACKLIGHT) && defined(BACKLIGHT_FULL_INIT) */
1070
1071#ifndef HAVE_BUTTON_LIGHT /* Dummy Functions */
1072void buttonlight_on(void) {}
1073void buttonlight_on_ignore(bool value, int timeout){(void)value;(void)timeout;}
1074void buttonlight_off(void) {}
1075void buttonlight_set_timeout(int value) {(void)value;}
1076#endif /* ndef HAVE_BUTTON_LIGHT */
1077
1078#ifndef HAVE_BUTTONLIGHT_BRIGHTNESS /* Dummy Functions */
1079void buttonlight_set_brightness(int val) { (void)val; }
1080#endif /* ndef HAVE_BUTTONLIGHT_BRIGHTNESS */