1
0
Fork 0
forked from len0rd/rockbox

A new implementation of logf, logfdisplay and logfdump.

Flyspray: FS#10528
Author: Amaury Pouly


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22462 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Maurus Cuelenaere 2009-08-21 22:54:23 +00:00
parent 249392c2d3
commit 20b0dd2788
5 changed files with 321 additions and 206 deletions

View file

@ -29,6 +29,7 @@
#include <action.h> #include <action.h>
#include <lcd.h> #include <lcd.h>
#include <font.h>
#include "menu.h" #include "menu.h"
#include "logf.h" #include "logf.h"
#include "settings.h" #include "settings.h"
@ -36,90 +37,174 @@
#include "action.h" #include "action.h"
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
int compute_nb_lines(int w, struct font* font)
{
int i, nb_lines;
int cur_x, delta_x;
if(logfindex == 0 && !logfwrap)
return 0;
if(logfwrap)
i = logfindex;
else
i = 0;
cur_x = 0;
nb_lines = 0;
do {
if(logfbuffer[i] == '\0')
{
cur_x = 0;
nb_lines++;
}
else
{
/* does character fit on this line ? */
delta_x = font_get_width(font, logfbuffer[i]);
if(cur_x + delta_x > w)
{
cur_x = 0;
nb_lines++;
}
/* update pointer */
cur_x += delta_x;
}
i++;
if(i >= MAX_LOGF_SIZE)
i = 0;
} while(i != logfindex);
return nb_lines;
}
bool logfdisplay(void) bool logfdisplay(void)
{ {
int w, h;
int lines;
int columns;
int i;
int action; int action;
int w, h, i, index;
bool lcd = false; /* fixed atm */ int fontnr;
int index, user_index=0; int cur_x, cur_y, delta_y, delta_x;
struct font* font;
lcd_getstringsize("A", &w, &h); int user_index;/* user_index will be number of the first line to display (warning: line!=logf entry) */
lines = (lcd? char buf[2];
#ifdef HAVE_REMOTE_LCD
LCD_REMOTE_HEIGHT fontnr = lcd_getfont();
#else font = font_get(fontnr);
0
#endif /* get the horizontal size of each line */
:LCD_HEIGHT)/h; font_getstringsize("A", NULL, &delta_y, fontnr);
columns = (lcd?
#ifdef HAVE_REMOTE_LCD buf[1] = '\0';
LCD_REMOTE_WIDTH w = LCD_WIDTH;
#else h = LCD_HEIGHT;
0 /* start at the end of the log */
#endif user_index = compute_nb_lines(w, font) - h/delta_y -1; /* if negative, will be set 0 to zero later */
:LCD_WIDTH)/w;
if (columns > MAX_LOGF_ENTRY+1)
columns = MAX_LOGF_ENTRY+1;
if(!lines)
return false;
do { do {
lcd_clear_display(); lcd_clear_display();
index = logfindex + user_index; if(user_index < 0)
for(i = lines-1; i>=0; i--) { user_index = 0;
unsigned char buffer[columns + 1];
if(logfwrap)
if(--index < 0) { i = logfindex;
if(logfwrap) else
index = MAX_LOGF_LINES-1; i = 0;
else
break; /* done */ index = 0;
cur_x = 0;
cur_y = 0;
/* nothing to print ? */
if(logfindex == 0 && !logfwrap)
goto end_print;
do {
if(logfbuffer[i] == '\0')
{
/* should be display a newline ? */
if(index >= user_index)
cur_y += delta_y;
cur_x = 0;
index++;
} }
else
{
/* does character fit on this line ? */
delta_x = font_get_width(font, logfbuffer[i]);
if(cur_x + delta_x > w)
{
/* should be display a newline ? */
if(index >= user_index)
cur_y += delta_y;
cur_x = 0;
index++;
}
/* should we print character ? */
if(index >= user_index)
{
buf[0] = logfbuffer[i];
lcd_putsxy(cur_x, cur_y, buf);
}
/* update pointer */
cur_x += delta_x;
}
/* did we fill the screen ? */
if(cur_y > h)
break;
i++;
if(i >= MAX_LOGF_SIZE)
i = 0;
} while(i != logfindex);
memcpy(buffer, logfbuffer[index], columns); end_print:
if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_CONTINUE_LINE)
buffer[columns-1] = '>';
else if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_MULTI_LINE)
buffer[columns-1] = '\0';
buffer[columns] = '\0';
lcd_puts(0, i, buffer);
}
lcd_update(); lcd_update();
action = get_action(CONTEXT_STD, HZ); action = get_action(CONTEXT_STD, HZ);
if(action == ACTION_STD_NEXT) switch( action )
user_index++;
else if(action == ACTION_STD_PREV)
user_index--;
else if(action == ACTION_STD_OK)
user_index = 0;
#ifdef HAVE_TOUCHSCREEN
else if(action == ACTION_TOUCHSCREEN)
{ {
short x, y; case ACTION_STD_NEXT:
static int prev_y; case ACTION_STD_NEXTREPEAT:
user_index++;
action = action_get_touchscreen_press(&x, &y); break;
case ACTION_STD_PREV:
if(action & BUTTON_REL) case ACTION_STD_PREVREPEAT:
prev_y = 0; user_index--;
else break;
case ACTION_STD_OK:
user_index = 0;
break;
#ifdef HAVE_TOUCHSCREEN
case ACTION_TOUCHSCREEN:
{ {
if(prev_y != 0) short x, y;
user_index += (prev_y - y) / h; static int prev_y;
prev_y = y; action = action_get_touchscreen_press(&x, &y);
if(action & BUTTON_REL)
prev_y = 0;
else
{
if(prev_y != 0)
user_index += (prev_y - y) / delta_y;
prev_y = y;
}
} }
}
#endif #endif
default:
break;
}
} while(action != ACTION_STD_CANCEL); } while(action != ACTION_STD_CANCEL);
return false; return false;
@ -140,67 +225,31 @@ bool logfdump(void)
{ {
int fd; int fd;
if(!logfindex && !logfwrap) /* nothing to print ? */
if(logfindex == 0 && !logfwrap)
/* nothing is logged just yet */ /* nothing is logged just yet */
return false; return false;
fd = open(ROCKBOX_DIR "/logf.txt", O_CREAT|O_WRONLY|O_TRUNC); fd = open(ROCKBOX_DIR "/logf.txt", O_CREAT|O_WRONLY|O_TRUNC);
if(-1 != fd) { if(-1 != fd) {
unsigned char buffer[MAX_LOGF_ONE_LINE_SIZE +1]; int i;
unsigned char *ptr;
int index = logfindex-1; if(logfwrap)
int stop = logfindex; i = logfindex;
int tindex; else
bool dumpwrap = false; i = 0;
bool multiline;
do {
while(!dumpwrap || (index >= stop)) { if(logfbuffer[i]=='\0')
if(index < 0) { fdprintf(fd, "\n");
if(logfwrap) else
{ fdprintf(fd, "%c", logfbuffer[i]);
index = MAX_LOGF_LINES-1;
dumpwrap = true; i++;
} if(i >= MAX_LOGF_SIZE)
else i = 0;
break; /* done */ } while(i != logfindex);
}
multiline = false;
if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_MULTI_LINE)
{
multiline = true;
do {
index--;
if(index < 0) {
if(logfwrap)
{
index = MAX_LOGF_LINES-1;
dumpwrap = true;
}
else
goto end_loop;
}
} while(logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_CONTINUE_LINE);
index++;
if (index >= MAX_LOGF_LINES)
index = 0;
}
tindex = index-1;
ptr = buffer;
do {
tindex++;
memcpy(ptr, logfbuffer[tindex], MAX_LOGF_ENTRY);
ptr += MAX_LOGF_ENTRY;
if (tindex >= MAX_LOGF_LINES)
tindex = 0;
} while(logfbuffer[tindex][MAX_LOGF_ENTRY] == LOGF_TERMINATE_CONTINUE_LINE);
*ptr = '\0';
fdprintf(fd, "%s\n", buffer);
index--;
}
end_loop:
close(fd); close(fd);
} }
return false; return false;

View file

@ -292,3 +292,8 @@ int fdprintf(int fd, const char *fmt, ...)
return fpr.bytes; /* return 0 on error */ return fpr.bytes; /* return 0 on error */
} }
int vfnprintf(int (*push)(void *userp, unsigned char data), void *userp, const char *fmt, va_list ap)
{
return format(push, userp, fmt, ap);
}

