cc6b036ef5
Change-Id: I060033d9a7cd54bab75e4f82e3de002bdb027af2
381 lines
8.5 KiB
C
381 lines
8.5 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2005 by Daniel Stenberg
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/*
|
|
* logf() logs entries in a circular buffer. Each logged string is null-terminated.
|
|
*
|
|
* When the length of log exceeds MAX_LOGF_SIZE bytes, the buffer wraps.
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "font.h"
|
|
#include "lcd.h"
|
|
#ifdef HAVE_REMOTE_LCD
|
|
#include "lcd-remote.h"
|
|
#endif
|
|
#include "logf.h"
|
|
#include "serial.h"
|
|
#include "vuprintf.h"
|
|
|
|
#ifdef HAVE_USBSTACK
|
|
#include "usb_core.h"
|
|
#include "usbstack/usb_serial.h"
|
|
#else
|
|
#undef USB_ENABLE_SERIAL
|
|
#endif
|
|
|
|
#ifdef ROCKBOX_HAS_LOGDISKF
|
|
#include "logdiskf.h"
|
|
#include "file.h"
|
|
#include "rbpaths.h"
|
|
#include "ata_idle_notify.h"
|
|
|
|
unsigned char logdiskfbuffer[MAX_LOGDISKF_SIZE];
|
|
static int logdiskfindex;
|
|
#endif
|
|
|
|
/* Only provide all this if asked to */
|
|
#ifdef ROCKBOX_HAS_LOGF
|
|
|
|
#ifndef __PCTOOL__
|
|
unsigned char logfbuffer[MAX_LOGF_SIZE + 1];
|
|
int logfindex;
|
|
bool logfwrap;
|
|
bool logfenabled = true;
|
|
#endif
|
|
|
|
#ifdef HAVE_REMOTE_LCD
|
|
static void displayremote(void)
|
|
{
|
|
/* TODO: we should have a debug option that enables/disables this! */
|
|
int w, h, i;
|
|
int fontnr;
|
|
int cur_x, cur_y, delta_y, delta_x;
|
|
struct font* font;
|
|
int nb_lines;
|
|
char buf[2];
|
|
/* Memorize the pointer to the beginning of the last ... lines
|
|
I assume delta_y >= 6 to avoid wasting memory and allocating memory dynamically
|
|
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();
|
|
|
|
i = line_start_ptr[ MAX(nb_lines - h / delta_y, 0) % NB_ENTRIES];
|
|
cur_x = 0;
|
|
cur_y = 0;
|
|
buf[1] = '\0';
|
|
|
|
do {
|
|
if(logfbuffer[i] == '\0')
|
|
{
|
|
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;
|
|
}
|
|
|
|
i++;
|
|
if(i >= MAX_LOGF_SIZE)
|
|
i = 0;
|
|
} while(i != logfindex);
|
|
|
|
lcd_remote_update();
|
|
}
|
|
#else
|
|
#define displayremote()
|
|
#endif
|
|
|
|
#ifdef __PCTOOL__
|
|
void _logf(const char *format, ...)
|
|
{
|
|
char buf[1024];
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
|
|
vsnprintf(buf, sizeof buf, format, ap);
|
|
printf("DEBUG: %s\n", buf);
|
|
}
|
|
#else
|
|
static void check_logfindex(void)
|
|
{
|
|
if(logfindex >= MAX_LOGF_SIZE)
|
|
{
|
|
/* wrap */
|
|
logfwrap = true;
|
|
logfindex = 0;
|
|
}
|
|
}
|
|
|
|
static int logf_push(void *userp, int c)
|
|
{
|
|
(void)userp;
|
|
|
|
logfbuffer[logfindex++] = c;
|
|
check_logfindex();
|
|
|
|
#if defined(HAVE_SERIAL) && !defined(SIMULATOR) && defined(LOGF_SERIAL)
|
|
if(c != '\0')
|
|
{
|
|
char buf[2];
|
|
buf[0] = c;
|
|
buf[1] = '\0';
|
|
serial_tx(buf);
|
|
}
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
void _logf(const char *fmt, ...)
|
|
{
|
|
if (!logfenabled)
|
|
return;
|
|
|
|
#ifdef USB_ENABLE_SERIAL
|
|
int old_logfindex = logfindex;
|
|
#endif
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
|
|
char buf[1024];
|
|
vsnprintf(buf, sizeof buf, fmt, ap);
|
|
DEBUGF("%s\n", buf);
|
|
/* restart va_list otherwise the result if undefined when vuprintf is called */
|
|
va_end(ap);
|
|
va_start(ap, fmt);
|
|
#endif
|
|
|
|
vuprintf(logf_push, NULL, fmt, ap);
|
|
va_end(ap);
|
|
|
|
/* add trailing zero */
|
|
logf_push(NULL, '\0');
|
|
|
|
#if defined(HAVE_SERIAL) && !defined(SIMULATOR) && defined(LOGF_SERIAL)
|
|
serial_tx("\r\n");
|
|
#endif
|
|
#ifdef USB_ENABLE_SERIAL
|
|
|
|
if(logfindex < old_logfindex)
|
|
{
|
|
usb_serial_send(logfbuffer + old_logfindex, MAX_LOGF_SIZE - old_logfindex);
|
|
usb_serial_send(logfbuffer, logfindex - 1);
|
|
}
|
|
else
|
|
usb_serial_send(logfbuffer + old_logfindex, logfindex - old_logfindex - 1);
|
|
usb_serial_send("\r\n", 2);
|
|
#endif
|
|
|
|
displayremote();
|
|
}
|
|
#endif
|
|
|
|
void logf_panic_dump(int *y)
|
|
{
|
|
int i;
|
|
/* nothing to print ? */
|
|
if(logfindex == 0 && !logfwrap)
|
|
{
|
|
lcd_puts(1, (*y)++, "no logf data");
|
|
lcd_update();
|
|
return;
|
|
}
|
|
|
|
/* Explicitly null-terminate our buffer */
|
|
logfbuffer[MAX_LOGF_SIZE] = 0;
|
|
|
|
lcd_puts(1, (*y)++, "start of logf data");
|
|
lcd_update();
|
|
|
|
/* The intent is to dump the newest log entries first! */
|
|
i = logfindex - 2; /* The last actual characer (i.e. not '\0') */
|
|
while(i >= 0)
|
|
{
|
|
while(logfbuffer[i] != 0 && i>=0)
|
|
{
|
|
i--;
|
|
}
|
|
if(strlen( &logfbuffer[i + 1]) > 0)
|
|
{
|
|
lcd_puts(1, (*y)++, &logfbuffer[i + 1]);
|
|
lcd_update();
|
|
}
|
|
i--;
|
|
}
|
|
if(logfwrap)
|
|
{
|
|
i = MAX_LOGF_SIZE - 1;
|
|
while(i >= logfindex)
|
|
{
|
|
while(logfbuffer[i] != 0 && i >= logfindex)
|
|
{
|
|
i--;
|
|
}
|
|
if(strlen( &logfbuffer[i + 1]) > 0)
|
|
{
|
|
lcd_putsf(1, (*y)++, "%*s", (MAX_LOGF_SIZE-i), &logfbuffer[i + 1]);
|
|
lcd_update();
|
|
}
|
|
}
|
|
i--;
|
|
}
|
|
|
|
lcd_puts(1, (*y)++, "end of logf data");
|
|
lcd_update();
|
|
}
|
|
#endif
|
|
|
|
#ifdef ROCKBOX_HAS_LOGDISKF
|
|
static int logdiskf_push(void *userp, int c)
|
|
{
|
|
(void)userp;
|
|
|
|
/*just stop logging if out of space*/
|
|
if(logdiskfindex>=MAX_LOGDISKF_SIZE-1)
|
|
{
|
|
strcpy(&logdiskfbuffer[logdiskfindex-8], "LOGFULL");
|
|
logdiskfindex=MAX_LOGDISKF_SIZE;
|
|
return 0;
|
|
}
|
|
logdiskfbuffer[logdiskfindex++] = c;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void flush_buffer(void);
|
|
|
|
void _logdiskf(const char* file, const char level, const char *fmt, ...)
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
int len =strlen(file);
|
|
if(logdiskfindex +len + 4 > MAX_LOGDISKF_SIZE-1)
|
|
{
|
|
strcpy(&logdiskfbuffer[logdiskfindex-8], "LOGFULL");
|
|
logdiskfindex=MAX_LOGDISKF_SIZE;
|
|
va_end(ap);
|
|
return;
|
|
}
|
|
|
|
logdiskf_push(NULL, level);
|
|
logdiskf_push(NULL, ' ');
|
|
logdiskf_push(NULL, '[');
|
|
strcpy(&logdiskfbuffer[logdiskfindex], file);
|
|
logdiskfindex += len;
|
|
logdiskf_push(NULL, ']');
|
|
|
|
vuprintf(logdiskf_push, NULL, fmt, ap);
|
|
va_end(ap);
|
|
register_storage_idle_func(flush_buffer);
|
|
}
|
|
|
|
static void flush_buffer(void)
|
|
{
|
|
int fd;
|
|
if(logdiskfindex < 1)
|
|
return;
|
|
|
|
fd = open(HOME_DIR"/rockbox_log.txt", O_RDWR | O_CREAT | O_APPEND, 0666);
|
|
if (fd < 0)
|
|
return;
|
|
|
|
write(fd, logdiskfbuffer, logdiskfindex);
|
|
close(fd);
|
|
|
|
logdiskfindex = 0;
|
|
}
|
|
|
|
#endif
|