Index: apps/settings.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.c,v
retrieving revision 1.439
diff -u -r1.439 settings.c
--- apps/settings.c	6 Dec 2006 12:11:56 -0000	1.439
+++ apps/settings.c	18 Dec 2006 13:11:09 -0000
@@ -2120,6 +2120,167 @@
 #endif
 }
 
+/* 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.
Index: apps/settings.h
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.h,v
retrieving revision 1.255
diff -u -r1.255 settings.h
--- apps/settings.h	24 Nov 2006 19:49:02 -0000	1.255
+++ apps/settings.h	18 Dec 2006 13:11:10 -0000
@@ -184,7 +184,6 @@
                           13= 1GB, 14 = 1.5GB 15 = 1.75MB*/
     int rec_split_type; /* split/stop */
     int rec_split_method; /* time/filesize */
-
     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 */
@@ -543,6 +542,11 @@
     long voice_id;
 };
 
+struct opt_settings {
+    int* setting;
+    int setting_max;
+};
+
 /* prototypes */
 
 void settings_calc_config_sector(void);
@@ -564,6 +568,8 @@
 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, 
Index: apps/sound_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/sound_menu.c,v
retrieving revision 1.122
diff -u -r1.122 sound_menu.c
--- apps/sound_menu.c	24 Nov 2006 19:49:02 -0000	1.122
+++ apps/sound_menu.c	18 Dec 2006 13:11:12 -0000
@@ -41,6 +41,7 @@
 #include "sound.h"
 #ifdef HAVE_RECORDING
 #include "audio.h"
+#include "recording.h"
 #ifdef CONFIG_TUNER
 #include "radio.h"
 #endif
@@ -602,12 +603,81 @@
     return ret;
 }
 
