Index: apps/debug_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/debug_menu.c,v
retrieving revision 1.187
diff -u -r1.187 debug_menu.c
--- apps/debug_menu.c   25 May 2006 13:34:51 -0000  1.187
+++ apps/debug_menu.c   3 Jun 2006 13:39:30 -0000
@@ -53,6 +53,7 @@
 #include "tagcache.h"
 #include "lcd-remote.h"
 #include "crc32.h"
+#include "logf"

 #ifdef HAVE_LCD_BITMAP
 #include "widgets.h"
Index: apps/logfdisp.c
===================================================================
RCS file: /cvsroot/rockbox/apps/logfdisp.c,v
retrieving revision 1.9
diff -u -r1.9 logfdisp.c
--- apps/logfdisp.c 11 Apr 2006 22:19:47 -0000  1.9
+++ apps/logfdisp.c 3 Jun 2006 13:39:30 -0000
@@ -18,7 +18,6 @@
  ****************************************************************************/
 #include "config.h"

-#ifdef ROCKBOX_HAS_LOGF
 #include <file.h>
 #include <sprintf.h>
 #include <timefuncs.h>
@@ -29,6 +28,7 @@
 #include <lcd.h>
 #include "menu.h"
 #include "logf.h"
+#include "settings.h"

 #if CONFIG_KEYPAD == IPOD_4G_PAD
 #define LOGF_BUTTON_QUIT BUTTON_MENU
@@ -38,10 +38,12 @@
 #define LOGF_BUTTON_QUIT BUTTON_OFF
 #endif

+
 #ifdef HAVE_LCD_BITMAP
 bool logfdisplay(void)

 {
+#if 0
     int w, h;
     int lines;
     int columns;
@@ -95,7 +97,7 @@
         lcd_update();
         button = button_get_w_tmo(HZ/2);
     } while(button != LOGF_BUTTON_QUIT);
-
+#endif
     return false;
 }
 #else /* HAVE_LCD_BITMAP */
@@ -107,40 +109,3 @@
 }
 #endif /* HAVE_LCD_BITMAP */

-/* Store the logf log to logf.txt in the .rockbox directory. The order of the
- * entries will be "reversed" so that the most recently logged entry is on the
- * top of the file */
-bool logfdump(void)
-{
-    int fd;
-
-    if(!logfindex && !logfwrap)
-        /* nothing is logged just yet */
-        return false;
-
-    fd = open("/.rockbox/logf.txt", O_CREAT|O_WRONLY|O_TRUNC);
-    if(-1 != fd) {
-        unsigned char buffer[MAX_LOGF_ENTRY +1];
-        int index = logfindex-1;
-        int stop = logfindex;
-
-
-        while(index != stop) {
-            if(index < 0) {
-                if(logfwrap)
-                    index = MAX_LOGF_LINES-1;
-                else
-                    break; /* done */
-            }
-
-            memcpy(buffer, logfbuffer[index], MAX_LOGF_ENTRY);
-            buffer[MAX_LOGF_ENTRY]=0;
-            fdprintf(fd, "%s\n", buffer);
-            index--;
-        }
-        close(fd);
-    }
-    return false;
-}
-
-#endif /* ROCKBOX_HAS_LOGF */
Index: apps/logfdisp.h
===================================================================
RCS file: /cvsroot/rockbox/apps/logfdisp.h,v
retrieving revision 1.3
diff -u -r1.3 logfdisp.h
--- apps/logfdisp.h 1 Jun 2005 13:07:37 -0000   1.3
+++ apps/logfdisp.h 3 Jun 2006 13:39:30 -0000
@@ -18,8 +18,8 @@
  ****************************************************************************/
 #ifndef LOGFDISP_H
 #define LOGFDISP_H
+#include "logf.h"
 bool logfdisplay(void);
-bool logfdump(void);

 #endif /* LOGFDISP_H */

Index: apps/settings.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.c,v
retrieving revision 1.388
diff -u -r1.388 settings.c
--- apps/settings.c 30 May 2006 11:26:40 -0000  1.388
+++ apps/settings.c 3 Jun 2006 13:39:34 -0000
@@ -80,6 +80,7 @@
 #ifdef CONFIG_TUNER
 #include "radio.h"
 #endif
+#include "logf.h"

 #if CONFIG_CODEC == MAS3507D
 void dac_line_in(bool enable);
@@ -565,7 +566,7 @@

     /* If values are just added to the end, no need to bump the version. */
     /* new stuff to be added at the end */
-
+    {16, S_O(log_level), 0, "log_level", NULL },
     /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
 };

@@ -1169,6 +1170,7 @@
     set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress);
 #endif
 #endif
+    set_log_level(global_settings.log_level);
 }


