rockbox/firmware/logf.c
Amaury Pouly c13f21a4d5 Fix logdisk
The code was broken in a subtle but crucial way: storage idle
callbacks are oneshot so after the first flush everything would
stay in the buffer forever and would never be written to the disk
thus resulting into many events being lost. This changed correctly
registers the idle callback each time the buffer is not empty.
Note that the idle storage code checks if a callback
has is in the queue already so we don't register twice.

Change-Id: Ifdf331d4b757e05b8a6902bf5926cbc7689f5109
2013-08-16 21:59:16 +02:00

321 lines
7.2 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"
#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];
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;
#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, ...)
{
#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
#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* data);
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;
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* data)
{
(void)data;
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