-static bool filesplitoptionsmenu(void)
+/* Displays a menu for changing the countdown timer settings */
+static bool countdown_timer(void)
+{
+    bool retval;
+    struct timer* timer = get_timerstat();
+    unsigned int old_timer_day = timer->days;
+    unsigned int old_timer_hr = timer->hrs;
+    unsigned int old_timer_min = timer->mins;
+
+    /* pause timer while in timer settings */
+    timer->countdown = false;
+
+    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);
+
+    if ((old_timer_day != timer->days) ||
+            (old_timer_hr != timer->hrs) ||
+            (old_timer_min != timer->mins))
+    {
+        timer->secs = 0;
+        timer->timer_display = false;
+    }
+    else /* restart timer if no change */
+        timer->countdown = true;
+
+    return retval;
+}
+
+static bool countdown_timer_repeat(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);
+
+    /* 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 */
+    }
+
+    return retval;
+}
+
+static bool timermenu(void)
 {
     int m;
     bool result;
 
     static const struct menu_item items[] = {
+        { ID2P(LANG_TIMER_SET), countdown_timer },
+        { ID2P(LANG_TIMER_REPEAT), countdown_timer_repeat },
         { ID2P(LANG_SPLIT_MEASURE), splitmethod },
         { ID2P(LANG_SPLIT_TYPE),  splittype  },
         { ID2P(LANG_SPLIT_TIME),  rectimesplit  },
@@ -1255,7 +1325,7 @@
 #if CONFIG_CODEC == MAS3587F
         { ID2P(LANG_RECORDING_EDITABLE), receditable },
 #endif
-        { ID2P(LANG_RECORD_TIMESPLIT), filesplitoptionsmenu },
+        { ID2P(LANG_RECORD_TIMESPLIT), timermenu },
         { ID2P(LANG_RECORD_PRERECORD_TIME), recprerecord },
         { ID2P(LANG_RECORD_DIRECTORY), recdirectory },
         { ID2P(LANG_RECORD_STARTUP), reconstartup },
Index: apps/gui/statusbar.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/statusbar.c,v
retrieving revision 1.33
diff -u -r1.33 statusbar.c
--- apps/gui/statusbar.c	6 Nov 2006 18:07:26 -0000	1.33
+++ apps/gui/statusbar.c	18 Dec 2006 13:11:14 -0000
@@ -37,6 +37,7 @@
 #include "action.h" /* for keys_locked */
 #include "statusbar.h"
 #ifdef HAVE_RECORDING
+#include "recording.h"
 #include "audio.h"
 #endif
 
@@ -116,7 +117,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
@@ -124,6 +129,10 @@
 #endif
 #define STATUSBAR_TIME_X_END(statusbar_width)   statusbar_width - 1 - \
                                                 STATUSBAR_DISK_WIDTH
+#if defined(HAVE_RECORDING)
+#define TIMER_ICON_WIDTH 7
+#endif
+
 struct gui_syncstatusbar statusbars;
 
 void gui_statusbar_init(struct gui_statusbar * bar)
@@ -218,6 +227,20 @@
         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;
+#endif
 
     /* only redraw if forced to, or info has changed */
     if (force_redraw || bar->redraw_volume ||
@@ -295,8 +318,14 @@
         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);
+#endif
 #ifdef 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)
@@ -556,10 +585,11 @@
 /*
  * Print time to status bar
  */
-void gui_statusbar_time(struct screen * display, int hour, int minute)
+void gui_statusbar_time(struct screen * display, int hour, int minute,
+                           bool timer_display)
 {
     unsigned char buffer[6];
-    unsigned int width, height;
+    int width, height;
     if ( hour >= 0 &&
          hour <= 23 &&
          minute >= 0 &&
@@ -578,15 +608,70 @@
     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
+void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, int sc)
+{
+    unsigned char buffer[8];
+    int width, height, offset;
+
+#ifdef CONFIG_RTC
+    strncpy(buffer, " --:--", sizeof buffer);
+    display->getstringsize(buffer, &width, &height);
+    offset = width;
+#else
+    offset = 0;
+#endif
+
+    /* 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 + offset + 1))
+            display->putsxy(STATUSBAR_TIME_X_END(display->width) - width -
+                                offset, STATUSBAR_Y_POS, buffer);
+        /* display only an icon for small screens */
+        else if ((display->width) >= (STATUSBAR_LOCKR_X_POS +
+                                           STATUSBAR_LOCKR_WIDTH +
+                                           STATUSBAR_DISK_WIDTH +
+                                           TIMER_ICON_WIDTH + offset + 1))
+            display->mono_bitmap(bitmap_icons_7x7[Icon_Timer],
+                                       STATUSBAR_TIME_X_END(display->width) -
+                                       TIMER_ICON_WIDTH - offset,
+                                       STATUSBAR_Y_POS,
+                                       TIMER_ICON_WIDTH, STATUSBAR_HEIGHT);
+    }
+
+    display->setfont(FONT_UI);
+
+}
+
 #if CONFIG_CODEC == SWCODEC
 /**
  * Write a number to the display using bitmaps and return new position
Index: apps/gui/statusbar.h
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/statusbar.h,v
retrieving revision 1.17
diff -u -r1.17 statusbar.h
--- apps/gui/statusbar.h	2 Sep 2006 17:30:30 -0000	1.17
+++ apps/gui/statusbar.h	18 Dec 2006 13:11:14 -0000
@@ -39,6 +39,14 @@
     int hour;
     int minute;
 #endif
+#ifdef HAVE_RECORDING
+    int timer_day;
+    int timer_hour;
+    int timer_min;
+    int timer_sec;
+#endif
+    int timer_display;
+
 
 #ifdef CONFIG_CHARGING
     bool inserted;
@@ -106,11 +114,13 @@
 void gui_statusbar_icon_lock_remote(struct screen * display);
 void gui_statusbar_led(struct screen * display);
 #ifdef HAVE_RECORDING
+void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, int sc);
 void gui_statusbar_icon_recording_info(struct screen * display);
 #endif
 
 #ifdef CONFIG_RTC
-void gui_statusbar_time(struct screen * display, int hour, int minute);
+void gui_statusbar_time(struct screen * display, int hour, int minute,
+                            bool timer_display);
 #endif
 
 
Index: apps/keymaps/keymap-h1x0_h3x0.c
===================================================================
RCS file: /cvsroot/rockbox/apps/keymaps/keymap-h1x0_h3x0.c,v
retrieving revision 1.40
diff -u -r1.40 keymap-h1x0_h3x0.c
--- apps/keymaps/keymap-h1x0_h3x0.c	14 Dec 2006 08:16:20 -0000	1.40
+++ apps/keymaps/keymap-h1x0_h3x0.c	18 Dec 2006 13:11:17 -0000
@@ -441,6 +441,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 },
@@ -453,8 +457,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 */
Index: apps/keymaps/keymap-x5.c
===================================================================
RCS file: /cvsroot/rockbox/apps/keymaps/keymap-x5.c,v
retrieving revision 1.27
diff -u -r1.27 keymap-x5.c
--- apps/keymaps/keymap-x5.c	12 Dec 2006 07:55:17 -0000	1.27
+++ apps/keymaps/keymap-x5.c	18 Dec 2006 13:11:17 -0000
@@ -209,6 +209,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)
Index: apps/lang/english.lang
===================================================================
RCS file: /cvsroot/rockbox/apps/lang/english.lang,v
retrieving revision 1.304
diff -u -r1.304 english.lang
--- apps/lang/english.lang	10 Dec 2006 10:47:11 -0000	1.304
+++ apps/lang/english.lang	18 Dec 2006 13:11:24 -0000
@@ -2713,16 +2713,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>
@@ -10033,6 +10033,99 @@
   </voice>
 </phrase>
 <phrase>
+  id: LANG_TIMER_CONFIRM
+  desc: Confirm string for recording countdown timer settings
+  user:
+  <source>
+    *: "Press PLAY to confirm"
+  </source>
+  <dest>
+    *: "Press PLAY to confirm"
+    h100,h120,h300: "Press NAVI 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>
+    *: "Hrs"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_TIMER_MINS
+  desc: recording timer settings string
+  <source>
+    *: "Mins"
+  </source>
+  <dest>
+    *: "Mins"
+  </dest>
+  <voice>
+    *: "Mins"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_REC_TIMER
+  desc: recording screen timer string
+  <source>
+    *: "Timer"
+  </source>
+  <dest>
+    *: "Timer"
+  </dest>
+  <voice>
+    *: "Timer"
+  </voice>
+</phrase>
+<phrase>
   id: LANG_DITHERING
   desc: in the sound settings menu
   user:
Index: apps/recorder/icons.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/icons.c,v
retrieving revision 1.88
diff -u -r1.88 icons.c
--- apps/recorder/icons.c	24 Nov 2006 19:49:04 -0000	1.88
+++ apps/recorder/icons.c	18 Dec 2006 13:11:27 -0000
@@ -44,6 +44,11 @@
 #endif
 };
 
