Maemo port: Exclude plugins requiring a keymap from packaging
[maemo-rb.git] / firmware / powermgmt.c
blob379b91ca134175d4850f8051dea58aa3f89f26ed
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 #ifdef HAVE_REMOTE_LCD
47 #include "lcd-remote.h"
48 #endif
49 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
50 #include <time.h>
51 #endif
53 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
54 && !defined (SIMULATOR)
55 #include "pcf50606.h"
56 #endif
58 /** Shared by sim **/
59 int last_sent_battery_level = 100;
60 /* battery level (0-100%) */
61 int battery_percent = -1;
62 void send_battery_level_event(void);
64 static bool sleeptimer_active = false;
65 static long sleeptimer_endtick;
66 /* Whether an active sleep timer should be restarted when a key is pressed */
67 static bool sleeptimer_key_restarts = false;
68 /* The number of seconds the sleep timer was last set to */
69 static unsigned int sleeptimer_duration = 0;
71 #if CONFIG_CHARGING
72 /* State of the charger input as seen by the power thread */
73 enum charger_input_state_type charger_input_state;
74 /* Power inputs as seen by the power thread */
75 unsigned int power_thread_inputs;
76 #if CONFIG_CHARGING >= CHARGING_MONITOR
77 /* Charging state (mode) as seen by the power thread */
78 enum charge_state_type charge_state = DISCHARGING;
79 #endif
80 #endif /* CONFIG_CHARGING */
82 static int shutdown_timeout = 0;
84 void handle_auto_poweroff(void);
85 static int poweroff_timeout = 0;
86 static long last_event_tick = 0;
88 #if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE
89 int _battery_voltage(void) { return -1; }
91 const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
92 const unsigned short percent_to_volt_charge[11];
94 #elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE
95 int _battery_level(void) { return -1; }
97 * Average battery voltage and charger voltage, filtered via a digital
98 * exponential filter (aka. exponential moving average, scaled):
99 * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N.
101 static unsigned int avgbat;
102 /* filtered battery voltage, millivolts */
103 static unsigned int battery_millivolts;
104 #elif (CONFIG_BATTERY_MEASURE == 0)
105 int _battery_voltage(void) { return -1; }
106 int _battery_level(void) { return -1; }
108 const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
109 const unsigned short percent_to_volt_charge[11];
110 #endif
112 #if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE)
113 static int powermgmt_est_runningtime_min;
114 int _battery_time(void) { return powermgmt_est_runningtime_min; }
115 #endif
117 /* default value, mAh */
118 static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
120 #if BATTERY_TYPES_COUNT > 1
121 static int battery_type = 0;
122 #else
123 #define battery_type 0
124 #endif
126 /* Power history: power_history[0] is the newest sample */
127 unsigned short power_history[POWER_HISTORY_LEN] = {0};
129 #if CONFIG_CPU == JZ4732 /* FIXME! */ || (CONFIG_PLATFORM & PLATFORM_HOSTED)
130 static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK];
131 #else
132 static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
133 #endif
134 static const char power_thread_name[] = "power";
137 static int voltage_to_battery_level(int battery_millivolts);
138 static void battery_status_update(void);
140 #ifdef CURRENT_NORMAL /*only used if we have run current*/
141 static int runcurrent(void);
142 #endif
144 void battery_read_info(int *voltage, int *level)
146 int millivolts = _battery_voltage();
147 int percent;
149 if (voltage)
150 *voltage = millivolts;
152 if (level) {
153 percent = voltage_to_battery_level(millivolts);
154 if (percent < 0)
155 percent = _battery_level();
156 *level = percent;
160 #if BATTERY_TYPES_COUNT > 1
161 void set_battery_type(int type)
163 if (type != battery_type) {
164 if ((unsigned)type >= BATTERY_TYPES_COUNT)
165 type = 0;
167 battery_type = type;
168 battery_status_update(); /* recalculate the battery status */
171 #endif
173 #ifdef BATTERY_CAPACITY_MIN
174 void set_battery_capacity(int capacity)
176 if (capacity > BATTERY_CAPACITY_MAX)
177 capacity = BATTERY_CAPACITY_MAX;
178 if (capacity < BATTERY_CAPACITY_MIN)
179 capacity = BATTERY_CAPACITY_MIN;
181 battery_capacity = capacity;
183 battery_status_update(); /* recalculate the battery status */
185 #endif
187 int get_battery_capacity(void)
189 return battery_capacity;
192 int battery_time(void)
194 #if ((CONFIG_BATTERY_MEASURE & TIME_MEASURE) == 0)
196 #ifndef CURRENT_NORMAL /* no estimation without current */
197 return -1;
198 #endif
199 if (battery_capacity <= 0) /* nor without capacity */
200 return -1;
202 #endif
203 return _battery_time();
206 /* Returns battery level in percent */
207 int battery_level(void)
209 #ifdef HAVE_BATTERY_SWITCH
210 if ((power_input_status() & POWER_INPUT_BATTERY) == 0)
211 return -1;
212 #endif
213 return battery_percent;
216 /* Tells if the battery level is safe for disk writes */
217 bool battery_level_safe(void)
219 #if defined(NO_LOW_BATTERY_SHUTDOWN)
220 return true;
221 #elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
222 return (battery_percent > 0);
223 #elif defined(HAVE_BATTERY_SWITCH)
224 /* Cannot rely upon the battery reading to be valid and the
225 * device could be powered externally. */
226 return input_millivolts() > battery_level_dangerous[battery_type];
227 #else
228 return battery_millivolts > battery_level_dangerous[battery_type];
229 #endif
232 /* look into the percent_to_volt_* table and get a realistic battery level */
233 static int voltage_to_percent(int voltage, const short* table)
235 if (voltage <= table[0]) {
236 return 0;
238 else if (voltage >= table[10]) {
239 return 100;
241 else {
242 /* search nearest value */
243 int i = 0;
245 while (i < 10 && table[i+1] < voltage)
246 i++;
248 /* interpolate linear between the smaller and greater value */
249 /* Tens digit, 10% per entry, ones digit: interpolated */
250 return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]);
254 /* update battery level and estimated runtime, called once per minute or
255 * when battery capacity / type settings are changed */
256 static int voltage_to_battery_level(int battery_millivolts)
258 int level;
260 if (battery_millivolts < 0)
261 return -1;
263 #if CONFIG_CHARGING >= CHARGING_MONITOR
264 if (charging_state()) {
265 /* battery level is defined to be < 100% until charging is finished */
266 level = voltage_to_percent(battery_millivolts,
267 percent_to_volt_charge);
268 if (level > 99)
269 level = 99;
271 else
272 #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
274 /* DISCHARGING or error state */
275 level = voltage_to_percent(battery_millivolts,
276 percent_to_volt_discharge[battery_type]);
279 return level;
282 static void battery_status_update(void)
284 int millivolt = battery_voltage();
285 int level = _battery_level();
287 if (level < 0)
288 level = voltage_to_battery_level(millivolt);
290 #ifdef CURRENT_NORMAL /*don't try to estimate run or charge
291 time without normal current defined*/
292 /* calculate estimated remaining running time */
293 #if CONFIG_CHARGING >= CHARGING_MONITOR
294 if (charging_state()) {
295 /* charging: remaining charging time */
296 powermgmt_est_runningtime_min = (100 - level)*battery_capacity*60
297 / 100 / (CURRENT_MAX_CHG - runcurrent());
299 else
300 #endif
302 /* discharging: remaining running time */
303 if (level > 0 && (millivolt > percent_to_volt_discharge[battery_type][0]
304 || millivolt < 0)) {
305 /* linear extrapolation */
306 powermgmt_est_runningtime_min = (level + battery_percent)*60
307 * battery_capacity / 200 / runcurrent();
309 if (0 > powermgmt_est_runningtime_min) {
310 powermgmt_est_runningtime_min = 0;
312 #endif
314 battery_percent = level;
315 send_battery_level_event();
318 #ifdef CURRENT_NORMAL /*check that we have a current defined in a config file*/
321 * Estimate how much current we are drawing just to run.
323 static int runcurrent(void)
325 int current = CURRENT_NORMAL;
327 #ifndef BOOTLOADER
328 if (usb_inserted()
329 #ifdef HAVE_USB_POWER
330 #if (CURRENT_USB < CURRENT_NORMAL)
331 || usb_powered()
332 #else
333 && !usb_powered()
334 #endif
335 #endif
337 current = CURRENT_USB;
340 #if defined(HAVE_BACKLIGHT)
341 if (backlight_get_current_timeout() == 0) /* LED always on */
342 current += CURRENT_BACKLIGHT;
343 #endif
345 #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
346 if (audio_status() & AUDIO_STATUS_RECORD)
347 current += CURRENT_RECORD;
348 #endif
350 #ifdef HAVE_SPDIF_POWER
351 if (spdif_powered())
352 current += CURRENT_SPDIF_OUT;
353 #endif
355 #ifdef HAVE_REMOTE_LCD
356 if (remote_detect())
357 current += CURRENT_REMOTE;
358 #endif
360 #if defined(HAVE_ATA_POWER_OFF) && defined(CURRENT_ATA)
361 if (ide_powered())
362 current += CURRENT_ATA;
363 #endif
365 #endif /* BOOTLOADER */
367 return current;
370 #endif /* CURRENT_NORMAL */
372 /* Check to see whether or not we've received an alarm in the last second */
373 #ifdef HAVE_RTC_ALARM
374 static void power_thread_rtc_process(void)
376 if (rtc_check_alarm_flag())
377 rtc_enable_alarm(false);
379 #endif
381 /* switch off unit if battery level is too low for reliable operation */
382 bool query_force_shutdown(void)
384 #if defined(NO_LOW_BATTERY_SHUTDOWN)
385 return false;
386 #elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
387 return battery_percent == 0;
388 #elif defined(HAVE_BATTERY_SWITCH)
389 /* Cannot rely upon the battery reading to be valid and the
390 * device could be powered externally. */
391 return input_millivolts() < battery_level_shutoff[battery_type];
392 #else
393 return battery_millivolts < battery_level_shutoff[battery_type];
394 #endif
397 #if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
399 * Reset the battery voltage filter to a new value and update the
400 * status.
402 void reset_battery_filter(int millivolts)
404 avgbat = millivolts * BATT_AVE_SAMPLES;
405 battery_millivolts = millivolts;
406 battery_status_update();
408 #endif /* HAVE_BATTERY_SWITCH */
410 /** Generic charging algorithms for common charging types **/
411 #if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
412 static inline void powermgmt_init_target(void)
414 /* Nothing to do */
417 static inline void charging_algorithm_step(void)
419 /* Nothing to do */
422 static inline void charging_algorithm_close(void)
424 /* Nothing to do */
426 #elif CONFIG_CHARGING == CHARGING_MONITOR
428 * Monitor CHARGING/DISCHARGING state.
430 static inline void powermgmt_init_target(void)
432 /* Nothing to do */
435 static inline void charging_algorithm_step(void)
437 switch (charger_input_state)
439 case CHARGER_PLUGGED:
440 case CHARGER:
441 if (charging_state()) {
442 charge_state = CHARGING;
443 break;
445 /* Fallthrough */
446 case CHARGER_UNPLUGGED:
447 case NO_CHARGER:
448 charge_state = DISCHARGING;
449 break;
453 static inline void charging_algorithm_close(void)
455 /* Nothing to do */
457 #endif /* CONFIG_CHARGING == * */
459 #if CONFIG_CHARGING
460 /* Shortcut function calls - compatibility, simplicity. */
462 /* Returns true if any power input is capable of charging. */
463 bool charger_inserted(void)
465 return power_thread_inputs & POWER_INPUT_CHARGER;
468 /* Returns true if any power input is connected - charging-capable
469 * or not. */
470 bool power_input_present(void)
472 return power_thread_inputs & POWER_INPUT;
476 * Detect charger inserted. Return true if the state is transistional.
478 static inline bool detect_charger(unsigned int pwr)
481 * Detect charger plugged/unplugged transitions. On a plugged or
482 * unplugged event, we return immediately, run once through the main
483 * loop (including the subroutines), and end up back here where we
484 * transition to the appropriate steady state charger on/off state.
486 if (pwr & POWER_INPUT_CHARGER) {
487 switch (charger_input_state)
489 case NO_CHARGER:
490 case CHARGER_UNPLUGGED:
491 charger_input_state = CHARGER_PLUGGED;
492 break;
494 case CHARGER_PLUGGED:
495 queue_broadcast(SYS_CHARGER_CONNECTED, 0);
496 last_sent_battery_level = 0;
497 charger_input_state = CHARGER;
498 break;
500 case CHARGER:
501 /* Steady state */
502 return false;
505 else { /* charger not inserted */
506 switch (charger_input_state)
508 case NO_CHARGER:
509 /* Steady state */
510 return false;
512 case CHARGER_UNPLUGGED:
513 queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
514 last_sent_battery_level = 100;
515 charger_input_state = NO_CHARGER;
516 break;
518 case CHARGER_PLUGGED:
519 case CHARGER:
520 charger_input_state = CHARGER_UNPLUGGED;
521 break;
525 /* Transitional state */
526 return true;
528 #endif /* CONFIG_CHARGING */
531 #if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
532 /* Returns filtered battery voltage [millivolts] */
533 int battery_voltage(void)
535 return battery_millivolts;
538 static void average_init(void)
540 /* initialize the voltages for the exponential filter */
541 avgbat = _battery_voltage() + 15;
543 #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
544 /* The battery voltage is usually a little lower directly after
545 turning on, because the disk was used heavily. Raise it by 5% */
546 #if CONFIG_CHARGING
547 if (!charger_inserted()) /* only if charger not connected */
548 #endif
550 avgbat += (percent_to_volt_discharge[battery_type][6] -
551 percent_to_volt_discharge[battery_type][5]) / 2;
553 #endif /* HAVE_DISK_STORAGE */
555 avgbat = avgbat * BATT_AVE_SAMPLES;
556 battery_millivolts = power_history[0] = avgbat / BATT_AVE_SAMPLES;
559 static void average_step(void)
561 avgbat += _battery_voltage() - avgbat / BATT_AVE_SAMPLES;
563 * battery_millivolts is the millivolt-scaled filtered battery value.
565 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
568 static void average_step_low(void)
570 battery_millivolts = (_battery_voltage() + battery_millivolts + 1) / 2;
571 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
574 static void init_battery_percent(void)
576 #if CONFIG_CHARGING
577 if (charger_inserted()) {
578 battery_percent = voltage_to_percent(battery_millivolts,
579 percent_to_volt_charge);
581 else
582 #endif
584 battery_percent = voltage_to_percent(battery_millivolts,
585 percent_to_volt_discharge[battery_type]);
586 battery_percent += battery_percent < 100;
591 static int power_hist_item(void)
593 return battery_millivolts;
595 #define power_history_unit() battery_millivolts
597 #else
598 int battery_voltage(void)
600 return -1;
603 static void average_init(void) {}
604 static void average_step(void) {}
605 static void average_step_low(void) {}
606 static void init_battery_percent(void)
608 battery_percent = _battery_level();
611 static int power_hist_item(void)
613 return battery_percent;
615 #endif
617 static void collect_power_history(void)
619 /* rotate the power history */
620 memmove(&power_history[1], &power_history[0],
621 sizeof(power_history) - sizeof(power_history[0]));
622 power_history[0] = power_hist_item();
626 * Monitor the presence of a charger and perform critical frequent steps
627 * such as running the battery voltage filter.
629 static inline void power_thread_step(void)
631 /* If the power off timeout expires, the main thread has failed
632 to shut down the system, and we need to force a power off */
633 if (shutdown_timeout) {
634 shutdown_timeout -= POWER_THREAD_STEP_TICKS;
636 if (shutdown_timeout <= 0)
637 power_off();
640 #ifdef HAVE_RTC_ALARM
641 power_thread_rtc_process();
642 #endif
645 * Do a digital exponential filter. We don't sample the battery if
646 * the disk is spinning unless we are in USB mode (the disk will most
647 * likely always be spinning in USB mode) or charging.
649 if (!storage_disk_is_active() || usb_inserted()
650 #if CONFIG_CHARGING >= CHARGING_MONITOR
651 || charger_input_state == CHARGER
652 #endif
654 average_step();
655 /* update battery status every time an update is available */
656 battery_status_update();
658 else if (battery_percent < 8) {
659 average_step_low();
660 /* update battery status every time an update is available */
661 battery_status_update();
664 * If battery is low, observe voltage during disk activity.
665 * Shut down if voltage drops below shutoff level and we are not
666 * using NiMH or Alkaline batteries.
668 if (!shutdown_timeout && query_force_shutdown()) {
669 sys_poweroff();
672 } /* power_thread_step */
674 static void power_thread(void)
676 long next_power_hist;
678 /* Delay reading the first battery level */
679 #ifdef MROBE_100
680 while (_battery_voltage() > 4200) /* gives false readings initially */
681 #endif
683 sleep(HZ/100);
686 #if CONFIG_CHARGING
687 /* Initialize power input status before calling other routines. */
688 power_thread_inputs = power_input_status();
689 #endif
691 /* initialize voltage averaging (if available) */
692 average_init();
693 /* get initial battery level value (in %) */
694 init_battery_percent();
695 /* get some initial data for the power curve */
696 collect_power_history();
697 /* call target specific init now */
698 powermgmt_init_target();
700 next_power_hist = current_tick + HZ*60;
702 while (1)
704 #if CONFIG_CHARGING
705 unsigned int pwr = power_input_status();
706 #ifdef HAVE_BATTERY_SWITCH
707 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
708 sleep(HZ/10);
709 reset_battery_filter(_battery_voltage());
711 #endif
712 power_thread_inputs = pwr;
714 if (!detect_charger(pwr))
715 #endif /* CONFIG_CHARGING */
717 /* Steady state */
718 sleep(POWER_THREAD_STEP_TICKS);
720 /* Do common power tasks */
721 power_thread_step();
724 /* Perform target tasks */
725 charging_algorithm_step();
727 /* check if some idle or sleep timer wears off */
728 handle_auto_poweroff();
730 if (TIME_AFTER(current_tick, next_power_hist)) {
731 /* increment to ensure there is a record for every minute
732 * rather than go forward from the current tick */
733 next_power_hist += HZ*60;
734 collect_power_history();
737 } /* power_thread */
739 void powermgmt_init(void)
741 create_thread(power_thread, power_stack, sizeof(power_stack), 0,
742 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
743 IF_COP(, CPU));
746 /* Various hardware housekeeping tasks relating to shutting down the player */
747 void shutdown_hw(void)
749 charging_algorithm_close();
750 audio_stop();
752 if (battery_level_safe()) { /* do not save on critical battery */
753 #ifdef HAVE_LCD_BITMAP
754 font_unload_all();
755 #endif
757 /* Commit pending writes if needed. Even though we don't do write caching,
758 things like flash translation layers may need this to commit scattered
759 pages to there final locations. So far only used for iPod Nano 2G. */
760 #ifdef HAVE_STORAGE_FLUSH
761 storage_flush();
762 #endif
764 if (storage_disk_is_active())
765 storage_spindown(1);
768 #if CONFIG_CODEC == SWCODEC
769 audiohw_close();
770 #else
771 mp3_shutdown();
772 #endif
774 /* If HD is still active we try to wait for spindown, otherwise the
775 shutdown_timeout in power_thread_step will force a power off */
776 while (storage_disk_is_active())
777 sleep(HZ/10);
779 #ifndef HAVE_LCD_COLOR
780 lcd_set_contrast(0);
781 #endif
782 #ifdef HAVE_REMOTE_LCD
783 lcd_remote_set_contrast(0);
784 #endif
785 #ifdef HAVE_LCD_SHUTDOWN
786 lcd_shutdown();
787 #endif
789 /* Small delay to make sure all HW gets time to flush. Especially
790 eeprom chips are quite slow and might be still writing the last
791 byte. */
792 sleep(HZ/4);
793 power_off();
796 void set_poweroff_timeout(int timeout)
798 poweroff_timeout = timeout;
801 void reset_poweroff_timer(void)
803 last_event_tick = current_tick;
804 if (sleeptimer_active && sleeptimer_key_restarts)
805 set_sleep_timer(sleeptimer_duration);
808 void sys_poweroff(void)
810 #ifndef BOOTLOADER
811 logf("sys_poweroff()");
812 /* If the main thread fails to shut down the system, we will force a
813 power off after an 20 second timeout - 28 seconds if recording */
814 if (shutdown_timeout == 0) {
815 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
816 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
817 #endif
818 #ifdef HAVE_RECORDING
819 if (audio_status() & AUDIO_STATUS_RECORD)
820 shutdown_timeout += HZ*8;
821 #endif
822 #ifdef IPOD_NANO2G
823 /* The FTL alone may take half a minute to shut down cleanly. */
824 shutdown_timeout += HZ*60;
825 #else
826 shutdown_timeout += HZ*20;
827 #endif
830 queue_broadcast(SYS_POWEROFF, 0);
831 #endif /* BOOTLOADER */
834 void cancel_shutdown(void)
836 logf("cancel_shutdown()");
838 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
839 /* TODO: Move some things to target/ tree */
840 if (shutdown_timeout)
841 pcf50606_reset_timeout();
842 #endif
844 shutdown_timeout = 0;
847 /* Send system battery level update events on reaching certain significant
848 levels. This must be called after battery_percent has been updated. */
849 void send_battery_level_event(void)
851 static const int levels[] = { 5, 15, 30, 50, 0 };
852 const int *level = levels;
854 while (*level)
856 if (battery_percent <= *level && last_sent_battery_level > *level) {
857 last_sent_battery_level = *level;
858 queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level);
859 break;
862 level++;
866 void set_sleep_timer(int seconds)
868 if (seconds) {
869 sleeptimer_active = true;
870 sleeptimer_endtick = current_tick + seconds * HZ;
872 else {
873 sleeptimer_active = false;
874 sleeptimer_endtick = 0;
876 sleeptimer_duration = seconds;
879 int get_sleep_timer(void)
881 if (sleeptimer_active && (sleeptimer_endtick >= current_tick))
882 return (sleeptimer_endtick - current_tick) / HZ;
883 else
884 return 0;
887 void set_keypress_restarts_sleep_timer(bool enable)
889 sleeptimer_key_restarts = enable;
892 #ifndef BOOTLOADER
893 static void handle_sleep_timer(void)
895 if (!sleeptimer_active)
896 return;
898 /* Handle sleeptimer */
899 if (TIME_AFTER(current_tick, sleeptimer_endtick)) {
900 if (usb_inserted()
901 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
902 || charger_input_state != NO_CHARGER
903 #endif
905 DEBUGF("Sleep timer timeout. Stopping...\n");
906 audio_pause();
907 set_sleep_timer(0);
908 backlight_off(); /* Nighty, nighty... */
910 else {
911 DEBUGF("Sleep timer timeout. Shutting off...\n");
912 sys_poweroff();
916 #endif /* BOOTLOADER */
919 * We shut off in the following cases:
920 * 1) The unit is idle, not playing music
921 * 2) The unit is playing music, but is paused
922 * 3) The battery level has reached shutdown limit
924 * We do not shut off in the following cases:
925 * 1) The USB is connected
926 * 2) The charger is connected
927 * 3) We are recording, or recording with pause
928 * 4) The radio is playing
930 void handle_auto_poweroff(void)
932 #ifndef BOOTLOADER
933 long timeout = poweroff_timeout*60*HZ;
934 int audio_stat = audio_status();
935 long tick = current_tick;
938 * Inhibit shutdown as long as the charger is plugged in. If it is
939 * unplugged, wait for a timeout period and then shut down.
941 if (audio_stat == AUDIO_STATUS_PLAY
942 #if CONFIG_CHARGING
943 || charger_input_state == CHARGER
944 #endif
946 last_event_tick = current_tick;
949 if (!shutdown_timeout && query_force_shutdown()) {
950 backlight_on();
951 sys_poweroff();
954 if (timeout &&
955 #if CONFIG_TUNER
956 !(get_radio_status() & FMRADIO_PLAYING) &&
957 #endif
958 !usb_inserted() &&
959 (audio_stat == 0 ||
960 (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) &&
961 !sleeptimer_active))) {
963 if (TIME_AFTER(tick, last_event_tick + timeout)
964 #if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
965 && TIME_AFTER(tick, storage_last_disk_activity() + timeout)
966 #endif
968 sys_poweroff();
970 } else
971 handle_sleep_timer();
972 #endif