e599810ffa
Fix log file corruption if we have new messages at dumping log to file. Comment removed as it incorrect. We store all messages in direct order (last message at end of file). Change-Id: I4acfa8a0935cc41a889e08f6bc42974fefd1ade2
374 lines
8.3 KiB
C
374 lines
8.3 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 "format.h"
|
|
|
|
#ifdef HAVE_USBSTACK
|
|
#include "usb_core.h"
|
|
#include "usbstack/usb_serial.h"
|
|
#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];
|
|
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, unsigned char 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 true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
lcd_puts(1, (*y)++, "start of logf data");
|
|
lcd_update();
|
|
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, unsigned char 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 false;
|
|
}
|
|
logdiskfbuffer[logdiskfindex++] = c;
|
|
|
|
return true;
|
|
}
|
|
|
|
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
|