diff --git a/apps/keymaps/keymap-h1x0_h3x0.c b/apps/keymaps/keymap-h1x0_h3x0.c index 0c0b61d201..4ac671ff3c 100644 --- a/apps/keymaps/keymap-h1x0_h3x0.c +++ b/apps/keymaps/keymap-h1x0_h3x0.c @@ -415,6 +415,10 @@ const struct button_mapping button_context_settings_h100remote[] = { { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_SETTINGS_DEC, BUTTON_RC_FF, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_RC_SOURCE, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_RC_SOURCE|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RC_BITRATE, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RC_BITRATE|BUTTON_REPEAT, BUTTON_NONE }, /* { ACTION_NONE, BUTTON_RC_ON, BUTTON_NONE }, { ACTION_NONE, BUTTON_RC_STOP, BUTTON_NONE }, { ACTION_NONE, BUTTON_RC_MENU|BUTTON_REL, BUTTON_NONE }, @@ -427,8 +431,11 @@ const struct button_mapping button_context_settings_h300lcdremote[] = { { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_SETTINGS_DEC, BUTTON_RC_VOL_DOWN, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_NONE, BUTTON_RC_REW, BUTTON_NONE }, - { ACTION_NONE, BUTTON_RC_FF, BUTTON_NONE }, + { ACTION_STD_PREV, BUTTON_RC_REW, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RC_FF, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_RESET, BUTTON_RC_ON, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_settings */ diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 320d4d0f2b..8dee255c8a 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -9806,3 +9806,83 @@ *: "" + + id: LANG_TIMER_CONFIRM + desc: Confirm string for recording countdown timer settings + user: + + *: "Press PLAY to confirm" + + + *: "Press PLAY to confirm" + h100,h120,h300: "Press NAVI to confirm" + + + *: "" + + + + id: LANG_TIMER_SET + desc: Recording timer menu + + *: "Set countdown timer" + + + *: "Set countdown timer" + + + *: "Set countdown timer" + + + + id: LANG_TIMER_DAYS + desc: recording timer settings string + + *: "Days" + + + *: "Days" + + + *: "Days" + + + + id: LANG_TIMER_HRS + desc: recording timer settings string + + *: "Hrs" + + + *: "Hrs" + + + *: "Hrs" + + + + id: LANG_TIMER_MINS + desc: recording timer settings string + + *: "Mins" + + + *: "Mins" + + + *: "Mins" + + + + id: LANG_REC_TIMER + desc: recording screen timer string + + *: "Timer" + + + *: "Timer" + + + *: "Timer" + + diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c index 711df633f4..20a681fc81 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c @@ -36,6 +36,12 @@ const unsigned char bitmap_icons_5x8[][5] = [Icon_Mono]={0x00, 0x1c, 0x22, 0x1c, 0x00} /* Mono recording */ }; +const unsigned char bitmap_icons_7x7[][7] = +{ + [Icon_Timer]={0x1c, 0x22, 0x41, 0x4f, 0x49, 0x22, 0x1d}, /* Recording timer icon */ + [Icon_Blank]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* Blank for flashing */ +}; + const unsigned char bitmap_icons_6x8[][6] = { { 0x60, 0x7f, 0x03, 0x33, 0x3f, 0x00 }, /* Musical note */ diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index b4310aa90a..c68b281852 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h @@ -44,6 +44,12 @@ enum icons_5x8 { Icon5x8Last }; +enum icons_7x7 { + Icon_Timer, + Icon_Blank, + Icon7x7Last +}; + enum icons_6x8 { Icon_Audio, Icon_Folder, @@ -117,6 +123,7 @@ enum icons_18x8 { #endif extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; +extern const unsigned char bitmap_icons_7x7[Icon7x7Last][7]; extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6]; extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; #if CONFIG_CODEC == SWCODEC diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 6ee71d2eee..4d0e226254 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -69,8 +69,18 @@ #include "screen_access.h" #include "action.h" #include "radio.h" +#include "timer.h" #ifdef HAVE_RECORDING +#ifdef SIMULATOR +bool timer_register(int reg_prio, void (*unregister_callback)(void), + long cycles, int int_prio, void (*timer_callback)(void)); +void timer_unregister(void); +#define TIMER_FREQ 0 +#endif +#define TIMER_ICON_WIDTH 7 +#define TIMER_ICON_HEIGHT 7 + #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1) bool f2_rec_screen(void); @@ -78,6 +88,9 @@ bool f3_rec_screen(void); #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ +int days, hrs, mins, secs; +bool timer_icon; /* timer icon displayed? */ + int screen_update = NB_SCREENS; bool remote_display_on = true; const char* const freq_str[6] = @@ -779,6 +792,52 @@ static void trigger_listener(int trigger_status) } } +/* countdown timer callback function */ +void timer_callback(void) +{ + static int mini_tick = 0; + /* print icon at bottom right of main screen */ + if (timer_icon) + screens[0].mono_bitmap(bitmap_icons_7x7[Icon_Timer], + screens[0].width - TIMER_ICON_WIDTH, + screens[0].height - TIMER_ICON_HEIGHT, + TIMER_ICON_WIDTH, TIMER_ICON_HEIGHT); + else + screens[0].mono_bitmap(bitmap_icons_7x7[Icon_Blank], + screens[0].width - TIMER_ICON_WIDTH, + screens[0].height - TIMER_ICON_HEIGHT, + TIMER_ICON_WIDTH, TIMER_ICON_HEIGHT); + + screens[0].update_rect(screens[0].width - TIMER_ICON_WIDTH, + screens[0].height - TIMER_ICON_HEIGHT, + TIMER_ICON_WIDTH, TIMER_ICON_HEIGHT); + + mini_tick ++; + /* the countdown */ + if (mini_tick > 10) + { + secs -= 1; + if (secs < 0){ + mins -= 1; + secs = 59; + if (mins < 0){ + hrs -= 1; + mins = 59; + if (hrs < 0){ + days -= 1; + hrs = 23; + if (days < 0) + { + days = hrs = mins = secs = 0; + timer_icon = !timer_icon; /* flash icon when */ + } /* countdown finished */ + } + } + } + mini_tick = 0; + } +} + bool recording_screen(bool no_source) { long button; @@ -818,6 +877,8 @@ bool recording_screen(bool no_source) int i; int filename_offset[NB_SCREENS]; int pm_y[NB_SCREENS]; + static bool countdown; /* countdown in progress indicator */ + int countdown_offset = 0; static const unsigned char *byte_units[] = { ID2P(LANG_BYTE), @@ -827,6 +888,20 @@ bool recording_screen(bool no_source) }; global_settings.recscreen_on = true; + + /* Stop countdown if countdown settings changed */ + if ((mins != global_settings.ctdn_mins)|| + (hrs != global_settings.ctdn_hrs) || + (days != global_settings.ctdn_days)) + { + mins = global_settings.ctdn_mins; + hrs = global_settings.ctdn_hrs; + days = global_settings.ctdn_days; + secs = global_settings.ctdn_secs; + countdown = false; + timer_unregister(); + } + cursor = 0; #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) ata_set_led_enabled(false); @@ -969,6 +1044,17 @@ bool recording_screen(bool no_source) last_audio_stat = audio_stat; } + /* When countdown timer reaches zero fake a new file button press */ + if (countdown && !days && !hrs && !mins && !secs) + { + timer_unregister(); + button = ACTION_REC_NEWFILE; + countdown = false; + global_settings.ctdn_days = days; + global_settings.ctdn_hrs = hrs; + global_settings.ctdn_mins = mins; + } + switch(button) { case ACTION_REC_LCD: @@ -1004,7 +1090,12 @@ bool recording_screen(bool no_source) #if CONFIG_CODEC != SWCODEC peak_meter_playback(true); peak_meter_enabled = false; -#endif +#endif + /* keeps settings the same as the countdown values */ + global_settings.ctdn_days = days; + global_settings.ctdn_hrs = hrs; + global_settings.ctdn_mins = mins; + global_settings.ctdn_secs = secs; done = true; } update_countdown = 1; /* Update immediately */ @@ -1014,7 +1105,27 @@ bool recording_screen(bool no_source) case ACTION_REC_NEWFILE: /* Only act if the mpeg is stopped */ if(!(audio_stat & AUDIO_STATUS_RECORD)) - { + { /* if countdown timer is set, start countdown */ + if (days || hrs || mins || secs) + { + if (button == ACTION_REC_PAUSE) + { + countdown = !countdown; + if (countdown) + timer_register(1, NULL, TIMER_FREQ/10, 1, timer_callback); + else + timer_unregister(); + break; + } + else + { + /* if newfile button pressed and countdown timer is on, + start new file and reset timer */ + timer_unregister(); + days = hrs = mins = secs = 0; + countdown = false; + } + } /* is this manual or triggered recording? */ if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) || (peak_meter_trigger_status() != TRIG_OFF)) @@ -1221,7 +1332,11 @@ bool recording_screen(bool no_source) #ifdef HAVE_FMRADIO_IN const int prev_rec_source = global_settings.rec_source; #endif - + /* maintain countdown values when entering menu */ + global_settings.ctdn_days = days; + global_settings.ctdn_hrs = hrs; + global_settings.ctdn_mins = mins; + global_settings.ctdn_secs = secs; #if CONFIG_LED == LED_REAL /* led is restored at begin of loop / end of function */ led(false); @@ -1245,6 +1360,19 @@ bool recording_screen(bool no_source) && prev_rec_source == AUDIO_SRC_FMRADIO) radio_status = FMRADIO_OFF; #endif + /* if countdown timer settings changed in menu, + stop counting and reset */ + if ((hrs != global_settings.ctdn_hrs) || + (mins != global_settings.ctdn_mins) || + (days != global_settings.ctdn_days)) + { + days = global_settings.ctdn_days; + hrs = global_settings.ctdn_hrs; + mins = global_settings.ctdn_mins; + secs = global_settings.ctdn_secs; + countdown = false; + timer_unregister(); + } #if CONFIG_CODEC == SWCODEC /* reinit after submenu exit */ @@ -1347,6 +1475,8 @@ bool recording_screen(bool no_source) break; } + timer_icon = countdown; /* display timer icon if countdown enabled */ + #ifdef HAVE_AGC peak_read = !peak_read; if (peak_read) { /* every 2nd run of loop */ @@ -1383,11 +1513,13 @@ bool recording_screen(bool no_source) if ((global_settings.rec_sizesplit) && (global_settings.rec_split_method)) { + countdown_offset = 1; dmb = dsize/1024/1024; snprintf(buf, sizeof(buf), "%s %dMB", str(LANG_SYSFONT_SPLIT_SIZE), dmb); } - else + /* only display recording time if countdown timer is off */ + else if (!days && !hrs && !mins && !secs) { hours = seconds / 3600; minutes = (seconds - (hours * 3600)) / 60; @@ -1395,6 +1527,11 @@ bool recording_screen(bool no_source) str(LANG_SYSFONT_RECORDING_TIME), hours, minutes, seconds%60); } + else + { + countdown_offset = 0; + snprintf(buf, 32, ""); + } for(i = 0; i < screen_update; i++) screens[i].puts(0, 0, buf); @@ -1418,7 +1555,8 @@ bool recording_screen(bool no_source) str(LANG_SYSFONT_RECORD_TIMESPLIT_REC), dhours, dminutes); } - else + /* only display recording size if countdown timer is off */ + else if (!days && !hrs && !mins && !secs) { output_dyn_value(buf2, sizeof buf2, num_recorded_bytes, @@ -1430,6 +1568,16 @@ bool recording_screen(bool no_source) for(i = 0; i < screen_update; i++) screens[i].puts(0, 1, buf); + /* display countdown timer if set */ + if (days || hrs || mins || secs) + { + snprintf(buf, 32, "%s %d:%02d:%02d:%02d", str(LANG_REC_TIMER), + days, hrs, mins, secs); + + for(i = 0; i < screen_update; i++) + screens[i].puts(0, countdown_offset, buf); + } + for(i = 0; i < screen_update; i++) { if (filename_offset[i] > 0) @@ -2123,6 +2271,21 @@ unsigned long pcm_rec_status(void) #endif /* #ifdef SIMULATOR */ #endif /* #ifdef CONFIG_CODEC == SWCODEC */ +#ifdef SIMULATOR +bool timer_register(int reg_prio, void (*unregister_callback)(void), + long cycles, int int_prio, void (*timer_callback)(void)) +{ + reg_prio = reg_prio; + unregister_callback = unregister_callback; + cycles = cycles; + int_prio = int_prio; + timer_callback = timer_callback; + return false; +} +void timer_unregister(void) +{ +} +#endif #endif /* HAVE_RECORDING */ diff --git a/apps/settings.c b/apps/settings.c index 3dc4ee1530..b2f7888a22 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -96,7 +96,7 @@ const char rec_base_directory[] = REC_BASE_DIR; #include "eq_menu.h" #endif -#define CONFIG_BLOCK_VERSION 52 +#define CONFIG_BLOCK_VERSION 53 #define CONFIG_BLOCK_SIZE 512 #define RTC_BLOCK_SIZE 44 @@ -477,6 +477,11 @@ static const struct bit_entry hd_bits[] = {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" }, {1, S_O(rec_split_type), 0, "rec split type", "Split, Stop" }, {1, S_O(rec_split_method), 0, "rec split method", "Time,Filesize" }, + {6, S_O(ctdn_mins), 0, "countdown timer minutes", NULL }, /* 0 - 59 */ + {5, S_O(ctdn_hrs), 0, "countdown timer hours", NULL }, /* 0 - 23 */ + {6, S_O(ctdn_secs), 0, "countdown timer seconds", NULL }, /* 0 - 59 */ + {3, S_O(ctdn_days), 0, "countdown timer days", NULL }, /* 0 - 6 */ + { #if defined(HAVE_SPDIF_IN) || defined(HAVE_FMRADIO_IN) @@ -2032,6 +2037,167 @@ bool set_int(const unsigned char* string, (max-*variable)/step, &data,function); } +/* Useful for time and other multi integer settings */ +bool set_multi_int(const char* string, const struct opt_items * names, + struct opt_settings * variable, int varcount) +{ + int i, j; + char buf[32]; + long button; + int cursor = 0; + bool done = false; + int oldvalue[varcount]; + int pos = 0; + + for(j = 0; j < varcount; j++) + oldvalue[j] = *(int*)variable[j].setting; + + FOR_NB_SCREENS(i) + { + screens[i].clear_display(); +#ifdef HAVE_LCD_BITMAP + screens[i].setmargins(0, 8); +#endif + } + + snprintf(buf, sizeof(buf), "%s", string); + FOR_NB_SCREENS(i) + screens[i].puts(0, 0, buf); + + /* print variable names */ + for(j = 0; j < varcount ; j++) + { + if (j > 0) + { + snprintf(buf, sizeof(buf), ":"); + FOR_NB_SCREENS(i) + screens[i].puts(pos - 2, 1, buf); + } + + snprintf(buf, sizeof(buf), "%s", P2STR(names[j].string)); + FOR_NB_SCREENS(i) + screens[i].puts(pos, 1, buf); + + pos += strlen(buf) + 3; + } + + snprintf(buf, sizeof(buf), "%s", str(LANG_TIMER_CONFIRM)); + FOR_NB_SCREENS(i) + screens[i].puts(0, 5, buf); + + gui_syncstatusbar_draw(&statusbars, true); + + while(!done) + { + pos = 0; + + /* print variables */ + for(j = 0; j < varcount; j++) + { + if (j > 0) + { + snprintf(buf, sizeof(buf), " :"); + FOR_NB_SCREENS(i) + screens[i].puts(pos - 3, 3, buf); + } + + snprintf(buf, sizeof(buf), "%d", *(int*)variable[j].setting); + +#ifdef HAVE_LCD_BITMAP + if (cursor == j) + { + FOR_NB_SCREENS(i) + screens[i].puts_style_offset(pos, 3, buf, STYLE_INVERT, 0); + } + else +#endif + { + FOR_NB_SCREENS(i) + screens[i].puts(pos, 3, buf); + } + + snprintf(buf, sizeof(buf), "%d", variable[j].setting_max); + pos += strlen(buf) + 3; + } + + /* print empty char to terminate invert style */ + snprintf(buf, sizeof(buf), " "); + FOR_NB_SCREENS(i) + screens[i].puts(pos - 3, 3, buf); + +#ifdef HAVE_LCD_BITMAP + FOR_NB_SCREENS(i) + screens[i].update(); +#endif + + button = get_action(CONTEXT_SETTINGS, TIMEOUT_BLOCK); + + switch (button) + { + case ACTION_STD_NEXT: + cursor ++; + if (cursor >= varcount) + cursor = varcount - 1; + if (global_settings.talk_menu) + talk_id(names[cursor].voice_id, false); + break; + + case ACTION_STD_PREV: + if (cursor == 0) + { + /* cancel if pressing left when cursor + is already at the far left */ + for(j = 0; j < varcount; j++) + *(int*)variable[j].setting = oldvalue[j]; + gui_syncsplash(HZ/2, true, str(LANG_MENU_SETTING_CANCEL)); + done = true; + } + else + cursor --; + if (cursor < 0) + cursor = 0; + if (global_settings.talk_menu) + talk_id(names[cursor].voice_id, false); + break; + + case ACTION_SETTINGS_INC: + case ACTION_SETTINGS_INCREPEAT: + *(int*)variable[cursor].setting += 1; + if (*(int*)variable[cursor].setting > + variable[cursor].setting_max) + *(int*)variable[cursor].setting = 0; + if (global_settings.talk_menu) + talk_unit(INT, *(int*)variable[cursor].setting); + break; + + case ACTION_SETTINGS_DEC: + case ACTION_SETTINGS_DECREPEAT: + *(int*)variable[cursor].setting -= 1; + if (*(int*)variable[cursor].setting < 0) + *(int*)variable[cursor].setting = + variable[cursor].setting_max; + if (global_settings.talk_menu) + talk_unit(INT, *(int*)variable[cursor].setting); + break; + + case ACTION_STD_OK: + done = true; + break; + + case ACTION_STD_CANCEL: + for(j = 0; j < varcount; j++) + *(int*)variable[j].setting = oldvalue[j]; + gui_syncsplash(HZ/2, true, str(LANG_MENU_SETTING_CANCEL)); + return false; + + default: + if (default_event_handler(button) == SYS_USB_CONNECTED) + return true; + } + } + return false; +} + /* NOTE: the 'type' parameter specifies the actual type of the variable that 'variable' points to. not the value within. Only variables with type 'bool' should use parameter BOOL. diff --git a/apps/settings.h b/apps/settings.h index 561dc59375..fe00dce023 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -167,7 +167,10 @@ struct user_settings 13= 1GB, 14 = 1.5GB 15 = 1.75MB*/ int rec_split_type; /* split/stop */ int rec_split_method; /* time/filesize */ - + int ctdn_mins; /* 0 - 59 */ + int ctdn_hrs; /* 0 - 23 */ + int ctdn_secs; /* 0 - 59 */ + int ctdn_days; /* 0 - 6 */ int rec_prerecord_time; /* In seconds, 0-30, 0 means OFF */ int rec_directory; /* 0=base dir, 1=current dir */ bool rec_startup; /* true means start Rockbox in recording screen */ @@ -495,6 +498,11 @@ struct opt_items { long voice_id; }; +struct opt_settings { + int* setting; + int setting_max; +}; + /* prototypes */ void settings_calc_config_sector(void); @@ -516,6 +524,8 @@ bool set_bool_options(const char* string, bool* variable, bool set_bool(const char* string, bool* variable ); bool set_option(const char* string, void* variable, enum optiontype type, const struct opt_items* options, int numoptions, void (*function)(int)); +bool set_multi_int(const char* string, const struct opt_items * names, + struct opt_settings * variable, int varcount); bool set_int(const unsigned char* string, const char* unit, int voice_unit, int* variable, void (*function)(int), int step, int min, int max, diff --git a/apps/sound_menu.c b/apps/sound_menu.c index f220d26f8f..6537b5b171 100644 --- a/apps/sound_menu.c +++ b/apps/sound_menu.c @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2002 Björn Stenberg + * Copyright (C) 2002 Bj�n Stenberg * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. @@ -591,6 +591,25 @@ static bool agc_cliptime(void) INT, names, 5, NULL ); } #endif /* HAVE_AGC */ + +/* Displays a menu for changing the countdown timer settings */ +static bool countdown_timer(void) +{ + static const struct opt_items names[] = { + { STR(LANG_TIMER_DAYS) }, + { STR(LANG_TIMER_HRS) }, + { STR(LANG_TIMER_MINS) } + }; + + struct opt_settings settings[] = { + { &global_settings.ctdn_days, 6 }, + { &global_settings.ctdn_hrs, 23 }, + { &global_settings.ctdn_mins, 59 } + }; + + return set_multi_int(str(LANG_TIMER_SET), names, settings, 3); +} + #endif /* HAVE_RECORDING */ static bool chanconf(void) @@ -1089,6 +1108,8 @@ bool recording_menu(bool no_source) items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME); items[i++].function = agc_cliptime; #endif + items[i].desc = ID2P(LANG_TIMER_SET); + items[i++].function = countdown_timer; m=menu_init( items, i, NULL, NULL, NULL, NULL); result = menu_run(m);