Index: apps/settings.h
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.h,v
retrieving revision 1.219
diff -u -r1.219 settings.h
--- apps/settings.h 25 May 2006 13:34:51 -0000  1.219
+++ apps/settings.h 3 Jun 2006 13:39:35 -0000
@@ -495,6 +495,7 @@
 #ifdef HAVE_LCD_BITMAP
     unsigned char kbd_file[MAX_FILENAME+1]; /* last keyboard */
 #endif
+    short int log_level;
 };

 enum optiontype { INT, BOOL };
Index: apps/settings_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings_menu.c,v
retrieving revision 1.256
diff -u -r1.256 settings_menu.c
--- apps/settings_menu.c    29 May 2006 05:19:18 -0000  1.256
+++ apps/settings_menu.c    3 Jun 2006 13:39:36 -0000
@@ -55,6 +55,9 @@
 #include "yesno.h"
 #include "list.h"
 #include "color_picker.h"
+#include "logf.h"
+#include "logfdisp.h"
+#include "gui/splash.h"

 #ifdef HAVE_LCD_BITMAP
 #include "peakmeter.h"
@@ -1952,7 +1955,132 @@
     return result;
 }

+void set_loglvl_format(char* buffer, int buffer_size, int value,
+                       const char* unit)
+{
+    switch (value)
+    {
+        case SYSLOG_LVL_INFO:
+            snprintf(buffer,buffer_size,"Information or worse");
+            break;
+        case SYSLOG_LVL_ATTENTION:
+            snprintf(buffer,buffer_size,"Attention or worse");
+            break;
+        case SYSLOG_LVL_NOTICE:
+            snprintf(buffer,buffer_size,"Notice or worse");
+            break;
+        case SYSLOG_LVL_WARNING:
+            snprintf(buffer,buffer_size,"Warning or worse");
+            break;
+        case SYSLOG_LVL_ERROR:
+            snprintf(buffer,buffer_size,"Error or worse");
+            break;
+        case SYSLOG_LVL_URGENT:
+            snprintf(buffer,buffer_size,"Urgent Or Critial");
+            break;
+        case SYSLOG_LVL_CRITICAL:
+            snprintf(buffer,buffer_size,"Everything");
+            break;
+        case SYSLOG_LVL_NONE:
+            snprintf(buffer,buffer_size,"OFF");
+            break;
+    }
+}
+bool set_loglvl(void)
+{
+    int level = global_settings.log_level&(~SYSLOG_SUBSYSTEM_MASK);
+    bool result = set_int("Log Level", "",
+                          0, &level, NULL, 1, 0, 7,
+                          set_loglvl_format);
+
+    global_settings.log_level = (global_settings.log_level&(SYSLOG_SUBSYSTEM_MASK))
+            &level;
+    return result;
+
+}
+bool set_logsystems(void)
+{
+    int m, systems = global_settings.log_level&(SYSLOG_SUBSYSTEM_MASK);
+    bool result;
+    int r;
+    static const struct menu_item items[] = {
+        { "All On", NULL },
+        { "All Off", NULL },
+        { "Main Thread", NULL },
+        { "Playback", NULL },
+        { "LCD", NULL },
+        { "Plugin", NULL },
+        { "Codec", NULL },
+        { "Power", NULL },
+        { "Others", NULL }
+    };
+    m=menu_init( items, sizeof items / sizeof(struct menu_item), NULL,
+                 NULL, NULL, NULL);
+    r = menu_show(m);
+    switch (r)
+    {
+        case 0:
+            systems = SYSLOG_SUBSYSTEM_MASK;
+            gui_syncsplash(HZ/2,true,"All On");
+            break;
+        case 1:
+            systems = 0;
+            gui_syncsplash(HZ/2,true,"All Off");
+            break;
+        case 2:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_MAIN_THREAD?"Not Monitoring":"Monitoring");
+            systems |= SYSLOG_SYS_MAIN_THREAD;
+            break;
+        case 3:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_PLAYBACK?"Not Monitoring":"Monitoring");
+            systems |= SYSLOG_SYS_PLAYBACK;
+            break;
+        case 4:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_LCD?"Not Monitoring":"Monitoring");
+            systems |= SYSLOG_SYS_LCD;
+            break;
+        case 5:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_PLUGIN?"Not Monitoring":"Monitoring");
+            systems |= SYSLOG_SYS_PLUGIN;
+            break;
+        case 6:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_CODEC?"Not Monitoring":"Monitoring");;
+            systems |= SYSLOG_SYS_CODEC;
+            break;
+        case 7:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_POWER?"Not Monitoring":"Monitoring");
+            systems |= SYSLOG_SYS_POWER;
+            break;
+        case 8:
+            gui_syncsplash(HZ/2,true,systems&SYSLOG_SYS_OTHER?"Not Monitoring":"Monitoring");
+            systems |= SYSLOG_SYS_OTHER;
+            break;
+    }
+    global_settings.log_level = (global_settings.log_level&(~SYSLOG_SUBSYSTEM_MASK))
+            &systems;
+    set_log_level(global_settings.log_level);
+    menu_exit(m);
+
+    return false;
+}
+
+bool dbg_log(void)
+{
+    int m;
+    bool result;
+    static const struct menu_item items[] = {
+        { "View System Log", logfdisplay },
+        { "Dump System Log To Disk", logfdump },
+        { "Change Log Level", set_loglvl },
+        { "Change Monitored Systems", set_logsystems }
+    };
+    m=menu_init( items, sizeof items / sizeof(struct menu_item), NULL,
+                 NULL, NULL, NULL);
+    result = menu_run(m);
+    menu_exit(m);

+    return result;
+}
 static bool system_settings_menu(void)
 {
     int m;
@@ -1978,6 +2106,7 @@
 #ifdef HAVE_CHARGING
         { ID2P(LANG_CAR_ADAPTER_MODE), car_adapter_mode       },
 #endif
+{ "System Log",          dbg_log                },
     };

     m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
