Remove hosted_get_volume(), as event data is available in button_get_data().
[kugel-rb.git] / firmware / powermgmt.c
blob79a7a90a2b254ff76b9a0f04b9d988d4edc7292f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
11 * Revisions copyright (C) 2005 by Gerald Van Baren
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "config.h"
23 #include "system.h"
24 #include "kernel.h"
25 #include "thread.h"
26 #include "debug.h"
27 #include "adc.h"
28 #include "string.h"
29 #include "storage.h"
30 #include "power.h"
31 #include "audio.h"
32 #include "mp3_playback.h"
33 #include "usb.h"
34 #include "powermgmt.h"
35 #include "backlight.h"
36 #include "lcd.h"
37 #include "rtc.h"
38 #if CONFIG_TUNER
39 #include "fmradio.h"
40 #endif
41 #include "sound.h"
42 #ifdef HAVE_LCD_BITMAP
43 #include "font.h"
44 #endif
45 #include "logf.h"
46 #include "lcd-remote.h"
47 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
48 #include <time.h>
49 #endif
51 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && !defined (SIMULATOR)
52 #include "lcd-remote-target.h"
53 #endif
54 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
55 && !defined (SIMULATOR)
56 #include "pcf50606.h"
57 #endif
59 /** Shared by sim **/
60 int last_sent_battery_level = 100;
61 /* battery level (0-100%) */
62 int battery_percent = -1;
63 void send_battery_level_event(void);
65 static bool sleeptimer_active = false;
66 static long sleeptimer_endtick;
68 #if CONFIG_CHARGING
69 /* State of the charger input as seen by the power thread */
70 enum charger_input_state_type charger_input_state;
71 /* Power inputs as seen by the power thread */
72 unsigned int power_thread_inputs;
73 #if CONFIG_CHARGING >= CHARGING_MONITOR
74 /* Charging state (mode) as seen by the power thread */
75 enum charge_state_type charge_state = DISCHARGING;
76 #endif
77 #endif /* CONFIG_CHARGING */
79 static int shutdown_timeout = 0;
81 void handle_auto_poweroff(void);
82 static int poweroff_timeout = 0;
83 static long last_event_tick = 0;
85 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
87 * Average battery voltage and charger voltage, filtered via a digital
88 * exponential filter (aka. exponential moving average, scaled):
89 * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N.
91 static unsigned int avgbat;
92 /* filtered battery voltage, millivolts */
93 static unsigned int battery_millivolts;
94 /* default value, mAh */
95 static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
98 #if BATTERY_TYPES_COUNT > 1
99 static int battery_type = 0;
100 #else
101 #define battery_type 0
102 #endif
104 /* Power history: power_history[0] is the newest sample */
105 unsigned short power_history[POWER_HISTORY_LEN] = {0};
107 #if CONFIG_CPU == JZ4732 /* FIXME! */
108 static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK];
109 #else
110 static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
111 #endif
112 static const char power_thread_name[] = "power";
114 static int powermgmt_est_runningtime_min = -1;
116 static int voltage_to_battery_level(int battery_millivolts);
117 static void battery_status_update(void);
119 #ifdef CURRENT_NORMAL /*only used if we have run current*/
120 static int runcurrent(void);
121 #endif
123 void battery_read_info(int *voltage, int *level)
125 int millivolts = battery_adc_voltage();
127 if (voltage)
128 *voltage = millivolts;
130 if (level)
131 *level = voltage_to_battery_level(millivolts);
134 #if BATTERY_TYPES_COUNT > 1
135 void set_battery_type(int type)
137 if (type != battery_type) {
138 if ((unsigned)type >= BATTERY_TYPES_COUNT)
139 type = 0;
141 battery_type = type;
142 battery_status_update(); /* recalculate the battery status */
145 #endif
147 void set_battery_capacity(int capacity)
149 if (capacity > BATTERY_CAPACITY_MAX)
150 capacity = BATTERY_CAPACITY_MAX;
151 if (capacity < BATTERY_CAPACITY_MIN)
152 capacity = BATTERY_CAPACITY_MIN;
154 battery_capacity = capacity;
156 battery_status_update(); /* recalculate the battery status */
159 int get_battery_capacity(void)
161 return battery_capacity;
164 int battery_time(void)
166 return powermgmt_est_runningtime_min;
169 /* Returns battery level in percent */
170 int battery_level(void)
172 #ifdef HAVE_BATTERY_SWITCH
173 if ((power_input_status() & POWER_INPUT_BATTERY) == 0)
174 return -1;
175 #endif
176 return battery_percent;
179 /* Returns filtered battery voltage [millivolts] */
180 unsigned int battery_voltage(void)
182 return battery_millivolts;
185 /* Tells if the battery level is safe for disk writes */
186 bool battery_level_safe(void)
188 #if defined(NO_LOW_BATTERY_SHUTDOWN)
189 return true;
190 #elif defined(HAVE_BATTERY_SWITCH)
191 /* Cannot rely upon the battery reading to be valid and the
192 * device could be powered externally. */
193 return input_millivolts() > battery_level_dangerous[battery_type];
194 #else
195 return battery_millivolts > battery_level_dangerous[battery_type];
196 #endif
199 /* look into the percent_to_volt_* table and get a realistic battery level */
200 static int voltage_to_percent(int voltage, const short* table)
202 if (voltage <= table[0]) {
203 return 0;
205 else if (voltage >= table[10]) {
206 return 100;
208 else {
209 /* search nearest value */
210 int i = 0;
212 while (i < 10 && table[i+1] < voltage)
213 i++;
215 /* interpolate linear between the smaller and greater value */
216 /* Tens digit, 10% per entry, ones digit: interpolated */
217 return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]);
221 /* update battery level and estimated runtime, called once per minute or
222 * when battery capacity / type settings are changed */
223 static int voltage_to_battery_level(int battery_millivolts)
225 int level;
227 #if CONFIG_CHARGING >= CHARGING_MONITOR
228 if (charging_state()) {
229 /* battery level is defined to be < 100% until charging is finished */
230 level = voltage_to_percent(battery_millivolts,
231 percent_to_volt_charge);
232 if (level > 99)
233 level = 99;
235 else
236 #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
238 /* DISCHARGING or error state */
239 level = voltage_to_percent(battery_millivolts,
240 percent_to_volt_discharge[battery_type]);
243 return level;
246 static void battery_status_update(void)
248 int level = voltage_to_battery_level(battery_millivolts);
250 #ifdef CURRENT_NORMAL /*don't try to estimate run or charge
251 time without normal current defined*/
252 /* calculate estimated remaining running time */
253 #if CONFIG_CHARGING >= CHARGING_MONITOR
254 if (charging_state()) {
255 /* charging: remaining charging time */
256 powermgmt_est_runningtime_min = (100 - level)*battery_capacity*60
257 / 100 / (CURRENT_MAX_CHG - runcurrent());
259 else
260 #endif
262 /* discharging: remaining running time */
263 if (battery_millivolts > percent_to_volt_discharge[0][0]) {
264 /* linear extrapolation */
265 powermgmt_est_runningtime_min = (level + battery_percent)*60
266 * battery_capacity / 200 / runcurrent();
268 if (0 > powermgmt_est_runningtime_min) {
269 powermgmt_est_runningtime_min = 0;
271 #else
272 powermgmt_est_runningtime_min=-1;
273 #endif
275 battery_percent = level;
276 send_battery_level_event();
279 #ifdef CURRENT_NORMAL /*check that we have a current defined in a config file*/
282 * Estimate how much current we are drawing just to run.
284 static int runcurrent(void)
286 int current = CURRENT_NORMAL;
288 #ifndef BOOTLOADER
289 if (usb_inserted()
290 #ifdef HAVE_USB_POWER
291 #if (CURRENT_USB < CURRENT_NORMAL)
292 || usb_powered()
293 #else
294 && !usb_powered()
295 #endif
296 #endif
298 current = CURRENT_USB;
301 #if defined(HAVE_BACKLIGHT)
302 if (backlight_get_current_timeout() == 0) /* LED always on */
303 current += CURRENT_BACKLIGHT;
304 #endif
306 #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
307 if (audio_status() & AUDIO_STATUS_RECORD)
308 current += CURRENT_RECORD;
309 #endif
311 #ifdef HAVE_SPDIF_POWER
312 if (spdif_powered())
313 current += CURRENT_SPDIF_OUT;
314 #endif
316 #ifdef HAVE_REMOTE_LCD
317 if (remote_detect())
318 current += CURRENT_REMOTE;
319 #endif
321 #if defined(HAVE_ATA_POWER_OFF) && defined(CURRENT_ATA)
322 if (ide_powered())
323 current += CURRENT_ATA;
324 #endif
326 #endif /* BOOTLOADER */
328 return current;
331 #endif /* CURRENT_NORMAL */
333 /* Check to see whether or not we've received an alarm in the last second */
334 #ifdef HAVE_RTC_ALARM
335 static void power_thread_rtc_process(void)
337 if (rtc_check_alarm_flag())
338 rtc_enable_alarm(false);
340 #endif
342 /* switch off unit if battery level is too low for reliable operation */
343 bool query_force_shutdown(void)
345 #if defined(NO_LOW_BATTERY_SHUTDOWN)
346 return false;
347 #elif defined(HAVE_BATTERY_SWITCH)
348 /* Cannot rely upon the battery reading to be valid and the
349 * device could be powered externally. */
350 return input_millivolts() < battery_level_shutoff[battery_type];
351 #else
352 return battery_millivolts < battery_level_shutoff[battery_type];
353 #endif
356 #if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
358 * Reset the battery voltage filter to a new value and update the
359 * status.
361 void reset_battery_filter(int millivolts)
363 avgbat = millivolts * BATT_AVE_SAMPLES;
364 battery_millivolts = millivolts;
365 battery_status_update();
367 #endif /* HAVE_BATTERY_SWITCH */
369 /** Generic charging algorithms for common charging types **/
370 #if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
371 static inline void powermgmt_init_target(void)
373 /* Nothing to do */
376 static inline void charging_algorithm_step(void)
378 /* Nothing to do */
381 static inline void charging_algorithm_close(void)
383 /* Nothing to do */
385 #elif CONFIG_CHARGING == CHARGING_MONITOR
387 * Monitor CHARGING/DISCHARGING state.
389 static inline void powermgmt_init_target(void)
391 /* Nothing to do */
394 static inline void charging_algorithm_step(void)
396 switch (charger_input_state)
398 case CHARGER_PLUGGED:
399 case CHARGER:
400 if (charging_state()) {
401 charge_state = CHARGING;
402 break;
404 /* Fallthrough */
405 case CHARGER_UNPLUGGED:
406 case NO_CHARGER:
407 charge_state = DISCHARGING;
408 break;
412 static inline void charging_algorithm_close(void)
414 /* Nothing to do */
416 #endif /* CONFIG_CHARGING == * */
418 #if CONFIG_CHARGING
419 /* Shortcut function calls - compatibility, simplicity. */
421 /* Returns true if any power input is capable of charging. */
422 bool charger_inserted(void)
424 return power_thread_inputs & POWER_INPUT_CHARGER;
427 /* Returns true if any power input is connected - charging-capable
428 * or not. */
429 bool power_input_present(void)
431 return power_thread_inputs & POWER_INPUT;
435 * Detect charger inserted. Return true if the state is transistional.
437 static inline bool detect_charger(unsigned int pwr)
440 * Detect charger plugged/unplugged transitions. On a plugged or
441 * unplugged event, we return immediately, run once through the main
442 * loop (including the subroutines), and end up back here where we
443 * transition to the appropriate steady state charger on/off state.
445 if (pwr & POWER_INPUT_CHARGER) {
446 switch (charger_input_state)
448 case NO_CHARGER:
449 case CHARGER_UNPLUGGED:
450 charger_input_state = CHARGER_PLUGGED;
451 break;
453 case CHARGER_PLUGGED:
454 queue_broadcast(SYS_CHARGER_CONNECTED, 0);
455 last_sent_battery_level = 0;
456 charger_input_state = CHARGER;
457 break;
459 case CHARGER:
460 /* Steady state */
461 return false;
464 else { /* charger not inserted */
465 switch (charger_input_state)
467 case NO_CHARGER:
468 /* Steady state */
469 return false;
471 case CHARGER_UNPLUGGED:
472 queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
473 last_sent_battery_level = 100;
474 charger_input_state = NO_CHARGER;
475 break;
477 case CHARGER_PLUGGED:
478 case CHARGER:
479 charger_input_state = CHARGER_UNPLUGGED;
480 break;
484 /* Transitional state */
485 return true;
487 #endif /* CONFIG_CHARGING */
490 * Monitor the presence of a charger and perform critical frequent steps
491 * such as running the battery voltage filter.
493 static inline void power_thread_step(void)
495 /* If the power off timeout expires, the main thread has failed
496 to shut down the system, and we need to force a power off */
497 if (shutdown_timeout) {
498 shutdown_timeout -= POWER_THREAD_STEP_TICKS;
500 if (shutdown_timeout <= 0)
501 power_off();
504 #ifdef HAVE_RTC_ALARM
505 power_thread_rtc_process();
506 #endif
509 * Do a digital exponential filter. We don't sample the battery if
510 * the disk is spinning unless we are in USB mode (the disk will most
511 * likely always be spinning in USB mode) or charging.
513 if (!storage_disk_is_active() || usb_inserted()
514 #if CONFIG_CHARGING >= CHARGING_MONITOR
515 || charger_input_state == CHARGER
516 #endif
518 avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES;
520 * battery_millivolts is the millivolt-scaled filtered battery value.
522 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
524 /* update battery status every time an update is available */
525 battery_status_update();
527 else if (battery_percent < 8) {
529 * If battery is low, observe voltage during disk activity.
530 * Shut down if voltage drops below shutoff level and we are not
531 * using NiMH or Alkaline batteries.
533 battery_millivolts = (battery_adc_voltage() +
534 battery_millivolts + 1) / 2;
536 /* update battery status every time an update is available */
537 battery_status_update();
539 if (!shutdown_timeout && query_force_shutdown()) {
540 sys_poweroff();
542 else {
543 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
546 } /* power_thread_step */
548 static void power_thread(void)
550 long next_power_hist;
552 /* Delay reading the first battery level */
553 #ifdef MROBE_100
554 while (battery_adc_voltage() > 4200) /* gives false readings initially */
555 #endif
557 sleep(HZ/100);
560 #if CONFIG_CHARGING
561 /* Initialize power input status before calling other routines. */
562 power_thread_inputs = power_input_status();
563 #endif
565 /* initialize the voltages for the exponential filter */
566 avgbat = battery_adc_voltage() + 15;
568 #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
569 /* The battery voltage is usually a little lower directly after
570 turning on, because the disk was used heavily. Raise it by 5% */
571 #if CONFIG_CHARGING
572 if (!charger_inserted()) /* only if charger not connected */
573 #endif
575 avgbat += (percent_to_volt_discharge[battery_type][6] -
576 percent_to_volt_discharge[battery_type][5]) / 2;
578 #endif /* HAVE_DISK_STORAGE */
580 avgbat = avgbat * BATT_AVE_SAMPLES;
581 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
582 power_history[0] = battery_millivolts;
584 #if CONFIG_CHARGING
585 if (charger_inserted()) {
586 battery_percent = voltage_to_percent(battery_millivolts,
587 percent_to_volt_charge);
589 else
590 #endif
592 battery_percent = voltage_to_percent(battery_millivolts,
593 percent_to_volt_discharge[battery_type]);
594 battery_percent += battery_percent < 100;
597 powermgmt_init_target();
599 next_power_hist = current_tick + HZ*60;
601 while (1)
603 #if CONFIG_CHARGING
604 unsigned int pwr = power_input_status();
605 #ifdef HAVE_BATTERY_SWITCH
606 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
607 sleep(HZ/10);
608 reset_battery_filter(battery_adc_voltage());
610 #endif
611 power_thread_inputs = pwr;
613 if (!detect_charger(pwr))
614 #endif /* CONFIG_CHARGING */
616 /* Steady state */
617 sleep(POWER_THREAD_STEP_TICKS);
619 /* Do common power tasks */
620 power_thread_step();
623 /* Perform target tasks */
624 charging_algorithm_step();
626 if (TIME_BEFORE(current_tick, next_power_hist))
627 continue;
629 /* increment to ensure there is a record for every minute
630 * rather than go forward from the current tick */
631 next_power_hist += HZ*60;
633 /* rotate the power history */
634 memmove(&power_history[1], &power_history[0],
635 sizeof(power_history) - sizeof(power_history[0]));
637 /* insert new value at the start, in millivolts 8-) */
638 power_history[0] = battery_millivolts;
640 handle_auto_poweroff();
642 } /* power_thread */
644 void powermgmt_init(void)
646 create_thread(power_thread, power_stack, sizeof(power_stack), 0,
647 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
648 IF_COP(, CPU));
651 /* Various hardware housekeeping tasks relating to shutting down the player */
652 void shutdown_hw(void)
654 charging_algorithm_close();
655 audio_stop();
657 if (battery_level_safe()) { /* do not save on critical battery */
658 #ifdef HAVE_LCD_BITMAP
659 glyph_cache_save(NULL);
660 #endif
662 /* Commit pending writes if needed. Even though we don't do write caching,
663 things like flash translation layers may need this to commit scattered
664 pages to there final locations. So far only used for iPod Nano 2G. */
665 #ifdef HAVE_STORAGE_FLUSH
666 storage_flush();
667 #endif
669 if (storage_disk_is_active())
670 storage_spindown(1);
673 #if CONFIG_CODEC == SWCODEC
674 audiohw_close();
675 #else
676 mp3_shutdown();
677 #endif
679 /* If HD is still active we try to wait for spindown, otherwise the
680 shutdown_timeout in power_thread_step will force a power off */
681 while (storage_disk_is_active())
682 sleep(HZ/10);
684 #ifndef HAVE_LCD_COLOR
685 lcd_set_contrast(0);
686 #endif
687 #ifdef HAVE_REMOTE_LCD
688 lcd_remote_set_contrast(0);
689 #endif
690 #ifdef HAVE_LCD_SHUTDOWN
691 lcd_shutdown();
692 #endif
694 /* Small delay to make sure all HW gets time to flush. Especially
695 eeprom chips are quite slow and might be still writing the last
696 byte. */
697 sleep(HZ/4);
698 power_off();
700 #endif /* PLATFORM_NATIVE */
702 void set_poweroff_timeout(int timeout)
704 poweroff_timeout = timeout;
707 void reset_poweroff_timer(void)
709 last_event_tick = current_tick;
712 void sys_poweroff(void)
714 #ifndef BOOTLOADER
715 logf("sys_poweroff()");
716 /* If the main thread fails to shut down the system, we will force a
717 power off after an 20 second timeout - 28 seconds if recording */
718 if (shutdown_timeout == 0) {
719 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
720 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
721 #endif
722 #ifdef HAVE_RECORDING
723 if (audio_status() & AUDIO_STATUS_RECORD)
724 shutdown_timeout += HZ*8;
725 #endif
726 #ifdef IPOD_NANO2G
727 /* The FTL alone may take half a minute to shut down cleanly. */
728 shutdown_timeout += HZ*60;
729 #else
730 shutdown_timeout += HZ*20;
731 #endif
734 queue_broadcast(SYS_POWEROFF, 0);
735 #endif /* BOOTLOADER */
738 void cancel_shutdown(void)
740 logf("cancel_shutdown()");
742 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
743 /* TODO: Move some things to target/ tree */
744 if (shutdown_timeout)
745 pcf50606_reset_timeout();
746 #endif
748 shutdown_timeout = 0;
751 /* Send system battery level update events on reaching certain significant
752 levels. This must be called after battery_percent has been updated. */
753 void send_battery_level_event(void)
755 static const int levels[] = { 5, 15, 30, 50, 0 };
756 const int *level = levels;
758 while (*level)
760 if (battery_percent <= *level && last_sent_battery_level > *level) {
761 last_sent_battery_level = *level;
762 queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level);
763 break;
766 level++;
770 void set_sleep_timer(int seconds)
772 if (seconds) {
773 sleeptimer_active = true;
774 sleeptimer_endtick = current_tick + seconds * HZ;
776 else {
777 sleeptimer_active = false;
778 sleeptimer_endtick = 0;
782 int get_sleep_timer(void)
784 if (sleeptimer_active && (sleeptimer_endtick >= current_tick))
785 return (sleeptimer_endtick - current_tick) / HZ;
786 else
787 return 0;
790 static void handle_sleep_timer(void)
792 #ifndef BOOTLOADER
793 if (!sleeptimer_active)
794 return;
796 /* Handle sleeptimer */
797 if (TIME_AFTER(current_tick, sleeptimer_endtick)) {
798 if (usb_inserted()
799 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
800 || charger_input_state != NO_CHARGER
801 #endif
803 DEBUGF("Sleep timer timeout. Stopping...\n");
804 audio_pause();
805 set_sleep_timer(0);
806 backlight_off(); /* Nighty, nighty... */
808 else {
809 DEBUGF("Sleep timer timeout. Shutting off...\n");
810 sys_poweroff();
813 #endif /* BOOTLOADER */
817 * We shut off in the following cases:
818 * 1) The unit is idle, not playing music
819 * 2) The unit is playing music, but is paused
820 * 3) The battery level has reached shutdown limit
822 * We do not shut off in the following cases:
823 * 1) The USB is connected
824 * 2) The charger is connected
825 * 3) We are recording, or recording with pause
826 * 4) The radio is playing
828 void handle_auto_poweroff(void)
830 long timeout = poweroff_timeout*60*HZ;
831 int audio_stat = audio_status();
832 long tick = current_tick;
835 * Inhibit shutdown as long as the charger is plugged in. If it is
836 * unplugged, wait for a timeout period and then shut down.
838 if (audio_stat == AUDIO_STATUS_PLAY
839 #if CONFIG_CHARGING
840 || charger_input_state == CHARGER
841 #endif
843 last_event_tick = current_tick;
846 #if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
847 if (!shutdown_timeout && query_force_shutdown()) {
848 backlight_on();
849 sys_poweroff();
851 #endif
853 if (timeout &&
854 #if CONFIG_TUNER
855 !(get_radio_status() & FMRADIO_PLAYING) &&
856 #endif
857 !usb_inserted() &&
858 (audio_stat == 0 ||
859 (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) &&
860 !sleeptimer_active))) {
862 if (TIME_AFTER(tick, last_event_tick + timeout)
863 #if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
864 && TIME_AFTER(tick, storage_last_disk_activity() + timeout)
865 #endif
867 sys_poweroff();
869 } else
870 handle_sleep_timer();