View file

@ -28,15 +28,10 @@
#ifdef ROCKBOX_HAS_LOGF #ifdef ROCKBOX_HAS_LOGF
#ifndef __PCTOOL__ #ifndef __PCTOOL__
#define MAX_LOGF_LINES 1000
#define MAX_LOGF_ENTRY 29
#define MAX_LOGF_ONE_LINE_SIZE 200
#define LOGF_TERMINATE_ONE_LINE 0x00 #define MAX_LOGF_SIZE 16384
#define LOGF_TERMINATE_CONTINUE_LINE 0x01
#define LOGF_TERMINATE_MULTI_LINE 0x02
extern unsigned char logfbuffer[MAX_LOGF_LINES][MAX_LOGF_ENTRY+1]; extern unsigned char logfbuffer[MAX_LOGF_SIZE];
extern int logfindex; extern int logfindex;
extern bool logfwrap; extern bool logfwrap;
#endif /* __PCTOOL__ */ #endif /* __PCTOOL__ */

View file

@ -32,4 +32,6 @@ int snprintf (char *buf, size_t size, const char *fmt, ...)
int vsnprintf (char *buf, int size, const char *fmt, va_list ap); int vsnprintf (char *buf, int size, const char *fmt, va_list ap);
int fdprintf (int fd, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); int fdprintf (int fd, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
int vfnprintf(int (*push)(void *userp, unsigned char data), void *userp, const char *fmt, va_list ap);
#endif /* __SPRINTF_H__ */ #endif /* __SPRINTF_H__ */

View file

@ -20,28 +20,18 @@
****************************************************************************/ ****************************************************************************/
/* /*
* logf() logs MAX_LOGF_ENTRY (29) bytes per entry in a circular buffer. Each * logf() logs entries in a circular buffer. Each logged string is null-terminated.
* 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).
* *
* When the length of log exceeds MAX_LOGF_ENTRY bytes, dividing into the * When the length of log exceeds MAX_LOGF_SIZE bytes, the buffer wraps.
* string of length is MAX_LOGF_ENTRY-1 bytes.
* *
* logfbuffer[*]:
*
* |<- MAX_LOGF_ENTRY bytes ->|1|
* | log data area |T|
*
* T : log terminate flag
* == LOGF_TERMINATE_ONE_LINE(0x00) : log data end (one line)
* == LOGF_TERMINATE_CONTINUE_LINE(0x01) : log data continues
* == LOGF_TERMINATE_MULTI_LINE(0x02) : log data end (multi line)
*/ */
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <sprintf.h>
#include <system.h>
#include <font.h>
#include "config.h" #include "config.h"
#include "lcd-remote.h" #include "lcd-remote.h"
#include "logf.h" #include "logf.h"
@ -56,7 +46,7 @@
#ifdef ROCKBOX_HAS_LOGF #ifdef ROCKBOX_HAS_LOGF
#ifndef __PCTOOL__ #ifndef __PCTOOL__
unsigned char logfbuffer[MAX_LOGF_LINES][MAX_LOGF_ENTRY+1]; unsigned char logfbuffer[MAX_LOGF_SIZE];
int logfindex; int logfindex;
bool logfwrap; bool logfwrap;
#endif #endif
@ -65,32 +55,103 @@ bool logfwrap;
static void displayremote(void) static void displayremote(void)
{ {
/* TODO: we should have a debug option that enables/disables this! */ /* TODO: we should have a debug option that enables/disables this! */
int w, h; int w, h, i;
int lines; int fontnr;
int columns; int cur_x, cur_y, delta_y, delta_x;
int i; struct font* font;
int index; int nb_lines;
char buf[2];
lcd_remote_getstringsize("A", &w, &h); /* Memorize the pointer to the beginning of the last ... lines
lines = LCD_REMOTE_HEIGHT/h; I assume delta_y >= 6 to avoid wasting memory and allocating memory dynamically
columns = LCD_REMOTE_WIDTH/w; I hope there is no font with height < 6 ! */
const int NB_ENTRIES=LCD_REMOTE_HEIGHT / 6;
int line_start_ptr[NB_ENTRIES];
fontnr = lcd_getfont();
font = font_get(fontnr);
/* get the horizontal size of each line */
font_getstringsize("A", NULL, &delta_y, fontnr);
/* font too small ? */
if(delta_y < 6)
return;
/* nothing to print ? */
if(logfindex == 0 && !logfwrap)
return;
w = LCD_REMOTE_WIDTH;
h = LCD_REMOTE_HEIGHT;
nb_lines = 0;
if(logfwrap)
i = logfindex;
else
i = 0;
cur_x = 0;
line_start_ptr[0] = i;
do
{
if(logfbuffer[i] == '\0')
{
line_start_ptr[++nb_lines % NB_ENTRIES] = i+1;
cur_x = 0;
}
else
{
/* does character fit on this line ? */
delta_x = font_get_width(font, logfbuffer[i]);
if(cur_x + delta_x > w)
{
cur_x = 0;
line_start_ptr[++nb_lines % NB_ENTRIES] = i;
}
/* update pointer */
cur_x += delta_x;
}
i++;
if(i >= MAX_LOGF_SIZE)
i = 0;
} while(i != logfindex);
lcd_remote_clear_display(); lcd_remote_clear_display();
index = logfindex; i = line_start_ptr[ MAX(nb_lines - h / delta_y, 0) % NB_ENTRIES];
for(i = lines-1; i>=0; i--) { cur_x = 0;
unsigned char buffer[columns+1]; cur_y = 0;
buf[1] = '\0';
if(--index < 0) {
if(logfwrap) do {
index = MAX_LOGF_LINES-1; if(logfbuffer[i] == '\0')
else {
break; /* done */ cur_y += delta_y;
cur_x = 0;
}
else
{
/* does character fit on this line ? */
delta_x = font_get_width(font, logfbuffer[i]);
if(cur_x + delta_x > w)
{
cur_y += delta_y;
cur_x = 0;
}
buf[0] = logfbuffer[i];
lcd_remote_putsxy(cur_x, cur_y, buf);
cur_x += delta_x;
} }
memcpy(buffer, logfbuffer[index], columns); i++;
buffer[columns]=0; if(i >= MAX_LOGF_SIZE)
lcd_remote_puts(0, i, buffer); i = 0;
} } while(i != logfindex);
lcd_remote_update(); lcd_remote_update();
} }
#else #else
@ -110,59 +171,62 @@ void _logf(const char *format, ...)
#else #else
static void check_logfindex(void) static void check_logfindex(void)
{ {
if(logfindex >= MAX_LOGF_LINES) { if(logfindex >= MAX_LOGF_SIZE)
{
/* wrap */ /* wrap */
logfwrap = true; logfwrap = true;
logfindex = 0; logfindex = 0;
} }
} }
void _logf(const char *format, ...) static int logf_push(void *userp, unsigned char c)
{ {
int len; (void)userp;
int tlen;
unsigned char buf[MAX_LOGF_ONE_LINE_SIZE]; logfbuffer[logfindex++] = c;
unsigned char *ptr; check_logfindex();
va_list ap;
bool multiline = false; #if defined(HAVE_SERIAL) && !defined(SIMULATOR)
if(c != '\0')
va_start(ap, format); {
vsnprintf(buf, MAX_LOGF_ONE_LINE_SIZE, format, ap); char buf[2];
va_end(ap); buf[0] = c;
buf[1] = '\0';
len = strlen(buf); serial_tx(buf);
}
#endif
return true;
}
void _logf(const char *fmt, ...)
{
#ifdef USB_ENABLE_SERIAL
int old_logfindex = logfindex;
#endif
va_list ap;
va_start(ap, fmt);
vfnprintf(logf_push, NULL, fmt, ap);
va_end(ap);
/* add trailing zero */
logf_push(NULL, '\0');
#if defined(HAVE_SERIAL) && !defined(SIMULATOR) #if defined(HAVE_SERIAL) && !defined(SIMULATOR)
serial_tx(buf);
serial_tx("\r\n"); serial_tx("\r\n");
#endif #endif
#ifdef USB_ENABLE_SERIAL #ifdef USB_ENABLE_SERIAL
usb_serial_send(buf, len);
usb_serial_send("\r\n", 2);
#endif
tlen = 0; if(logfindex < old_logfindex)
check_logfindex();
while(len > MAX_LOGF_ENTRY)
{ {
ptr = logfbuffer[logfindex]; usb_serial_send(logfbuffer + old_logfindex, MAX_LOGF_SIZE - old_logfindex);
memcpy(ptr, buf + tlen, MAX_LOGF_ENTRY); usb_serial_send(logfbuffer, logfindex - 1);
ptr[MAX_LOGF_ENTRY] = LOGF_TERMINATE_CONTINUE_LINE;
logfindex++;
check_logfindex();
len -= MAX_LOGF_ENTRY;
tlen += MAX_LOGF_ENTRY;
multiline = true;
} }
else
ptr = logfbuffer[logfindex]; usb_serial_send(logfbuffer + old_logfindex, logfindex - old_logfindex - 1);
memcpy(ptr, buf + tlen,len); usb_serial_send("\r\n", 2);
#endif
if(len < MAX_LOGF_ENTRY)
/* pad with spaces up to the MAX_LOGF_ENTRY byte border */
memset(ptr+len, ' ', MAX_LOGF_ENTRY-len);
ptr[MAX_LOGF_ENTRY] = (multiline)?LOGF_TERMINATE_MULTI_LINE:LOGF_TERMINATE_ONE_LINE;
logfindex++; /* leave it where we write the next time */
displayremote(); displayremote();
} }