Index: firmware/logf.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/logf.c,v
retrieving revision 1.8
diff -u -r1.8 logf.c
--- firmware/logf.c 30 Jun 2005 15:14:33 -0000  1.8
+++ firmware/logf.c 3 Jun 2006 13:39:38 -0000
@@ -18,7 +18,7 @@
  ****************************************************************************/

 /*
- * logf() logs MAX_LOGF_ENTRY (21) bytes per entry in a circular buffer. Each
+ * logf() logs MAX_LOGF_ENTRY bytes per entry in a circular buffer. Each
  * logged string is space- padded for easier and faster output on screen. Just
  * output MAX_LOGF_ENTRY characters on each line. MAX_LOGF_ENTRY bytes fit
  * nicely on the iRiver remote LCD (128 pixels with an 8x6 pixels font).
@@ -31,18 +31,18 @@
 #include "config.h"
 #include "lcd-remote.h"
 #include "logf.h"
+#include "file.h"

-/* Only provide all this if asked to */
-#ifdef ROCKBOX_HAS_LOGF

-unsigned char logfbuffer[MAX_LOGF_LINES][MAX_LOGF_ENTRY];
-int logfindex;
-bool logfwrap;
+char logfbuffer[MAX_LOGF_CHARS];
+int log_start = 0;
+short int log_level = SYSLOG_EVERYTHING;
+

 #ifdef HAVE_REMOTE_LCD
 static void displayremote(void)
 {
-    /* TODO: we should have a debug option that enables/disables this! */
+#if 0
     int w, h;
     int lines;
     int columns;
@@ -65,39 +65,85 @@
             else
                 break; /* done */
         }
-
+
         memcpy(buffer, logfbuffer[index], columns);
         buffer[columns]=0;
         lcd_remote_puts(0, i, buffer);
     }
-    lcd_remote_update();
+    lcd_remote_update();
+#endif
 }
 #else
 #define displayremote()
 #endif
-
-void logf(const char *format, ...)
+void syslogf(const short int level, const char *format, ...)
 {
-    int len;
-    unsigned char *ptr;
     va_list ap;
-    va_start(ap, format);
+    int chars;
+    int lvl_code, sys_code;
+
+    lvl_code = level&(~SYSLOG_SUBSYSTEM_MASK);
+    sys_code = level&SYSLOG_SUBSYSTEM_MASK;

-    if(logfindex >= MAX_LOGF_LINES) {
-        /* wrap */
-        logfwrap = true;
-        logfindex = 0;
+    if (get_loglevel() < lvl_code)
+        return; /* too low, ignore it */
+    else if (!(get_logsystems()&sys_code))
+        return; /* not watching this sub-system */
+
+    if (MAX_LOGF_CHARS-log_start < 32)
+        logfdump();
+    snprintf(&logfbuffer[log_start],6,"[%c%c] ",lvl_codes[lvl_code],lvl_codes[lvl_code]);
+    log_start+=5;
+    va_start(ap, format);
+    chars = vsnprintf(&logfbuffer[log_start], MAX_LOGF_CHARS-log_start, format, ap);
+    if (chars == (MAX_LOGF_CHARS-log_start)) /*likely it didnt get the whole error msg, so do it again */
+    {
+        logfbuffer[log_start-5] = '\0';
+        logfdump();
+        snprintf(&logfbuffer[log_start],6,"[%c%c] ",lvl_codes[lvl_code],lvl_codes[lvl_code]);
+        log_start+=5;
+        chars = vsnprintf(&logfbuffer[log_start], MAX_LOGF_CHARS-log_start, format, ap);
     }
-    ptr = logfbuffer[logfindex];
-    len = vsnprintf(ptr, MAX_LOGF_ENTRY, format, ap);
     va_end(ap);
-    if(len < MAX_LOGF_ENTRY)
-        /* pad with spaces up to the MAX_LOGF_ENTRY byte border */
-        memset(ptr+len, ' ', MAX_LOGF_ENTRY-len);
-
-    logfindex++; /* leave it where we write the next time */
+    logfbuffer[log_start] = '\n';
+    logfbuffer[log_start+1] = '\0';
+    log_start += chars+1;
+}

-    displayremote();
+void logf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    syslogf(SYSLOG_EVERYTHING , format, ap);
+    va_end(ap);
 }

