Index: apps/playlist.c =================================================================== --- apps/playlist.c (Revision 24785) +++ apps/playlist.c (Arbeitskopie) @@ -2610,7 +2610,6 @@ int playlist_update_resume_info(const struct mp3entry* id3) { struct playlist_info* playlist = ¤t_playlist; - if (id3) { if (global_status.resume_index != playlist->index || @@ -2619,6 +2618,9 @@ global_status.resume_index = playlist->index; global_status.resume_offset = id3->offset; status_save(); + DEBUGF("Saveing index %X offset %lX\n", + global_status.resume_index, + (unsigned long)global_status.resume_offset); } } else Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (Revision 24785) +++ apps/lang/english.lang (Arbeitskopie) @@ -4613,7 +4613,7 @@ id: LANG_SLEEP_TIMER - desc: sleep timer setting + desc: sleep timer menu user: core *: "Sleep Timer" @@ -4626,6 +4626,62 @@ + id: LANG_SLEEP_TIMER_START + desc: start sleep timer + user: core + + *: "Start Timer" + + + *: "Start Timer" + + + *: "Start Timer" + + + + id: LANG_SLEEP_TIMER_STOP + desc: stop sleep timer + user: core + + *: "Stop Timer" + + + *: "Stop Timer" + + + *: "Stop Timer" + + + + id: LANG_SLEEP_TIMER_DURATION + desc: sleep timer duration in minutes + user: core + + *: "Timer Duration" + + + *: "Timer Duration" + + + *: "Timer Duration" + + + + id: LANG_SLEEP_TIMER_ON_POWER_UP + desc: whether sleep timer starts on power up + user: core + + *: "Start Timer On Power Up?" + + + *: "Start Timer On Power Up?" + + + *: "Start Timer On Power Up?" + + + id: LANG_LIMITS_MENU desc: in the system sub menu user: core Index: apps/gui/wps.c =================================================================== --- apps/gui/wps.c (Revision 24785) +++ apps/gui/wps.c (Arbeitskopie) @@ -731,6 +731,7 @@ * In either way, call gwps_leave_wps(), in order to restore the correct * "main screen" backdrops and statusbars */ +extern void set_sleep_timer(int seconds); long gui_wps_show(void) { long button = 0; @@ -888,6 +889,12 @@ fade(true, true); else audio_resume(); + /* Restart sleep Timer if it is currently enabled for startup */ + if (global_settings.sleeptimer_on_startup == true) + { + set_sleep_timer(global_settings.sleeptimer_duration * 60); + } + } else { Index: apps/settings.h =================================================================== --- apps/settings.h (Revision 24785) +++ apps/settings.h (Arbeitskopie) @@ -806,6 +806,9 @@ int compressor_release_time; #endif + int sleeptimer_duration; + bool sleeptimer_on_startup; + #ifdef HAVE_MORSE_INPUT bool morse_input; /* text input method setting */ #endif Index: apps/menus/time_menu.c =================================================================== --- apps/menus/time_menu.c (Revision 24785) +++ apps/menus/time_menu.c (Arbeitskopie) @@ -82,9 +82,6 @@ timedate_set, NULL, NULL, Icon_NOICON); MENUITEM_SETTING(timeformat, &global_settings.timeformat, NULL); -/* in main_menu.c */ -extern const struct menu_item_ex sleep_timer_call; - #ifdef HAVE_RTC_ALARM MENUITEM_FUNCTION(alarm_screen_call, 0, ID2P(LANG_ALARM_MOD_ALARM_MENU), (menu_function)alarm_screen, NULL, NULL, Icon_NOICON); @@ -240,7 +237,7 @@ MAKE_MENU(time_menu, ID2P(LANG_TIME_MENU), time_menu_callback, Icon_NOICON, - &time_set, &sleep_timer_call, + &time_set, #ifdef HAVE_RTC_ALARM &alarm_screen_call, #if defined(HAVE_RECORDING) || CONFIG_TUNER Index: apps/menus/exported_menus.h =================================================================== --- apps/menus/exported_menus.h (Revision 24785) +++ apps/menus/exported_menus.h (Arbeitskopie) @@ -26,22 +26,23 @@ #ifndef PLUGIN extern const struct menu_item_ex - main_menu_, /* main_menu.c */ - display_menu, /* display_menu.c */ - playback_settings, /* playback_menu.c */ + main_menu_, /* main_menu.c */ + display_menu, /* display_menu.c */ + playback_settings, /* playback_menu.c */ #ifdef HAVE_RECORDING - recording_settings, /* recording_menu.c */ + recording_settings, /* recording_menu.c */ #ifdef HAVE_LCD_BITMAP peak_meter_menu, /* also used from within recording_menu */ #endif #endif - sound_settings, /* sound_menu.c */ - settings_menu_item, /* settings_menu.c */ - playlist_settings, /* playlist_menu.c */ - playlist_options, /* playlist_menu.c */ - equalizer_menu, /* eq_menu.c */ - info_menu, /* info_menu.c */ - theme_menu; /* theme_menu.c */ + sound_settings, /* sound_menu.c */ + settings_menu_item, /* settings_menu.c */ + playlist_settings, /* playlist_menu.c */ + playlist_options, /* playlist_menu.c */ + equalizer_menu, /* eq_menu.c */ + info_menu, /* info_menu.c */ + theme_menu, /* theme_menu.c */ + sleeptimer_menu; /* sleeptimer_menu.c */ struct browse_folder_info { const char* dir; Index: apps/menus/main_menu.c =================================================================== --- apps/menus/main_menu.c (Revision 24785) +++ apps/menus/main_menu.c (Arbeitskopie) @@ -382,46 +382,11 @@ MENUITEM_FUNCTION(show_info_item, 0, ID2P(LANG_ROCKBOX_INFO), (menu_function)show_info, NULL, NULL, Icon_NOICON); - -/* sleep Menu */ -static const char* sleep_timer_formatter(char* buffer, size_t buffer_size, - int value, const char* unit) -{ - (void) unit; - int minutes, hours; - - if (value) { - hours = value / 60; - minutes = value - (hours * 60); - snprintf(buffer, buffer_size, "%d:%02d", hours, minutes); - return buffer; - } else { - return str(LANG_OFF); - } -} - -static void sleep_timer_set(int minutes) -{ - set_sleep_timer(minutes * 60); -} - -static int sleep_timer(void) -{ - int minutes = (get_sleep_timer() + 59) / 60; /* round up */ - return (int)set_int(str(LANG_SLEEP_TIMER), "", UNIT_MIN, &minutes, - &sleep_timer_set, -5, 300, 0, sleep_timer_formatter); -} - - #if CONFIG_RTC int time_screen(void* ignored); MENUITEM_FUNCTION(timedate_item, MENU_FUNC_CHECK_RETVAL, ID2P(LANG_TIME_MENU), time_screen, NULL, NULL, Icon_Menu_setting ); #endif -/* This item is in the time/date screen if there is a RTC */ -MENUITEM_FUNCTION(sleep_timer_call, 0, ID2P(LANG_SLEEP_TIMER), sleep_timer, - NULL, NULL, Icon_Menu_setting); /* make it look like a - setting to the user */ MENUITEM_FUNCTION(show_credits_item, 0, ID2P(LANG_CREDITS), (menu_function)show_credits, NULL, NULL, Icon_NOICON); @@ -434,11 +399,9 @@ #if CONFIG_RTC &timedate_item, #endif - &show_info_item, &show_credits_item, &show_runtime_item, -#if CONFIG_RTC == 0 - &sleep_timer_call, -#endif - &debug_menu_item); + &sleeptimer_menu, &show_info_item, &show_credits_item, + &show_runtime_item, &debug_menu_item); + /* INFO MENU */ /***********************************/ Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (Revision 24785) +++ apps/settings_list.c (Arbeitskopie) @@ -529,6 +529,15 @@ memcpy(setting, defaultval, sizeof(struct touchscreen_parameter)); } #endif +static const char* sleeptimer_formatter(char* buffer, size_t buffer_size, + int value, const char* unit) +{ + (void) unit; + snprintf(buffer, buffer_size, "%d:%02d", + value / 60, value % 60); + //DEBUGF("sleeptimer_formatter.value = %02d\n",value); + return buffer; +} const struct settings_list settings[] = { /* sound settings */ SOUND_SETTING(F_NO_WRAP,volume, LANG_VOLUME, "volume", SOUND_VOLUME), @@ -1570,6 +1579,9 @@ #endif /* CONFIG_CODEC == SWCODEC */ TEXT_SETTING(0, playlist_catalog_dir, "playlist catalog directory", PLAYLIST_CATALOG_DEFAULT_DIR, NULL, NULL), + INT_SETTING(0, sleeptimer_duration, LANG_SLEEP_TIMER_DURATION, 30, "sleeptimer duration", + UNIT_MIN, 300, 5, -5, sleeptimer_formatter, NULL, NULL), + OFFON_SETTING(0, sleeptimer_on_startup, LANG_SLEEP_TIMER_ON_POWER_UP, false, "sleeptimer on startup", NULL), #ifdef HAVE_TOUCHPAD_SENSITIVITY_SETTING CHOICE_SETTING(0, touchpad_sensitivity, LANG_TOUCHPAD_SENSITIVITY, 0, "touchpad sensitivity", "normal,high", touchpad_set_sensitivity, 2, Index: apps/SOURCES =================================================================== --- apps/SOURCES (Revision 24785) +++ apps/SOURCES (Arbeitskopie) @@ -32,6 +32,7 @@ #if CONFIG_RTC menus/time_menu.c #endif +menus/sleeptimer_menu.c misc.c mp3data.c onplay.c Index: apps/root_menu.c =================================================================== --- apps/root_menu.c (Revision 24785) +++ apps/root_menu.c (Arbeitskopie) @@ -575,6 +575,12 @@ next_screen = GO_TO_ROOT; #endif + /* + * Only start sleeptimer while playing + */ + if (next_screen == GO_TO_WPS && global_settings.sleeptimer_on_startup) + set_sleep_timer(global_settings.sleeptimer_duration * 60); + while (true) { switch (next_screen) Index: apps/main.c =================================================================== --- apps/main.c (Revision 24785) +++ apps/main.c (Arbeitskopie) @@ -299,7 +299,7 @@ #endif #ifdef SIMULATOR - +extern void powermgmt_init(void); static void init(void) { kernel_init(); @@ -316,6 +316,9 @@ sim_tasks_init(); lang_init(core_language_builtin, language_strings, LANG_LAST_INDEX_IN_ARRAY); + /* test the function of SleepTimer */ + powermgmt_init(); + #ifdef DEBUG debug_init(); #endif Index: firmware/powermgmt.c =================================================================== --- firmware/powermgmt.c (Revision 24785) +++ firmware/powermgmt.c (Arbeitskopie) @@ -345,21 +345,22 @@ else if (sleeptimer_active) { /* Handle sleeptimer */ if (TIME_AFTER(tick, sleeptimer_endtick)) { - audio_stop(); + audio_pause(); + sleeptimer_active = false; if (usb_inserted() #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) || charger_input_state != NO_CHARGER #endif ) { - DEBUGF("Sleep timer timeout. Stopping...\n"); set_sleep_timer(0); backlight_off(); /* Nighty, nighty... */ + } - else { - DEBUGF("Sleep timer timeout. Shutting off...\n"); - sys_poweroff(); - } + //else { + // DEBUGF("Sleep timer timeout. Shutting off...\n"); + // sys_poweroff(); + //} } } } Index: manual/appendix/config_file_options.tex =================================================================== --- manual/appendix/config_file_options.tex (Revision 24785) +++ manual/appendix/config_file_options.tex (Arbeitskopie) @@ -359,6 +359,9 @@ jump scroll delay & 0 to 250 & 0.01s\\ }% + sleeptimer duration & 5 to 300 (in steps of 5) + & minutes\\ + sleeptimer on startup & off, on & N/A\\ \bottomrule \end{longtable} Index: manual/main_menu/main.tex =================================================================== --- manual/main_menu/main.tex (Revision 24785) +++ manual/main_menu/main.tex (Arbeitskopie) @@ -195,11 +195,6 @@ Time related menu options. Pressing \ActionStdContext{} will voice the current time if voice support is enabled \begin{description} \item [Set Time/Date: ] Set current time and date. - \item[Sleep Timer:] - The \setting{Sleep Timer} powers off your \dap{} after playing for a given - time. It can be set from \setting{Off} to 5 hours in 5 minute steps. - The \setting{Sleep Timer} is reset on boot. - \opt{alarm}{Using this option disables the \setting{Wake up alarm}.} \item [Time Format: ] Choose 12 or 24 hour clock. \opt{alarm}{ \subsection{Wake-Up Alarm} @@ -220,6 +215,27 @@ } \end{description} } + +\item[Sleep Timer:] + Sleep Timer related menu options. + The \setting{Sleep Timer} powers off your \dap{} after a given time. + \opt{alarm}{The \setting{Wake up alarm} is disabled while the timer is active.} + \begin{description} + \item[Start Timer (\emph{duration}):] + Shown when the timer is inactive, this option will initiate the timer with the duration shown in brackets. + \item[Stop Timer (\emph{remaining}):] + Shown when the timer is active, this option will disable the current timer. + The time remaining before completion is shown in brackets. + \item[Timer Duration:] + The number of minutes from when new timers are initiated to their completion. + The values range from 5 minutes to 5 hours in 5 minute steps. + If a timer is currently active, the timer's duration will be set to the newly entered value. + The value set is persistent, see \reference{ref:config_file_options}. + \item[Start Timer On Power Up?:] + If set, a timer will be initiated when the device starts. + The value set is persistent. + \end{description} + \item[Rockbox Info:] Displays some basic system information. This is, from top to bottom, the amount of memory Rockbox has available for storing music (the buffer). @@ -236,14 +252,6 @@ \item[Credits:] Display the list of contributors. -\nopt{rtc}{ - \item[Sleep Timer:] - The \setting{Sleep Timer} powers off your \dap{} after playing for a given - time. It can be set from \setting{Off} to 5 hours in 5 minute steps. - The \setting{Sleep Timer} is reset on boot. - \opt{alarm}{Using this option disables the \setting{Wake up alarm}.} -} - \item[Debug (Keep Out!):] This sub menu is intended to be used \emph{only} by Rockbox developers. It shows hardware, disk, battery status and other technical information. Index: uisimulator/common/stubs.c =================================================================== --- uisimulator/common/stubs.c (Revision 24785) +++ uisimulator/common/stubs.c (Arbeitskopie) @@ -35,6 +35,8 @@ #include "ata.h" /* for volume definitions */ +#include "kernel.h" /* access to current_tick */ + extern char having_new_lcd; static bool storage_spinning = false; @@ -278,16 +280,33 @@ (void)pitch; } -static int sleeptime; +/* +static bool sleeptimer_active = false; +static long sleeptimer_endtick; void set_sleep_timer(int seconds) { - sleeptime = seconds; + if (seconds) { + DEBUGF("Setting sleep timer to %d seconds (%d minutes)\n", seconds, seconds/60); + sleeptimer_active = true; + sleeptimer_endtick = current_tick + seconds * HZ; + } else { + DEBUGF("Disabling sleep timer\n"); + sleeptimer_active = false; + sleeptimer_endtick = 0; + } } int get_sleep_timer(void) { - return sleeptime; + if (sleeptimer_active) { + if (TIME_AFTER(sleeptimer_endtick, current_tick)) + return (sleeptimer_endtick - current_tick) / HZ; + DEBUGF("Sleep timer finished\n"); + set_sleep_timer(0); + } + return 0; } +*/ #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 24785) +++ uisimulator/common/powermgmt-sim.c (Arbeitskopie) @@ -23,13 +23,44 @@ #include "system.h" #include #include "kernel.h" +#include "power.h" #include "powermgmt.h" +#include "debug.h" +#include "string.h" +#include "audio.h" +#include "thread-sdl.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; + +/* Power history: power_history[0] is the newest sample */ +unsigned short power_history[POWER_HISTORY_LEN]; + +#define POWERMGMT_DEBUG_STACK 0 + +/* 2HZ sample rate unless otherwise specified */ +#define POWER_THREAD_STEP_TICKS (HZ/2) + + +#if CONFIG_CPU == JZ4732 /* FIXME! */ +static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK]; +#else +static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK]; +#endif +static const char power_thread_name[] = "power"; +//static int poweroff_timeout = 0; +//static int shutdown_timeout = 0; + + extern void send_battery_level_event(void); extern int last_sent_battery_level; extern int battery_percent; @@ -103,24 +134,28 @@ int battery_level(void) { + //DEBUGF("battery_level()\n"); battery_status_update(); return battery_percent; } int battery_time(void) { + //DEBUGF("battery_time()\n"); battery_status_update(); return powermgmt_est_runningtime_min; } bool battery_level_safe(void) { + //DEBUGF("battery_level_safe()\n"); return battery_level() >= 10; } void set_poweroff_timeout(int timeout) { - (void)timeout; + DEBUGF("set_poweroff_timeout(%d)",timeout); + poweroff_timeout = timeout; } void set_battery_capacity(int capacity) @@ -142,18 +177,147 @@ } #endif + + +/* + * We shut off in the following cases: + * 1) The unit is idle, not playing music + * 2) The unit is playing music, but is paused + * 3) The battery level has reached shutdown limit + * + * We do not shut off in the following cases: + * 1) The USB is connected + * 2) The charger is connected + * 3) We are recording, or recording with pause + * 4) The radio is playing + */ +static void handle_auto_poweroff(void) +{ + DEBUGF("handle_auto_poweroff()\n"); + long timeout = poweroff_timeout*60*HZ; + int audio_stat = audio_status(); + long tick = current_tick; + +/* + if (!shutdown_timeout && query_force_shutdown()) { + sys_poweroff(); + } +*/ + + 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(); + } + } + else if (sleeptimer_active) { + /* Handle sleeptimer */ + if (TIME_AFTER(tick, sleeptimer_endtick)) { + DEBUGF("Sleep timer timeout. Pause Playing...\n"); + audio_pause(); + sleeptimer_active = false; + //sys_poweroff(); + + } + } +} + + +static void power_thread(void) +{ + DEBUGF("power_thread() starting\n"); + long next_power_hist; + + next_power_hist = current_tick + HZ*60; + + while (1) + { + + //DEBUGF("power_thread() - while(1) - currenttick %ld - next_power_hist %ld\n",current_tick, next_power_hist); + + /* 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 */ + //memset(power_history, 0, sizeof(power_history)); + 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) { + DEBUGF("Setting sleep timer to %d seconds (%d minutes)\n", seconds, seconds/60); + sleeptimer_active = true; + sleeptimer_endtick = current_tick + seconds * HZ; + } else { + DEBUGF("Disabling sleep timer\n"); + sleeptimer_active = false; + sleeptimer_endtick = 0; + } +} + +int get_sleep_timer(void) +{ + if (sleeptimer_active) { + if (TIME_AFTER(sleeptimer_endtick, current_tick)) + return (sleeptimer_endtick - current_tick) / HZ; + DEBUGF("Sleep timer finished\n"); + set_sleep_timer(0); + } + return 0; +} + + + void reset_poweroff_timer(void) { + //DEBUGF("reset_poweroff_timer()\n"); + last_event_tick = current_tick; + } void shutdown_hw(void) { + DEBUGF("shutdown_hw()\n"); } void sys_poweroff(void) { + DEBUGF("sys_poweroff()\n"); + power_off(); } +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); +} + void cancel_shutdown(void) { + DEBUGF("cancel_shutdown()\n"); }