Index: apps/main.c =================================================================== --- apps/main.c (Revision 24869) +++ apps/main.c (Arbeitskopie) @@ -316,6 +316,9 @@ sim_tasks_init(); lang_init(core_language_builtin, language_strings, LANG_LAST_INDEX_IN_ARRAY); + /* simulated power-thread */ + powermgmt_init(); + #ifdef DEBUG debug_init(); #endif Index: firmware/export/powermgmt.h =================================================================== --- firmware/export/powermgmt.h (Revision 24869) +++ firmware/export/powermgmt.h (Arbeitskopie) @@ -117,11 +117,6 @@ #define BATT_AVE_SAMPLES 128 #endif -#ifndef POWER_THREAD_STEP_TICKS -/* 2HZ sample rate unless otherwise specified */ -#define POWER_THREAD_STEP_TICKS (HZ/2) -#endif - extern unsigned short power_history[POWER_HISTORY_LEN]; extern const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT]; extern const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT]; @@ -130,10 +125,16 @@ extern const unsigned short percent_to_volt_charge[11]; #endif +#endif /* SIMULATOR */ + +/* now for the simulator too */ +#ifndef POWER_THREAD_STEP_TICKS +/* 2HZ sample rate unless otherwise specified */ +#define POWER_THREAD_STEP_TICKS (HZ/2) +#endif /* Start up power management thread */ void powermgmt_init(void); -#endif /* SIMULATOR */ /* Returns battery statust */ int battery_level(void); /* percent */ Index: uisimulator/common/stubs.c =================================================================== --- uisimulator/common/stubs.c (Revision 24869) +++ uisimulator/common/stubs.c (Arbeitskopie) @@ -278,17 +278,6 @@ (void)pitch; } -static int sleeptime; -void set_sleep_timer(int seconds) -{ - sleeptime = seconds; -} - -int get_sleep_timer(void) -{ - return sleeptime; -} - #ifdef HAVE_LCD_CHARCELLS void lcd_clearrect (int x, int y, int nx, int ny) { Index: uisimulator/common/powermgmt-sim.c =================================================================== --- uisimulator/common/powermgmt-sim.c (Revision 24869) +++ uisimulator/common/powermgmt-sim.c (Arbeitskopie) @@ -24,12 +24,27 @@ #include #include "kernel.h" #include "powermgmt.h" +#include "power.h" +#include "debug.h" +#include "string.h" +#include "audio.h" +#include "SDL.h" + #define BATT_MINMVOLT 2500 /* minimum millivolts of battery */ #define BATT_MAXMVOLT 4500 /* maximum millivolts of battery */ #define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in minutes */ +static bool sleeptimer_active = false; +static long sleeptimer_endtick; +static long last_event_tick; +static int poweroff_timeout = 0; +static int shutdown_timeout = 0; +static char power_stack[DEFAULT_STACK_SIZE/2]; +static const char power_thread_name[] = "power"; + + extern void send_battery_level_event(void); extern int last_sent_battery_level; extern int battery_percent; @@ -121,6 +136,8 @@ void set_poweroff_timeout(int timeout) { (void)timeout; + DEBUGF("set_poweroff_timeout(%d)\n",timeout); + poweroff_timeout = timeout; } void set_battery_capacity(int capacity) @@ -144,16 +161,139 @@ void reset_poweroff_timer(void) { + DEBUGF("reset_poweroff_timer()\n"); + last_event_tick = current_tick; } +/* + * We shut (really!) off in the following cases: + * + * 1) The simulation is idle, not playing music (idle timeout) + * 2) The simulation is playing music, but is paused (idle timeout) + * 3) The simulation is playing music, sleep timer is active and timer has run out (sleep timer) + */ +static void handle_auto_poweroff(void) +{ + long timeout = poweroff_timeout*60*HZ; + int audio_stat = audio_status(); + long tick = current_tick; + + /* idle timeout is handled here */ + if (timeout && + (audio_stat == 0 || + (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) && + !sleeptimer_active))) { + + if (TIME_AFTER(tick, last_event_tick + timeout)) { + sys_poweroff(); + } + } + /* sleep timer is handled here */ + else if (sleeptimer_active) { + /* Handle sleeptimer */ + if (TIME_AFTER(tick, sleeptimer_endtick)) { + sys_poweroff(); + + } + } +} + void shutdown_hw(void) { } +static inline void power_thread_step(void) +{ + /* If the power off timeout expires, the main thread has failed + to shut down the system, and we need to force a power off */ + if (shutdown_timeout) { + shutdown_timeout -= POWER_THREAD_STEP_TICKS; + DEBUGF("shutdown by power_thread_stop()"); + if (shutdown_timeout <= 0) + power_off(); + } + +} /* power_thread_step */ + + +static void power_thread(void) +{ + DEBUGF("power_thread starts\n"); + long next_power_hist; + + next_power_hist = current_tick + HZ*60; + + while (1) + { + DEBUGF("power_thread() - current_tick %ld - next_power_hist %ld\n",current_tick, next_power_hist); + + /* Do common power tasks */ + power_thread_step(); + + /* Steady state */ + sleep(POWER_THREAD_STEP_TICKS); + + if (TIME_BEFORE(current_tick, next_power_hist)) + continue; + + /* increment to ensure there is a record for every minute + * rather than go forward from the current tick */ + next_power_hist += HZ*60; + + handle_auto_poweroff(); + } +} /* power_thread */ + + +void powermgmt_init(void) +{ + /* init history to 0 */ + create_thread(power_thread, power_stack, sizeof(power_stack), 0, + power_thread_name IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU)); +} + +void set_sleep_timer(int seconds) +{ + if (seconds) { + sleeptimer_active = true; + sleeptimer_endtick = current_tick + seconds * HZ; + DEBUGF("set sleep timer to %d seconds (%d minutes)\n", seconds, seconds/60); + } else { + sleeptimer_active = false; + sleeptimer_endtick = 0; + DEBUGF("sleep timer disabled\n"); + } +} + +int get_sleep_timer(void) +{ + if (sleeptimer_active) { + if (TIME_AFTER(sleeptimer_endtick, current_tick)) + return (sleeptimer_endtick - current_tick) / HZ; + set_sleep_timer(0); + } + return 0; +} + void sys_poweroff(void) { + DEBUGF("sys_poweroff()\n"); + queue_broadcast(SYS_POWEROFF, 0); + power_off(); } void cancel_shutdown(void) { } + +extern int playlist_update_resume_info(const struct mp3entry* id3); +void power_off(void) +{ + /* just to be sure the offset is actual */ + playlist_update_resume_info(audio_current_track()); + + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent (&event); +}