-#endif
+bool logfdump(void)
+{
+    int fd = open(SYSLOG_FILE, O_CREAT|O_APPEND );
+    if (fd < 0)
+        return false; /* no point doing any error messages here.. */
+
+    fdprintf(fd,"%s",logfbuffer);
+    log_start = 0;
+    close(fd);
+    return true;
+}
+char* get_next_log_msg(char* last_msg, char* buffer, int buf_size)
+{
+    char *s, *e;
+    if (last_msg == NULL)
+        s = logfbuffer;
+    else s = last_msg;
+
+    if (s >= &logfbuffer[log_start])
+        return NULL;
+
+    e = strchr(s,'\n');
+    if (e)
+    {
+        strncpy(buffer,s,(buf_size>(e-s))?e-s:buf_size);
+        return e + 1;
+    }
+    return NULL;
+}
Index: firmware/export/logf.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/logf.h,v
retrieving revision 1.7
diff -u -r1.7 logf.h
--- firmware/export/logf.h  30 Jun 2005 15:33:43 -0000  1.7
+++ firmware/export/logf.h  3 Jun 2006 13:39:38 -0000
@@ -21,20 +21,46 @@
 #include <config.h>
 #include <stdbool.h>

-#ifdef ROCKBOX_HAS_LOGF
-
-#define MAX_LOGF_LINES 1000
-#define MAX_LOGF_ENTRY 30
-#define MAX_LOGF_DATASIZE (MAX_LOGF_ENTRY*MAX_LOGF_LINES)
-
-extern unsigned char logfbuffer[MAX_LOGF_LINES][MAX_LOGF_ENTRY];
-extern int logfindex;
-extern bool logfwrap;

+#define MAX_LOGF_CHARS 0x4000 /* 16k */
+#define SYSLOG_FILE  "/.rockbox/syslog.log"
+void init_logf(void);
+void syslogf(const short int level, const char *format, ...);
 void logf(const char *format, ...);
-#else
-/* built without logf() support enabled */
-#define logf(...)
-#endif
+bool logfdump(void);
+char* get_next_log_msg(char* last_msg, char* buffer, int buf_size);
+extern short int log_level;
+
+#define set_log_level(a) log_level = a
+#define get_log_level() log_level
+#define get_loglevel() (log_level&(~SYSLOG_SUBSYSTEM_MASK))
+#define get_logsystems() (log_level&(SYSLOG_SUBSYSTEM_MASK))
+
+/* syslog warning/error levels */
+/* level for syslog is a ( SYSLOG_LVL_* | SYSLOG_SYS_* ) or SYSLOG_EVERYTHING */
+/* BITS: ...  UUUU USSS SSSS SLLL <- U: unused, S: sub-system L: level */
+/* If you add to these you need to change debug_menu.c also (down the very bottom */
+#define SYSLOG_LVL_INFO 0x0000
+#define SYSLOG_LVL_ATTENTION 0x0001
+#define SYSLOG_LVL_NOTICE 0x0002
+#define SYSLOG_LVL_WARNING 0x0003
+#define SYSLOG_LVL_ERROR 0x0004
+#define SYSLOG_LVL_URGENT 0x0005
+#define SYSLOG_LVL_CRITICAL 0x0006
+#define SYSLOG_LVL_NONE 0x0007
+static const char lvl_codes[8] = "IANIEUC";
+
+#define SYSLOG_SYS_MAIN_THREAD 0x0008
+#define SYSLOG_SYS_PLAYBACK 0x0010
+#define SYSLOG_SYS_LCD 0x0020
+#define SYSLOG_SYS_PLUGIN 0x0040
+#define SYSLOG_SYS_CODEC 0x0080
+#define SYSLOG_SYS_POWER 0x0100
+#define SYSLOG_SYS_OTHER 0x0200
+
+#define SYSLOG_EVERYTHING 0xFFFE /* every system, level CRITICAL */
+#define SYSLOG_SUBSYSTEM_MASK 0xFFF8
+
+

 #endif /* LOGF_H */
