From 49952325c9d4a74225b3099eb61860bf4592022c Mon Sep 17 00:00:00 2001 From: Martin Scarratt Date: Sun, 15 Apr 2007 13:56:21 +0000 Subject: Recording countdown timer and repeat timer - see FS #6297 for more details git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13165 a1c6a512-1295-4272-9138-f99709370657 --- apps/gui/statusbar.c | 104 +++++++++++++++++++++- apps/gui/statusbar.h | 8 ++ apps/keymaps/keymap-h10.c | 7 +- apps/keymaps/keymap-h1x0_h3x0.c | 11 ++- apps/keymaps/keymap-x5.c | 3 + apps/lang/english.lang | 100 ++++++++++++++++++++- apps/menus/recording_menu.c | 73 +++++++++++++++- apps/recorder/icons.c | 10 ++- apps/recorder/icons.h | 7 ++ apps/recorder/recording.c | 152 ++++++++++++++++++++++++++++++-- apps/recorder/recording.h | 17 ++++ apps/settings.c | 188 ++++++++++++++++++++++++++++++++++++++++ apps/settings.h | 9 ++ 13 files changed, 670 insertions(+), 19 deletions(-) diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c index e082063a6f..157224f77d 100644 --- a/apps/gui/statusbar.c +++ b/apps/gui/statusbar.c @@ -33,6 +33,7 @@ #include "action.h" /* for keys_locked */ #include "statusbar.h" #ifdef HAVE_RECORDING +#include "recording.h" #include "audio.h" #include "recording.h" #endif @@ -113,7 +114,11 @@ #define STATUSBAR_LOCKR_WIDTH 5 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) +#ifdef HAVE_MMC #define STATUSBAR_DISK_WIDTH 12 +#else +#define STATUSBAR_DISK_WIDTH 7 +#endif #define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \ STATUSBAR_DISK_WIDTH #else @@ -121,6 +126,15 @@ #endif #define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ STATUSBAR_DISK_WIDTH +#ifdef HAVE_RECORDING +#define TIMER_ICON_WIDTH 7 +#if CONFIG_RTC +#define CLOCK_WIDTH 35 +#else +#define CLOCK_WIDTH 0 +#endif +#endif + struct gui_syncstatusbar statusbars; /* Prototypes */ @@ -140,9 +154,11 @@ static void gui_statusbar_led(struct screen * display); #endif #ifdef HAVE_RECORDING static void gui_statusbar_icon_recording_info(struct screen * display); +static void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, int sc, bool recscreen); +static void gui_statusbar_timer_rep(struct screen * display); #endif #if CONFIG_RTC -static void gui_statusbar_time(struct screen * display, int hour, int minute); +static void gui_statusbar_time(struct screen * display, int hour, int minute, bool timer_display); #endif #endif @@ -245,6 +261,21 @@ void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw) bar->info.minute = tm->tm_min; } #endif /* CONFIG_RTC */ +#ifdef HAVE_RECORDING + struct timer* timer = get_timerstat(); + bar->info.timer_day = timer->days; + bar->info.timer_hour = timer->hrs; + bar->info.timer_min = timer->mins; + /* avoid an update every second unless less than one + minute remains on the timer */ + if (!bar->info.timer_day && !bar->info.timer_hour && !bar->info.timer_min) + bar->info.timer_sec = timer->secs; + else + bar->info.timer_sec = 0; + + bar->info.timer_display = timer->timer_display; + bar->info.timer_repeat = timer->repeater; +#endif /* only redraw if forced to, or info has changed */ if (force_redraw || bar->redraw_volume || @@ -316,8 +347,16 @@ void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw) if (bar->info.keylockremote) gui_statusbar_icon_lock_remote(display); #endif +#ifdef HAVE_RECORDING + if (bar->info.timer_display) + gui_statusbar_timer(display, bar->info.timer_day, bar->info.timer_hour, + bar->info.timer_min, bar->info.timer_sec, recscreen_on); + else if ((bar->info.timer_repeat) && (recscreen_on)) + gui_statusbar_timer_rep(display); +#endif #if CONFIG_RTC - gui_statusbar_time(display, bar->info.hour, bar->info.minute); + gui_statusbar_time(display, bar->info.hour, bar->info.minute, + bar->info.timer_display); #endif /* CONFIG_RTC */ #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) if(!display->has_disk_led && bar->info.led) @@ -577,7 +616,8 @@ static void gui_statusbar_led(struct screen * display) /* * Print time to status bar */ -static void gui_statusbar_time(struct screen * display, int hour, int minute) +static void gui_statusbar_time(struct screen * display, int hour, int minute, + bool timer_display) { unsigned char buffer[6]; unsigned int width, height; @@ -599,15 +639,73 @@ static void gui_statusbar_time(struct screen * display, int hour, int minute) display->setfont(FONT_SYSFIXED); display->getstringsize(buffer, &width, &height); if (height <= STATUSBAR_HEIGHT) { +#ifdef HAVE_RECORDING + if (timer_display) + display->set_drawmode(DRMODE_INVERSEVID); +#else + (void)timer_display; +#endif display->putsxy(STATUSBAR_TIME_X_END(display->width) - width, STATUSBAR_Y_POS, buffer); } + display->set_drawmode(DRMODE_SOLID); display->setfont(FONT_UI); } #endif #ifdef HAVE_RECORDING +static void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, + int sc, bool recscreen) +{ + unsigned char buffer[8]; + int width, height; + + /* vary the display depending on the remaining time to save space */ + if (dy) + snprintf(buffer, sizeof(buffer), " %dd%02dh", hr > 58 ? dy + 1 : dy, + hr > 58 ? 0 : hr + 1); + else if (!hr && !mn) + snprintf(buffer, sizeof(buffer), "%02ds", sc); + else + snprintf(buffer, sizeof(buffer), "%02dh%02dm", mn > 58 ? hr + 1: hr, + mn > 58 ? 0 : mn + 1); + + display->setfont(FONT_SYSFIXED); + display->getstringsize(buffer, &width, &height); + + if (height <= STATUSBAR_HEIGHT) + { + if(((display->width) >= (STATUSBAR_LOCKR_X_POS + STATUSBAR_LOCKR_WIDTH + + STATUSBAR_DISK_WIDTH + width + CLOCK_WIDTH + 1)) + && !recscreen) + display->putsxy(STATUSBAR_TIME_X_END(display->width) - width - + CLOCK_WIDTH, STATUSBAR_Y_POS, buffer); + /* display only an icon for small screens or when in recording screen*/ + else if ((display->width) >= (STATUSBAR_LOCKR_X_POS + + STATUSBAR_LOCKR_WIDTH + + STATUSBAR_DISK_WIDTH + + TIMER_ICON_WIDTH + CLOCK_WIDTH + 1)) + display->mono_bitmap(bitmap_icons_7x7[Icon_Timer], + STATUSBAR_TIME_X_END(display->width) - + TIMER_ICON_WIDTH - CLOCK_WIDTH, + STATUSBAR_Y_POS, + TIMER_ICON_WIDTH, STATUSBAR_HEIGHT); + } + + display->setfont(FONT_UI); + +} + +static void gui_statusbar_timer_rep(struct screen * display) +{ + display->mono_bitmap(bitmap_icons_7x7[Icon_Timer_rep], + STATUSBAR_TIME_X_END(display->width) - + TIMER_ICON_WIDTH - CLOCK_WIDTH, + STATUSBAR_Y_POS, + TIMER_ICON_WIDTH, STATUSBAR_HEIGHT); +} + #if CONFIG_CODEC == SWCODEC /** * Write a number to the display using bitmaps and return new position diff --git a/apps/gui/statusbar.h b/apps/gui/statusbar.h index 21f98336d0..660c657f29 100644 --- a/apps/gui/statusbar.h +++ b/apps/gui/statusbar.h @@ -37,6 +37,14 @@ struct status_info { int hour; int minute; #endif +#ifdef HAVE_RECORDING + int timer_day; + int timer_hour; + int timer_min; + int timer_sec; + int timer_repeat; +#endif + int timer_display; #if CONFIG_CHARGING bool inserted; diff --git a/apps/keymaps/keymap-h10.c b/apps/keymaps/keymap-h10.c index 1a3c81b989..b3586413dd 100644 --- a/apps/keymaps/keymap-h10.c +++ b/apps/keymaps/keymap-h10.c @@ -121,7 +121,10 @@ static const struct button_mapping button_context_settings[] = { { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE }, { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE }, + { ACTION_SETTINGS_RESET, BUTTON_POWER, BUTTON_NONE }, + { ACTION_NONE, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT }, + { ACTION_NONE, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT }, + { ACTION_STD_OK, BUTTON_PLAY, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), }; /* button_context_settings */ @@ -303,6 +306,8 @@ static const struct button_mapping button_context_bmark[] = { const struct button_mapping button_context_recscreen[] = { { ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE }, + { ACTION_STD_CANCEL, BUTTON_REW, BUTTON_NONE }, + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) }; /* button_context_recscreen */ diff --git a/apps/keymaps/keymap-h1x0_h3x0.c b/apps/keymaps/keymap-h1x0_h3x0.c index bbec420846..d3d5f8d35f 100644 --- a/apps/keymaps/keymap-h1x0_h3x0.c +++ b/apps/keymaps/keymap-h1x0_h3x0.c @@ -439,6 +439,10 @@ static 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 }, @@ -451,8 +455,11 @@ static 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/keymaps/keymap-x5.c b/apps/keymaps/keymap-x5.c index b637e1ddd1..3dc69d767c 100644 --- a/apps/keymaps/keymap-x5.c +++ b/apps/keymaps/keymap-x5.c @@ -219,6 +219,9 @@ static const struct button_mapping button_context_settings[] = { { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE }, { ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_STD_CANCEL, BUTTON_REC, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 69900c5e6a..66b864e0cc 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -2720,16 +2720,16 @@ id: LANG_RECORD_TIMESPLIT - desc: Record split menu + desc: Record timer menu user: *: "File Split Options" - *: "File Split Options" + *: "Timer Options" - *: "File Split Options" + *: "Timer Options" @@ -10741,3 +10741,97 @@ *: "Context Menu" + + id: LANG_MULTIINT_CONFIRM + desc: Confirm string for multi_int settings + user: + + *: "Press PLAY to confirm" + + + *: "Press PLAY to confirm" + h100,h120,h300: "Press NAVI to confirm" + ipod*,x5,gigabeat: "Press SELECT to confirm" + + + *: "" + + + + id: LANG_TIMER_SET + desc: Recording timer menu + + *: "Set countdown timer" + + + *: "Set countdown timer" + + + *: "Set countdown timer" + + + + id: LANG_TIMER_REPEAT + desc: Recording timer menu + + *: "Record repeat timer" + + + *: "Record repeat timer" + + + *: "Record repeat timer" + + + + id: LANG_TIMER_DAYS + desc: recording timer settings string + + *: "Days" + + + *: "Days" + + + *: "Days" + + + + id: LANG_TIMER_HRS + desc: recording timer settings string + + *: "Hrs" + + + *: "Hrs" + + + *: "Hours" + + + + id: LANG_TIMER_MINS + desc: recording timer settings string + + *: "Mins" + + + *: "Mins" + + + *: "Minutes" + + + + id: LANG_REC_TIMER + desc: recording screen timer string + + *: "Timer" + + + *: "Timer" + + + *: "Timer" + + diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c index 1bc84e90d2..d37fe39bfe 100644 --- a/apps/menus/recording_menu.c +++ b/apps/menus/recording_menu.c @@ -42,6 +42,7 @@ #include "sound.h" #ifdef HAVE_RECORDING #include "audio.h" +#include "recording.h" #if CONFIG_TUNER #include "radio.h" #endif @@ -305,12 +306,78 @@ MENUITEM_SETTING(rec_quality, &global_settings.rec_quality, NULL); MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL); #endif +/* Displays a menu for changing the countdown timer settings */ +static int countdown_timer_func(void) +{ + bool retval; + bool changed = false; + struct timer* timer = get_timerstat(); + + static const struct opt_items names[] = { + { STR(LANG_TIMER_DAYS) }, + { STR(LANG_TIMER_HRS) }, + { STR(LANG_TIMER_MINS) } + }; + + struct opt_settings settings[] = { + { &timer->days, 6 }, + { &timer->hrs, 23 }, + { &timer->mins, 59 } + }; + + retval = set_multi_int(str(LANG_TIMER_SET), names, settings, 3, &changed); + + if (changed) + { + timer->countdown = false; + timer->secs = 0; + timer->timer_display = false; + } + + return retval; +} + +static int countdown_timer_repeat_func(void) +{ + struct timer* timer = get_timerstat(); + bool retval; + + static const struct opt_items names[] = { + { STR(LANG_TIMER_DAYS) }, + { STR(LANG_TIMER_HRS) }, + { STR(LANG_TIMER_MINS) } + }; + + struct opt_settings settings[] = { + { &timer->days_rpt, 6 }, + { &timer->hrs_rpt, 23 }, + { &timer->mins_rpt, 59 } + }; + retval = set_multi_int(str(LANG_TIMER_REPEAT), names, settings, 3, NULL); + + /* automatically select settings necessary for repeated recording */ + if (timer->days_rpt || timer->hrs_rpt || timer->mins_rpt) + { + global_settings.rec_split_type = 1; /* Stop */ + global_settings.rec_split_method = 0; /* Time */ + global_settings.rec_trigger_mode = 0; /* The repeat timer isn't + compatible with the trigger */ + } + + return retval; +} + +MENUITEM_FUNCTION(countdown_timer, 0, ID2P(LANG_TIMER_SET), + countdown_timer_func, NULL, NULL, Icon_Menu_setting); +MENUITEM_FUNCTION(countdown_timer_repeat, 0, ID2P(LANG_TIMER_REPEAT), + countdown_timer_repeat_func, NULL, NULL, Icon_Menu_setting); MENUITEM_SETTING(rec_split_type, &global_settings.rec_split_type, NULL); MENUITEM_SETTING(rec_split_method, &global_settings.rec_split_method, NULL); MENUITEM_SETTING(rec_timesplit, &global_settings.rec_timesplit, NULL); MENUITEM_SETTING(rec_sizesplit, &global_settings.rec_sizesplit, NULL); -MAKE_MENU(filesplitoptionsmenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON, - &rec_split_method, &rec_split_type, &rec_timesplit, &rec_sizesplit); +MAKE_MENU(timermenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON, + &countdown_timer, &countdown_timer_repeat, &rec_split_method, + &rec_split_type, &rec_timesplit, &rec_sizesplit); MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL); @@ -819,7 +886,7 @@ MAKE_MENU(recording_setting_menu, ID2P(LANG_RECORDING_SETTINGS), NULL, Icon_Reco #if CONFIG_CODEC == MAS3587F &rec_editable, #endif - &filesplitoptionsmenu, + &timermenu, &rec_prerecord_time, &recdirectory, #ifdef HAVE_BACKLIGHT diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c index ccb42d5919..bf6500fb1f 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c @@ -44,6 +44,14 @@ const unsigned char bitmap_icons_5x8[][5] = #endif }; +const unsigned char bitmap_icons_7x7[][7] = +{ + [Icon_Timer] = + {0x1c, 0x22, 0x41, 0x4f, 0x49, 0x22, 0x1d}, /* Recording timer icon */ + [Icon_Timer_rep]= + {0x17, 0x26, 0x45, 0x41, 0x51, 0x32, 0x74}, /* Recording repeat timer icon */ +}; + const unsigned char bitmap_icons_6x8[][6] = { { 0x60, 0x7f, 0x03, 0x33, 0x3f, 0x00 }, /* Musical note */ @@ -159,7 +167,7 @@ const unsigned char bitmap_icon_disk[12] = #ifdef HAVE_MMC {0x15,0x3f,0x7d,0x7B,0x77,0x67,0x79,0x7b,0x57,0x4f,0x47,0x7f}; #else - {0x00,0x00,0x00,0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00}; + {0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00,0x00,0x00,0x00}; #endif /* diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index 7682d44733..09aadf0888 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h @@ -49,6 +49,12 @@ enum icons_5x8 { Icon5x8Last }; +enum icons_7x7 { + Icon_Timer, + Icon_Timer_rep, + Icon7x7Last +}; + /* If any icons are added to this enum, they must be added to the unused_but_needed enum in ../player/icons.h */ enum icons_6x8 { @@ -144,6 +150,7 @@ extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18]; #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ 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]; extern const unsigned char bitmap_icon_disk[]; diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 025480cf91..7a332228e5 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -70,6 +70,8 @@ #include "radio.h" #ifdef HAVE_RECORDING +static struct timer timer; + static bool in_screen = false; bool in_recording_screen(void) @@ -745,6 +747,37 @@ static void trigger_listener(int trigger_status) } } +/* countdown timer tick task */ +void timer_tick_task(void) +{ + static int mini_tick = 0; + + mini_tick ++; + /* the countdown */ + if ((mini_tick >= HZ) && (timer.countdown)) + { + mini_tick = 0; + if (timer.secs) timer.secs -= 1; + else{ + timer.secs = 59; + if (timer.mins) timer.mins -= 1; + else{ + timer.mins = 59; + if (timer.hrs) timer.hrs -= 1; + else{ + timer.hrs = 23; + if (timer.days) timer.days -= 1; + else{ + timer.days = timer.hrs = timer.mins = timer.secs = 0; + /* switch timer display on/off when countdown finished */ + timer.timer_display = !timer.timer_display; + } + } + } + } + } +} + bool recording_start_automatic = false; bool recording_screen(bool no_source) @@ -756,7 +789,7 @@ bool recording_screen(bool no_source) int w, h; int update_countdown = 1; bool have_recorded = false; - unsigned int seconds; + unsigned int seconds, prerec = 0; int hours, minutes; char filename[13]; bool been_in_usb_mode = false; @@ -793,6 +826,9 @@ bool recording_screen(bool no_source) int trig_xpos[NB_SCREENS]; int trig_ypos[NB_SCREENS]; int trig_width[NB_SCREENS]; + int countdown_offset = 0; + bool repeat_timer_start = false; + unsigned int repeat_timer; static const unsigned char *byte_units[] = { ID2P(LANG_BYTE), @@ -804,6 +840,11 @@ bool recording_screen(bool no_source) struct audio_recording_options rec_options; in_screen = true; + + /* Stop countdown if countdown settings changed */ + if (!timer.countdown) + tick_remove_task(timer_tick_task); + cursor = 0; #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) ata_set_led_enabled(false); @@ -937,6 +978,25 @@ bool recording_screen(bool no_source) last_audio_stat = audio_stat; } + /* repeat_timer is the repeat time in seconds */ + repeat_timer = (timer.mins_rpt * 60 + timer.hrs_rpt * + 3600 + timer.days_rpt * 3600 * 24); + + /* decide on repeat timer status */ + if ((repeat_timer > rec_timesplit_seconds()) && + global_settings.rec_timesplit) + timer.repeater = true; + else + timer.repeater = false; + + /* When countdown timer reaches zero fake a new file button press */ + if (timer.countdown && !timer.days && !timer.hrs && !timer.mins && + !timer.secs) + { + tick_remove_task(timer_tick_task); + button = ACTION_REC_NEWFILE; + timer.countdown = false; + } if (recording_start_automatic) { @@ -991,7 +1051,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 (timer.days || timer.hrs || timer.mins || timer.secs) + { + if (button == ACTION_REC_PAUSE) + { + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + break; + } + else + { + /* if newfile button pressed and countdown timer is on, + start new file and reset timer */ + tick_remove_task(timer_tick_task); + timer.days = timer.hrs = timer.mins = timer.secs = 0; + timer.countdown = false; + } + } /* is this manual or triggered recording? */ if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) || (peak_meter_trigger_status() != TRIG_OFF)) @@ -999,6 +1079,11 @@ bool recording_screen(bool no_source) /* manual recording */ have_recorded = true; rec_record(); + repeat_timer_start = true; /* allow access to repeat timer + code */ + /* amount of file that has been prerecorded - needed for + syncing repeat timer */ + prerec = audio_recorded_time() / HZ; last_seconds = 0; if (talk_menu) { /* no voice possible here, but a beep */ @@ -1197,7 +1282,6 @@ bool recording_screen(bool no_source) #ifdef HAVE_FMRADIO_IN const int prev_rec_source = global_settings.rec_source; #endif - #if (CONFIG_LED == LED_REAL) /* led is restored at begin of loop / end of function */ led(false); @@ -1221,6 +1305,10 @@ 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 (!timer.countdown) + tick_remove_task(timer_tick_task); #if CONFIG_CODEC == SWCODEC /* reinit after submenu exit */ @@ -1319,6 +1407,9 @@ bool recording_screen(bool no_source) break; } /* end switch */ + /* display timer status in status bar if countdown enabled */ + timer.timer_display = timer.countdown; + #ifdef HAVE_AGC peak_read = !peak_read; if (peak_read) { /* every 2nd run of loop */ @@ -1369,11 +1460,13 @@ bool recording_screen(bool no_source) #endif /* CONFIG_CODEC == SWCODEC */ 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 (!timer.days && !timer.hrs && !timer.mins && !timer.secs) { hours = seconds / 3600; minutes = (seconds - (hours * 3600)) / 60; @@ -1381,6 +1474,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); @@ -1404,7 +1502,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 (!timer.days && !timer.hrs && !timer.mins && !timer.secs) { output_dyn_value(buf2, sizeof buf2, num_recorded_bytes, @@ -1416,6 +1515,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 (timer.days || timer.hrs || timer.mins || timer.secs) + { + snprintf(buf, 32, "%s %d:%02d:%02d:%02d", str(LANG_REC_TIMER), + timer.days, timer.hrs, timer.mins, timer.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) @@ -1449,11 +1558,36 @@ bool recording_screen(bool no_source) rec_new_file(); last_seconds = 0; } - else + else if (repeat_timer_start) { peak_meter_trigger(false); peak_meter_set_trigger_listener(NULL); audio_stop_recording(); + + /* stop any more attempts to access this code until a new + recording is started */ + repeat_timer_start = false; + + /* start repeat countdown if set and only if + stop time < repeat time */ + if (timer.repeater) + { + repeat_timer -= dseconds; + timer.days = repeat_timer / (3600 * 24); + timer.hrs = (repeat_timer - (timer.days * 3600 * 24)) / + 3600; + timer.mins = (repeat_timer - (timer.hrs * 3600)) / 60; + timer.secs = prerec; /* add prerecorded time to timer */ + + /* This is not really a toggle so much as a safety feature + so that it is impossible to start the timer more than + once */ + timer.countdown = !timer.countdown; + if (timer.countdown) + tick_add_task(timer_tick_task); + else + tick_remove_task(timer_tick_task); + } } update_countdown = 1; } @@ -2035,6 +2169,12 @@ static bool f3_rec_screen(void) } #endif /* CONFIG_KEYPAD == RECORDER_PAD */ +struct timer *get_timerstat(void) +{ + return &timer; +} + + #if CONFIG_CODEC == SWCODEC void audio_beep(int duration) { diff --git a/apps/recorder/recording.h b/apps/recorder/recording.h index 3ca1f35834..4fba37b68a 100644 --- a/apps/recorder/recording.h +++ b/apps/recorder/recording.h @@ -25,6 +25,22 @@ bool recording_screen(bool no_source); char *rec_create_filename(char *buf); int rec_create_directory(void); +struct timer +{ + bool countdown; + bool timer_display; + unsigned int days; + unsigned int hrs; + unsigned int mins; + unsigned int secs; + unsigned int days_rpt; + unsigned int hrs_rpt; + unsigned int mins_rpt; + bool repeater; +}; + +struct timer *get_timerstat(void); + /* If true, start recording automatically when recording_sreen() is entered */ extern bool recording_start_automatic; @@ -33,6 +49,7 @@ extern bool recording_start_automatic; void rec_set_source(int source, unsigned flags); #endif /* CONFIG_CODEC == SW_CODEC */ +struct audio_recording_options; /* Initializes a recording_options structure with global settings. pass returned data to audio_set_recording_options or rec_set_recording_options */ diff --git a/apps/settings.c b/apps/settings.c index 23b81173bd..e8963b05df 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -1245,6 +1245,194 @@ bool set_int(const unsigned char* string, return set_int_ex(string, unit, voice_unit, variable, function, step, min, max, formatter, NULL); } + +/* 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, + bool *changes_accepted) +{ + int i, j, w, h; + char buf[32]; + long button; + int cursor = 0; + bool done = false; + int value[varcount]; + int pos = 0; + + /* store current values in temp array */ + for(j = 0; j < varcount; j++) + value[j] = *(int*)variable[j].setting; + + /* initialize screen */ + FOR_NB_SCREENS(i) + { + screens[i].clear_display(); +#ifdef HAVE_LCD_BITMAP + screens[i].setmargins(0, 8); +#endif + } + + gui_syncstatusbar_draw(&statusbars, true); + + FOR_NB_SCREENS(i) + screens[i].getstringsize("3", &w, &h); + + /* print title */ + 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; + } + + /* print button instructions */ + snprintf(buf, sizeof(buf), "%s", str(LANG_MULTIINT_CONFIRM)); + FOR_NB_SCREENS(i) + screens[i].puts(0, 5, buf); + + 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", value[j]); + + FOR_NB_SCREENS(i) + screens[i].puts(pos, 3, buf); + + snprintf(buf, sizeof(buf), "%d", variable[j].setting_max); + +#ifdef HAVE_LCD_BITMAP + /* highlight currently selected integer */ + if (cursor == j) + { + FOR_NB_SCREENS(i) + { + screens[i].set_drawmode(DRMODE_COMPLEMENT); + screens[i].fillrect(pos * w - 1, 8 + 3 * h, + strlen(buf)*w + 1, h); + screens[i].set_drawmode(DRMODE_SOLID); + } + } +#endif + + pos += strlen(buf) + 3; + } + +#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: + /* cancel if pressing left when cursor + is already at the far left */ + if (cursor == 0) + { + *changes_accepted = false; + gui_syncsplash(HZ/2, 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: + value[cursor] += 1; + + if (value[cursor] > variable[cursor].setting_max) + value[cursor] = 0; + + if (global_settings.talk_menu) + talk_unit(INT, value[cursor], NULL); + break; + + case ACTION_SETTINGS_DEC: + case ACTION_SETTINGS_DECREPEAT: + value[cursor] -= 1; + + if (value[cursor] < 0) + value[cursor] = variable[cursor].setting_max; + + if (global_settings.talk_menu) + talk_unit(INT, value[cursor], NULL); + break; + + case ACTION_STD_OK: + *changes_accepted = true; + done = true; + break; + + case ACTION_STD_CANCEL: + *changes_accepted = false; + gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL)); + done = true; + + default: + if (default_event_handler(button) == SYS_USB_CONNECTED) + return true; + } + } + /* store values if accepted */ + if(*changes_accepted) + { + for(j = 0; j < varcount; j++) + *(int*)variable[j].setting = value[j]; + } + + action_signalscreenchange(); + + 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 33dfb8546a..9b1124dbae 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -247,6 +247,12 @@ struct opt_items { unsigned const char* string; long voice_id; }; + +struct opt_settings { + int* setting; + int setting_max; +}; + const struct settings_list* find_setting(void* variable, int *id); bool cfg_int_to_string(int setting_id, int val, char* buf, int buf_len); void talk_setting(void *global_settings_variable); @@ -264,6 +270,9 @@ bool set_int(const unsigned char* string, const char* unit, int voice_unit, int* variable, void (*function)(int), int step, int min, int max, void (*formatter)(char*, int, int, const char*) ); +bool set_multi_int(const char* string, const struct opt_items * names, + struct opt_settings * variable, int varcount, + bool * changes_accepted); /* use this one if you need to create a lang from the value (i.e with TALK_ID()) */ bool set_int_ex(const unsigned char* string, const char* unit, int voice_unit, int* variable, -- cgit v1.2.3