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
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index e082063..157224f 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 @@
#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 @@
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 @@
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 @@
/*
* 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 @@
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 21f9833..660c657 100644
--- a/apps/gui/statusbar.h
+++ b/apps/gui/statusbar.h
@@ -37,6 +37,14 @@
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 1a3c81b..b358641 100644
--- a/apps/keymaps/keymap-h10.c
+++ b/apps/keymaps/keymap-h10.c
@@ -121,7 +121,10 @@
{ 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 @@
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 bbec420..d3d5f8d 100644
--- a/apps/keymaps/keymap-h1x0_h3x0.c
+++ b/apps/keymaps/keymap-h1x0_h3x0.c
@@ -439,6 +439,10 @@
{ 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 @@
{ 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 b637e1d..3dc69d7 100644
--- a/apps/keymaps/keymap-x5.c
+++ b/apps/keymaps/keymap-x5.c
@@ -219,6 +219,9 @@
{ 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 69900c5..66b864e 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -2720,16 +2720,16 @@
</phrase>
<phrase>
id: LANG_RECORD_TIMESPLIT
- desc: Record split menu
+ desc: Record timer menu
user:
<source>
*: "File Split Options"
</source>
<dest>
- *: "File Split Options"
+ *: "Timer Options"
</dest>
<voice>
- *: "File Split Options"
+ *: "Timer Options"
</voice>
</phrase>
<phrase>
@@ -10741,3 +10741,97 @@
*: "Context Menu"
</voice>
</phrase>
+<phrase>
+ id: LANG_MULTIINT_CONFIRM
+ desc: Confirm string for multi_int settings
+ user:
+ <source>
+ *: "Press PLAY to confirm"
+ </source>
+ <dest>
+ *: "Press PLAY to confirm"
+ h100,h120,h300: "Press NAVI to confirm"
+ ipod*,x5,gigabeat: "Press SELECT to confirm"
+ </dest>
+ <voice>
+ *: ""
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_TIMER_SET
+ desc: Recording timer menu
+ <source>
+ *: "Set countdown timer"
+ </source>
+ <dest>
+ *: "Set countdown timer"
+ </dest>
+ <voice>
+ *: "Set countdown timer"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_TIMER_REPEAT
+ desc: Recording timer menu
+ <source>
+ *: "Record repeat timer"
+ </source>
+ <dest>
+ *: "Record repeat timer"
+ </dest>
+ <voice>
+ *: "Record repeat timer"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_TIMER_DAYS
+ desc: recording timer settings string
+ <source>
+ *: "Days"
+ </source>
+ <dest>
+ *: "Days"
+ </dest>
+ <voice>
+ *: "Days"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_TIMER_HRS
+ desc: recording timer settings string
+ <source>
+ *: "Hrs"
+ </source>
+ <dest>
+ *: "Hrs"
+ </dest>
+ <voice>
+ *: "Hours"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_TIMER_MINS
+ desc: recording timer settings string
+ <source>
+ *: "Mins"
+ </source>
+ <dest>
+ *: "Mins"
+ </dest>
+ <voice>
+ *: "Minutes"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_REC_TIMER
+ desc: recording screen timer string
+ <source>
+ *: "Timer"
+ </source>
+ <dest>
+ *: "Timer"
+ </dest>
+ <voice>
+ *: "Timer"
+ </voice>
+</phrase>
diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c
index 1bc84e9..d37fe39 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_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 @@
#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 ccb42d5..bf6500f 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -44,6 +44,14 @@
#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 @@
#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 7682d44..09aadf0 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -49,6 +49,12 @@
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 @@
#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 025480c..7a33222 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 @@
}
}
+/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
#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 @@
&& 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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
}
#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 3ca1f35..4fba37b 100644
--- a/apps/recorder/recording.h
+++ b/apps/recorder/recording.h
@@ -25,6 +25,22 @@
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 @@
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 23b8117..e8963b0 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -1245,6 +1245,194 @@
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 33dfb85..9b1124d 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -247,6 +247,12 @@
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 @@
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,