+const unsigned char bitmap_icons_7x7[][7] =
+{
+    [Icon_Timer]={0x1c, 0x22, 0x41, 0x4f, 0x49, 0x22, 0x1d},  /* Recording timer icon */
+};
+
 const unsigned char bitmap_icons_6x8[][6] =
 {
     { 0x60, 0x7f, 0x03, 0x33, 0x3f, 0x00 }, /* Musical note */
@@ -141,7 +146,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
 
 /*
Index: apps/recorder/icons.h
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/icons.h,v
retrieving revision 1.68
diff -u -r1.68 icons.h
--- apps/recorder/icons.h	24 Nov 2006 19:49:04 -0000	1.68
+++ apps/recorder/icons.h	18 Dec 2006 13:11:27 -0000
@@ -47,6 +47,11 @@
     Icon5x8Last
 };
 
+enum icons_7x7 {
+    Icon_Timer,
+    Icon7x7Last
+};
+
 enum icons_6x8 {
     Icon_Audio,
     Icon_Folder,
@@ -122,6 +127,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[];
Index: apps/recorder/recording.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/recording.c,v
retrieving revision 1.151
diff -u -r1.151 recording.c
--- apps/recorder/recording.c	10 Dec 2006 14:32:38 -0000	1.151
+++ apps/recorder/recording.c	18 Dec 2006 13:11:30 -0000
@@ -70,6 +70,8 @@
 #include "radio.h"
 #ifdef HAVE_RECORDING
 
+static struct timer timer;
+
 #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1)
 
 #if CONFIG_KEYPAD == RECORDER_PAD
@@ -736,6 +738,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_screen(bool no_source)
 {
     long button;
@@ -745,7 +778,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;
@@ -782,6 +815,8 @@
     int trig_xpos[NB_SCREENS];
     int trig_ypos[NB_SCREENS];
     int trig_width[NB_SCREENS];
+    int countdown_offset = 0;
+    bool repeat_timer_start = false;
 
     static const unsigned char *byte_units[] = {
         ID2P(LANG_BYTE),
@@ -793,6 +828,11 @@
     struct audio_recording_options rec_options;
 
     global_settings.recscreen_on = 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);
@@ -925,6 +965,15 @@
             last_audio_stat = audio_stat;
         }
 
+        /* 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;
+        }
+
         switch(button)
         {
             case ACTION_REC_LCD:
@@ -970,7 +1019,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))
@@ -978,6 +1047,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 */
@@ -1176,7 +1250,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);
@@ -1200,6 +1273,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 */
@@ -1298,6 +1375,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 */
@@ -1318,7 +1398,7 @@
         update_countdown--;
         if(update_countdown == 0 || seconds > last_seconds)
         {
-            unsigned int dseconds, dhours, dminutes;
+            unsigned int dseconds, dhours, dminutes, ddays;
             unsigned long num_recorded_bytes, dsize, dmb;
             int pos = 0;
 
@@ -1348,11 +1428,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;
@@ -1360,6 +1442,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); 
@@ -1383,7 +1470,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,
@@ -1395,6 +1483,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)
@@ -1428,11 +1526,39 @@
                     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 (dseconds < timer.mins_rpt * 60 + timer.hrs_rpt * 3600 +
+                             timer.days_rpt * 3600 * 24)
+                    {
+                        ddays = dseconds / (3600 * 24);
+                        dhours = (dseconds - (ddays * 3600 * 24)) / 3600;
+                        dminutes = (dseconds - (dhours * 3600)) / 60;
+
+                        timer.secs = prerec; /* add prerecorded time to timer */
+                        timer.mins = timer.mins_rpt - dminutes;
+                        timer.hrs = timer.hrs_rpt - dhours;
+                        timer.days = timer.days_rpt - ddays;
+
+                        /* 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;
             }
@@ -2014,6 +2140,12 @@
 }
 #endif /* CONFIG_KEYPAD == RECORDER_PAD */
 
+struct timer *get_timerstat(void)
+{
+    return &timer;
+}
+
+
 #if CONFIG_CODEC == SWCODEC
 void audio_beep(int duration)
 {
Index: apps/recorder/recording.h
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/recording.h,v
retrieving revision 1.7
diff -u -r1.7 recording.h
--- apps/recorder/recording.h	23 Nov 2006 19:21:12 -0000	1.7
+++ apps/recorder/recording.h	18 Dec 2006 13:11:30 -0000
@@ -23,11 +23,27 @@
 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;
+};
+
+struct timer *get_timerstat(void);
+
 #if CONFIG_CODEC == SWCODEC
 /* handles device powerup and sets audio source */
 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 */
