forked from len0rd/rockbox
[Feature] db_commit plugin allows a more verbose commit
prints logf messages to the screen buffer and dumps the output to .rockbox/db_commit_log.txt logs warnings about tags that can't be displayed by the current font adds an option to the tagcache using the file .rockbox/database_commit.ignore to prevent auto commit Change-Id: Ib381b3b6d9dd19d76c95d0e87e605f7378e29674
This commit is contained in:
parent
6634a60bf0
commit
1ed640da24
13 changed files with 707 additions and 19 deletions
|
@ -832,7 +832,7 @@ static const struct plugin_api rockbox_api = {
|
||||||
|
|
||||||
/* new stuff at the end, sort into place next time
|
/* new stuff at the end, sort into place next time
|
||||||
the API gets incompatible */
|
the API gets incompatible */
|
||||||
|
tagcache_commit_finalize,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int plugin_buffer_handle;
|
static int plugin_buffer_handle;
|
||||||
|
|
|
@ -969,7 +969,7 @@ struct plugin_api {
|
||||||
#endif
|
#endif
|
||||||
/* new stuff at the end, sort into place next time
|
/* new stuff at the end, sort into place next time
|
||||||
the API gets incompatible */
|
the API gets incompatible */
|
||||||
|
void (*tagcache_commit_finalize)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* plugin header */
|
/* plugin header */
|
||||||
|
|
|
@ -22,6 +22,7 @@ clock,apps
|
||||||
codebuster,games
|
codebuster,games
|
||||||
credits,viewers
|
credits,viewers
|
||||||
cube,demos
|
cube,demos
|
||||||
|
db_commit,apps
|
||||||
db_folder_select,viewers
|
db_folder_select,viewers
|
||||||
demystify,demos
|
demystify,demos
|
||||||
dice,games
|
dice,games
|
||||||
|
|
|
@ -4,6 +4,7 @@ battery_bench.c
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_TAGCACHE
|
#ifdef HAVE_TAGCACHE
|
||||||
db_folder_select.c
|
db_folder_select.c
|
||||||
|
tagcache/tagcache.c
|
||||||
#endif
|
#endif
|
||||||
chessclock.c
|
chessclock.c
|
||||||
credits.c
|
credits.c
|
||||||
|
|
|
@ -31,6 +31,7 @@ rockboy
|
||||||
|
|
||||||
#if defined(HAVE_TAGCACHE)
|
#if defined(HAVE_TAGCACHE)
|
||||||
pictureflow
|
pictureflow
|
||||||
|
tagcache
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PLUGIN_BUFFER_SIZE > 0x20000
|
#if PLUGIN_BUFFER_SIZE > 0x20000
|
||||||
|
|
|
@ -17,6 +17,7 @@ reversi
|
||||||
|
|
||||||
#ifdef HAVE_TAGCACHE
|
#ifdef HAVE_TAGCACHE
|
||||||
pictureflow
|
pictureflow
|
||||||
|
tagcache
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* For all the swcodec targets */
|
/* For all the swcodec targets */
|
||||||
|
|
2
apps/plugins/tagcache/SOURCES
Normal file
2
apps/plugins/tagcache/SOURCES
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
tagcache.c
|
||||||
|
|
581
apps/plugins/tagcache/tagcache.c
Normal file
581
apps/plugins/tagcache/tagcache.c
Normal file
|
@ -0,0 +1,581 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 by William Wilgus
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*Plugin Includes*/
|
||||||
|
|
||||||
|
#include "plugin.h"
|
||||||
|
/* Redefinitons of ANSI C functions. */
|
||||||
|
#include "lib/wrappers.h"
|
||||||
|
#include "lib/helper.h"
|
||||||
|
|
||||||
|
static void thread_create(void);
|
||||||
|
static void thread(void); /* the thread running it all */
|
||||||
|
static void allocate_tempbuf(void);
|
||||||
|
static void free_tempbuf(void);
|
||||||
|
static bool do_timed_yield(void);
|
||||||
|
static void _log(const char *fmt, ...);
|
||||||
|
/*Aliases*/
|
||||||
|
#if 0
|
||||||
|
#ifdef ROCKBOX_HAS_LOGF
|
||||||
|
#define logf rb->logf
|
||||||
|
#else
|
||||||
|
#define logf(...) {}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define logf _log
|
||||||
|
#define sleep rb->sleep
|
||||||
|
#define qsort rb->qsort
|
||||||
|
|
||||||
|
#define write(x,y,z) rb->write(x,y,z)
|
||||||
|
#define ftruncate rb->ftruncate
|
||||||
|
#define remove rb->remove
|
||||||
|
|
||||||
|
#define vsnprintf rb->vsnprintf
|
||||||
|
#define mkdir rb->mkdir
|
||||||
|
#define filesize rb->filesize
|
||||||
|
|
||||||
|
#define strtok_r rb->strtok_r
|
||||||
|
#define strncasecmp rb->strncasecmp
|
||||||
|
#define strcasecmp rb->strcasecmp
|
||||||
|
|
||||||
|
#define current_tick (*rb->current_tick)
|
||||||
|
#define crc_32(x,y,z) rb->crc_32(x,y,z)
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SIMULATOR
|
||||||
|
#define errno (*rb->__errno())
|
||||||
|
#endif
|
||||||
|
#define ENOENT 2 /* No such file or directory */
|
||||||
|
#define EEXIST 17 /* File exists */
|
||||||
|
#define MAX_LOG_SIZE 16384
|
||||||
|
|
||||||
|
#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF)
|
||||||
|
#define EV_ACTION MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02)
|
||||||
|
#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01)
|
||||||
|
|
||||||
|
/* communication to the worker thread */
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int user_index;
|
||||||
|
bool exiting; /* signal to the thread that we want to exit */
|
||||||
|
bool resume;
|
||||||
|
unsigned int id; /* worker thread id */
|
||||||
|
struct event_queue queue; /* thread event queue */
|
||||||
|
long last_useraction_tick;
|
||||||
|
} gThread;
|
||||||
|
|
||||||
|
|
||||||
|
/*Support Fns*/
|
||||||
|
/* open but with a builtin printf for assembling the path */
|
||||||
|
int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, pathfmt);
|
||||||
|
vsnprintf(buf, size, pathfmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if ((oflag & O_PATH) == O_PATH)
|
||||||
|
return -1;
|
||||||
|
int handle = open(buf, oflag, 0666);
|
||||||
|
//logf("Open: %s %d flag: %x", buf, handle, oflag);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleep_yield(void)
|
||||||
|
{
|
||||||
|
rb->queue_remove_from_head(&gThread.queue, EV_ACTION);
|
||||||
|
rb->queue_post(&gThread.queue, EV_ACTION, 0);
|
||||||
|
sleep(1);
|
||||||
|
#undef yield
|
||||||
|
rb->yield();
|
||||||
|
#define yield sleep_yield
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure tag can be displayed by font pf*/
|
||||||
|
static bool text_is_displayable(struct font *pf, unsigned char *src)
|
||||||
|
{
|
||||||
|
unsigned short code;
|
||||||
|
const unsigned char *ptr = src;
|
||||||
|
while(*ptr)
|
||||||
|
{
|
||||||
|
ptr = rb->utf8decode(ptr, &code);
|
||||||
|
|
||||||
|
if(!rb->font_get_bits(pf, code))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* callback for each tag if false returned tag will not be added */
|
||||||
|
bool user_check_tag(int index_type, char* build_idx_buf)
|
||||||
|
{
|
||||||
|
static struct font *pf = NULL;
|
||||||
|
if (!pf)
|
||||||
|
pf = rb->font_get(FONT_UI);
|
||||||
|
|
||||||
|
if (index_type == tag_artist || index_type == tag_album ||
|
||||||
|
index_type == tag_genre || index_type == tag_title ||
|
||||||
|
index_type == tag_composer || index_type == tag_comment ||
|
||||||
|
index_type == tag_albumartist || index_type == tag_virt_canonicalartist)
|
||||||
|
{
|
||||||
|
/* this could be expanded with more rules / transformations */
|
||||||
|
if (rb->utf8length(build_idx_buf) != strlen(build_idx_buf))
|
||||||
|
{
|
||||||
|
if (!text_is_displayable(pf, build_idx_buf))
|
||||||
|
{
|
||||||
|
logf("Can't display (%d) %s", index_type, build_idx_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* undef features we don't need */
|
||||||
|
#undef HAVE_DIRCACHE
|
||||||
|
#undef HAVE_TC_RAMCACHE
|
||||||
|
#undef HAVE_EEPROM_SETTINGS
|
||||||
|
/* paste the whole tagcache.c file */
|
||||||
|
#include "../tagcache.c"
|
||||||
|
|
||||||
|
static bool logdump(bool append);
|
||||||
|
static unsigned char logbuffer[MAX_LOG_SIZE + 1];
|
||||||
|
static int logindex;
|
||||||
|
static bool logwrap;
|
||||||
|
static bool logenabled = true;
|
||||||
|
|
||||||
|
static void check_logindex(void)
|
||||||
|
{
|
||||||
|
if(logindex >= MAX_LOG_SIZE)
|
||||||
|
{
|
||||||
|
/* wrap */
|
||||||
|
logdump(true);
|
||||||
|
//logwrap = true;
|
||||||
|
logindex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int log_push(void *userp, int c)
|
||||||
|
{
|
||||||
|
(void)userp;
|
||||||
|
|
||||||
|
logbuffer[logindex++] = c;
|
||||||
|
check_logindex();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* our logf function */
|
||||||
|
static void _log(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
if (!logenabled)
|
||||||
|
{
|
||||||
|
rb->splash(10, "log not enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_SERIAL
|
||||||
|
int old_logindex = logindex;
|
||||||
|
#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
|
||||||
|
|
||||||
|
rb->vuprintf(log_push, NULL, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/* add trailing zero */
|
||||||
|
log_push(NULL, '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int compute_nb_lines(int w, struct font* font)
|
||||||
|
{
|
||||||
|
int i, nb_lines;
|
||||||
|
int cur_x, delta_x;
|
||||||
|
|
||||||
|
if(logindex>= MAX_LOG_SIZE || (logindex == 0 && !logwrap))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(logwrap)
|
||||||
|
i = logindex;
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
cur_x = 0;
|
||||||
|
nb_lines = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(logbuffer[i] == '\0')
|
||||||
|
{
|
||||||
|
cur_x = 0;
|
||||||
|
nb_lines++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* does character fit on this line ? */
|
||||||
|
delta_x = rb->font_get_width(font, logbuffer[i]);
|
||||||
|
|
||||||
|
if(cur_x + delta_x > w)
|
||||||
|
{
|
||||||
|
cur_x = 0;
|
||||||
|
nb_lines++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update pointer */
|
||||||
|
cur_x += delta_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if(i >= MAX_LOG_SIZE)
|
||||||
|
i = 0;
|
||||||
|
} while(i != logindex);
|
||||||
|
|
||||||
|
return nb_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool logdisplay(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
int w, h, i, index;
|
||||||
|
int fontnr;
|
||||||
|
static int delta_y = -1;
|
||||||
|
int cur_x, cur_y, delta_x;
|
||||||
|
struct font* font;
|
||||||
|
|
||||||
|
char buf[2];
|
||||||
|
|
||||||
|
fontnr = FONT_FIRSTUSERFONT;
|
||||||
|
font = rb->font_get(fontnr);
|
||||||
|
buf[1] = '\0';
|
||||||
|
w = LCD_WIDTH;
|
||||||
|
h = LCD_HEIGHT;
|
||||||
|
|
||||||
|
if (delta_y < 0) /* init, get the horizontal size of each line */
|
||||||
|
{
|
||||||
|
rb->font_getstringsize("A", NULL, &delta_y, fontnr);
|
||||||
|
/* start at the end of the log */
|
||||||
|
gThread.user_index = compute_nb_lines(w, font) - h/delta_y -1;
|
||||||
|
/* user_index will be number of the first line to display (warning: line!=log entry) */
|
||||||
|
/* if negative, will be set 0 to zero later */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rb->lcd_clear_display();
|
||||||
|
|
||||||
|
if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE)
|
||||||
|
gThread.user_index = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if(logwrap)
|
||||||
|
i = logindex;
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
cur_x = 0;
|
||||||
|
cur_y = 0;
|
||||||
|
|
||||||
|
/* nothing to print ? */
|
||||||
|
if(logindex == 0 && !logwrap)
|
||||||
|
goto end_print;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(logbuffer[i] == '\0')
|
||||||
|
{
|
||||||
|
/* should be display a newline ? */
|
||||||
|
if(index >= gThread.user_index)
|
||||||
|
cur_y += delta_y;
|
||||||
|
cur_x = 0;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* does character fit on this line ? */
|
||||||
|
delta_x = rb->font_get_width(font, logbuffer[i]);
|
||||||
|
|
||||||
|
if(cur_x + delta_x > w)
|
||||||
|
{
|
||||||
|
/* should be display a newline ? */
|
||||||
|
if(index >= gThread.user_index)
|
||||||
|
cur_y += delta_y;
|
||||||
|
cur_x = 0;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* should we print character ? */
|
||||||
|
if(index >= gThread.user_index)
|
||||||
|
{
|
||||||
|
buf[0] = logbuffer[i];
|
||||||
|
rb->lcd_putsxy(cur_x, cur_y, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update pointer */
|
||||||
|
cur_x += delta_x;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
/* did we fill the screen ? */
|
||||||
|
if(cur_y > h - delta_y)
|
||||||
|
{
|
||||||
|
if (TIME_AFTER(current_tick, gThread.last_useraction_tick + HZ))
|
||||||
|
gThread.user_index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i >= MAX_LOG_SIZE)
|
||||||
|
i = 0;
|
||||||
|
} while(i != logindex);
|
||||||
|
|
||||||
|
end_print:
|
||||||
|
rb->lcd_update();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool logdump(bool append)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int flags = O_CREAT|O_WRONLY|O_TRUNC;
|
||||||
|
/* nothing to print ? */
|
||||||
|
if(!logenabled || (logindex == 0 && !logwrap))
|
||||||
|
{
|
||||||
|
/* nothing is logged just yet */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!append)
|
||||||
|
{
|
||||||
|
flags = O_CREAT|O_WRONLY|O_APPEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(ROCKBOX_DIR "/db_commit_log.txt", flags, 0666);
|
||||||
|
logenabled = false;
|
||||||
|
if(-1 != fd) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(logwrap)
|
||||||
|
i = logindex;
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(logbuffer[i]=='\0')
|
||||||
|
rb->fdprintf(fd, "\n");
|
||||||
|
else
|
||||||
|
rb->fdprintf(fd, "%c", logbuffer[i]);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if(i >= MAX_LOG_SIZE)
|
||||||
|
i = 0;
|
||||||
|
} while(i != logindex);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
logenabled = true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void allocate_tempbuf(void)
|
||||||
|
{
|
||||||
|
tempbuf_size = 0;
|
||||||
|
tempbuf = rb->plugin_get_audio_buffer(&tempbuf_size);
|
||||||
|
tempbuf_size &= ~0x03;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_tempbuf(void)
|
||||||
|
{
|
||||||
|
if (tempbuf_size == 0)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
rb->plugin_release_audio_buffer();
|
||||||
|
tempbuf = NULL;
|
||||||
|
tempbuf_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool do_timed_yield(void)
|
||||||
|
{
|
||||||
|
/* Sorting can lock up for quite a while, so yield occasionally */
|
||||||
|
static long wakeup_tick = 0;
|
||||||
|
if (TIME_AFTER(current_tick, wakeup_tick))
|
||||||
|
{
|
||||||
|
|
||||||
|
yield();
|
||||||
|
|
||||||
|
wakeup_tick = current_tick + (HZ/5);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/******* plugin_start ******* */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
enum plugin_status plugin_start(const void* parameter)
|
||||||
|
{
|
||||||
|
(void) parameter;
|
||||||
|
|
||||||
|
/* Turn off backlight timeout */
|
||||||
|
backlight_ignore_timeout();
|
||||||
|
|
||||||
|
memset(&tc_stat, 0, sizeof(struct tagcache_stat));
|
||||||
|
memset(¤t_tcmh, 0, sizeof(struct master_header));
|
||||||
|
filenametag_fd = -1;
|
||||||
|
|
||||||
|
strlcpy(tc_stat.db_path, rb->global_settings->tagcache_db_path, sizeof(tc_stat.db_path));
|
||||||
|
if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */
|
||||||
|
strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path));
|
||||||
|
tc_stat.initialized = true;
|
||||||
|
|
||||||
|
memset(&gThread, 0, sizeof(gThread));
|
||||||
|
logf("started");
|
||||||
|
logdump(false);
|
||||||
|
|
||||||
|
thread_create();
|
||||||
|
gThread.user_index = 0;
|
||||||
|
logdisplay(); /* get something on the screen while user waits */
|
||||||
|
|
||||||
|
allocate_tempbuf();
|
||||||
|
|
||||||
|
commit();
|
||||||
|
|
||||||
|
if (tc_stat.ready)
|
||||||
|
rb->tagcache_commit_finalize();
|
||||||
|
|
||||||
|
free_tempbuf();
|
||||||
|
|
||||||
|
logdump(true);
|
||||||
|
gThread.user_index++;
|
||||||
|
logdisplay();
|
||||||
|
rb->thread_wait(gThread.id);
|
||||||
|
rb->queue_delete(&gThread.queue);
|
||||||
|
|
||||||
|
/* Turn on backlight timeout (revert to settings) */
|
||||||
|
backlight_use_settings();
|
||||||
|
return PLUGIN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************** main thread + helper ******************/
|
||||||
|
static void thread(void)
|
||||||
|
{
|
||||||
|
struct queue_event ev;
|
||||||
|
while (!gThread.exiting)
|
||||||
|
{
|
||||||
|
rb->queue_wait_w_tmo(&gThread.queue, &ev, 1);
|
||||||
|
switch (ev.id)
|
||||||
|
{
|
||||||
|
case SYS_USB_CONNECTED:
|
||||||
|
rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||||
|
logenabled = false;
|
||||||
|
break;
|
||||||
|
case SYS_USB_DISCONNECTED:
|
||||||
|
logenabled = true;
|
||||||
|
/*fall through*/
|
||||||
|
case EV_STARTUP:
|
||||||
|
logf("Thread Started");
|
||||||
|
break;
|
||||||
|
case EV_EXIT:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
logdisplay();
|
||||||
|
|
||||||
|
int action = rb->get_action(CONTEXT_STD, HZ/10);
|
||||||
|
|
||||||
|
switch( action )
|
||||||
|
{
|
||||||
|
case ACTION_NONE:
|
||||||
|
break;
|
||||||
|
case ACTION_STD_NEXT:
|
||||||
|
case ACTION_STD_NEXTREPEAT:
|
||||||
|
gThread.last_useraction_tick = current_tick;
|
||||||
|
gThread.user_index++;
|
||||||
|
break;
|
||||||
|
case ACTION_STD_PREV:
|
||||||
|
case ACTION_STD_PREVREPEAT:
|
||||||
|
gThread.last_useraction_tick = current_tick;
|
||||||
|
gThread.user_index--;
|
||||||
|
break;
|
||||||
|
case ACTION_STD_OK:
|
||||||
|
gThread.last_useraction_tick = current_tick;
|
||||||
|
gThread.user_index = 0;
|
||||||
|
break;
|
||||||
|
case SYS_POWEROFF:
|
||||||
|
case ACTION_STD_CANCEL:
|
||||||
|
gThread.exiting = true;
|
||||||
|
return;
|
||||||
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
|
case ACTION_TOUCHSCREEN:
|
||||||
|
{
|
||||||
|
gThread.last_useraction_tick = current_tick;
|
||||||
|
short x, y;
|
||||||
|
static int prev_y;
|
||||||
|
|
||||||
|
action = action_get_touchscreen_press(&x, &y);
|
||||||
|
|
||||||
|
if(action & BUTTON_REL)
|
||||||
|
prev_y = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(prev_y != 0)
|
||||||
|
gThread.user_index += (prev_y - y) / delta_y;
|
||||||
|
|
||||||
|
prev_y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void thread_create(void)
|
||||||
|
{
|
||||||
|
/* put the thread's queue in the bcast list */
|
||||||
|
rb->queue_init(&gThread.queue, true);
|
||||||
|
/*Note: tagcache_stack is defined in apps/tagcache.c */
|
||||||
|
gThread.last_useraction_tick = current_tick;
|
||||||
|
gThread.id = rb->create_thread(thread, tagcache_stack, sizeof(tagcache_stack),
|
||||||
|
0, "db_commit"
|
||||||
|
IF_PRIO(, PRIORITY_USER_INTERFACE)
|
||||||
|
IF_COP(, CPU));
|
||||||
|
rb->queue_post(&gThread.queue, EV_STARTUP, 0);
|
||||||
|
yield();
|
||||||
|
}
|
25
apps/plugins/tagcache/tagcache.h
Normal file
25
apps/plugins/tagcache/tagcache.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C)
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef _TC_PLUGIN_
|
||||||
|
#define _TC_PLUGIN_
|
||||||
|
#endif /*_TC_PLUGIN_ */
|
||||||
|
|
||||||
|
|
30
apps/plugins/tagcache/tagcache.make
Normal file
30
apps/plugins/tagcache/tagcache.make
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# __________ __ ___.
|
||||||
|
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
# \/ \/ \/ \/ \/
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
TCPLUG_SRCDIR := $(APPSDIR)/plugins/tagcache
|
||||||
|
TCPLUG_BUILDDIR := $(BUILDDIR)/apps/plugins/tagcache
|
||||||
|
|
||||||
|
ROCKS += $(TCPLUG_BUILDDIR)/db_commit.rock
|
||||||
|
|
||||||
|
TCPLUG_FLAGS = $(PLUGINFLAGS) -fno-strict-aliasing -Wno-unused \
|
||||||
|
-I$(TCPLUG_SRCDIR) -ffunction-sections \
|
||||||
|
-fdata-sections -Wl,--gc-sections
|
||||||
|
TCPLUG_SRC := $(call preprocess, $(TCPLUG_SRCDIR)/SOURCES)
|
||||||
|
TCPLUG_OBJ := $(call c2obj, $(TCPLUG_SRC))
|
||||||
|
|
||||||
|
# add source files to OTHER_SRC to get automatic dependencies
|
||||||
|
OTHER_SRC += $(APPSDIR)/tagcache.c $(TCPLUG_SRC)
|
||||||
|
|
||||||
|
$(TCPLUG_BUILDDIR)/db_commit.rock: $(TCPLUG_OBJ)
|
||||||
|
|
||||||
|
# special pattern rule for compiling with extra flags
|
||||||
|
$(TCPLUG_BUILDDIR)/%.o: $(TCPLUG_SRCDIR)/%.c $(TCPLUG_SRCDIR)/tagcache.make
|
||||||
|
$(SILENT)mkdir -p $(dir $@)
|
||||||
|
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(TCPLUG_FLAGS) -c $< -o $@
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !defined(PLUGIN)
|
||||||
|
|
||||||
/*#define LOGF_ENABLE*/
|
/*#define LOGF_ENABLE*/
|
||||||
/*#define LOGF_CLAUSES define to enable logf clause matching (LOGF_ENABLE req'd) */
|
/*#define LOGF_CLAUSES define to enable logf clause matching (LOGF_ENABLE req'd) */
|
||||||
|
@ -91,7 +92,7 @@
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "eeprom_settings.h"
|
#include "eeprom_settings.h"
|
||||||
#endif
|
#endif
|
||||||
|
#endif /*!defined(PLUGIN)*/
|
||||||
/*
|
/*
|
||||||
* Define this to support non-native endian tagcache files.
|
* Define this to support non-native endian tagcache files.
|
||||||
* Databases are always written in native endian so this is
|
* Databases are always written in native endian so this is
|
||||||
|
@ -132,6 +133,9 @@
|
||||||
/* Idle time before committing events in the command queue. */
|
/* Idle time before committing events in the command queue. */
|
||||||
#define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2
|
#define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2
|
||||||
|
|
||||||
|
/* Dont commit database_tmp data. */
|
||||||
|
#define TAGCACHE_FILE_NOCOMMIT "database_commit.ignore"
|
||||||
|
|
||||||
/* Temporary database containing new tags to be committed to the main db. */
|
/* Temporary database containing new tags to be committed to the main db. */
|
||||||
#define TAGCACHE_FILE_TEMP "database_tmp.tcd"
|
#define TAGCACHE_FILE_TEMP "database_tmp.tcd"
|
||||||
|
|
||||||
|
@ -730,7 +734,7 @@ static bool update_master_header(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(PLUGIN)
|
||||||
#ifndef __PCTOOL__
|
#ifndef __PCTOOL__
|
||||||
static bool do_timed_yield(void)
|
static bool do_timed_yield(void)
|
||||||
{
|
{
|
||||||
|
@ -2355,6 +2359,8 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
|
||||||
|
|
||||||
#undef ADD_TAG
|
#undef ADD_TAG
|
||||||
}
|
}
|
||||||
|
#endif /*!defined(PLUGIN)*/
|
||||||
|
|
||||||
|
|
||||||
static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
|
static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
|
||||||
{
|
{
|
||||||
|
@ -3064,18 +3070,22 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
||||||
}
|
}
|
||||||
str_setlen(build_idx_buf, entry.tag_length[index_type]);
|
str_setlen(build_idx_buf, entry.tag_length[index_type]);
|
||||||
|
|
||||||
if (TAGCACHE_IS_UNIQUE(index_type))
|
#if defined(PLUGIN)
|
||||||
error = !tempbuf_insert(build_idx_buf, i, -1, true);
|
if (user_check_tag(index_type, build_idx_buf))
|
||||||
else
|
#endif /*defined(PLUGIN)*/
|
||||||
error = !tempbuf_insert(build_idx_buf, i,
|
|
||||||
tcmh.tch.entry_count + i, false);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
{
|
||||||
logf("insert error");
|
if (TAGCACHE_IS_UNIQUE(index_type))
|
||||||
goto error_exit;
|
error = !tempbuf_insert(build_idx_buf, i, -1, true);
|
||||||
}
|
else
|
||||||
|
error = !tempbuf_insert(build_idx_buf, i,
|
||||||
|
tcmh.tch.entry_count + i, false);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
logf("insert error");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Skip to next. */
|
/* Skip to next. */
|
||||||
lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] -
|
lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] -
|
||||||
entry.tag_length[index_type], SEEK_CUR);
|
entry.tag_length[index_type], SEEK_CUR);
|
||||||
|
@ -3299,7 +3309,20 @@ static bool commit(void)
|
||||||
while (write_lock)
|
while (write_lock)
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
tmpfd = open_db_fd(TAGCACHE_FILE_TEMP, O_RDONLY);
|
#if !defined(PLUGIN)
|
||||||
|
int fd = open_db_fd(TAGCACHE_FILE_NOCOMMIT, O_RDONLY);
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
logf("canceling commit");
|
||||||
|
tc_stat.commit_delayed = true;
|
||||||
|
close(fd);
|
||||||
|
tmpfd = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /*!defined(PLUGIN)*/
|
||||||
|
{
|
||||||
|
tmpfd = open_db_fd(TAGCACHE_FILE_TEMP, O_RDONLY);
|
||||||
|
}
|
||||||
if (tmpfd < 0)
|
if (tmpfd < 0)
|
||||||
{
|
{
|
||||||
logf("nothing to commit");
|
logf("nothing to commit");
|
||||||
|
@ -3361,6 +3384,14 @@ static bool commit(void)
|
||||||
}
|
}
|
||||||
#endif /* HAVE_TC_RAMCACHE */
|
#endif /* HAVE_TC_RAMCACHE */
|
||||||
|
|
||||||
|
#if defined(PLUGIN)
|
||||||
|
if (tempbuf_size == 0)
|
||||||
|
{
|
||||||
|
tempbuf = rb->plugin_get_audio_buffer(&tempbuf_size);
|
||||||
|
tempbuf_size &= ~0x03;
|
||||||
|
}
|
||||||
|
#endif /*defined(PLUGIN)*/
|
||||||
|
|
||||||
/* And finally fail if there are no buffers available. */
|
/* And finally fail if there are no buffers available. */
|
||||||
if (tempbuf_size == 0)
|
if (tempbuf_size == 0)
|
||||||
{
|
{
|
||||||
|
@ -3433,8 +3464,7 @@ static bool commit(void)
|
||||||
close(masterfd);
|
close(masterfd);
|
||||||
|
|
||||||
logf("tagcache committed");
|
logf("tagcache committed");
|
||||||
tc_stat.ready = check_all_headers();
|
tagcache_commit_finalize();
|
||||||
tc_stat.readyvalid = true;
|
|
||||||
|
|
||||||
#if defined(HAVE_TC_RAMCACHE)
|
#if defined(HAVE_TC_RAMCACHE)
|
||||||
if (ramcache_buffer_stolen)
|
if (ramcache_buffer_stolen)
|
||||||
|
@ -3476,7 +3506,13 @@ commit_error:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tagcache_commit_finalize(void)
|
||||||
|
{
|
||||||
|
tc_stat.ready = check_all_headers();
|
||||||
|
tc_stat.readyvalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(PLUGIN)
|
||||||
#ifndef __PCTOOL__
|
#ifndef __PCTOOL__
|
||||||
|
|
||||||
static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
|
static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
|
||||||
|
@ -5116,8 +5152,7 @@ static void tagcache_thread(void)
|
||||||
if (!tc_stat.ready)
|
if (!tc_stat.ready)
|
||||||
{
|
{
|
||||||
sleep(HZ);
|
sleep(HZ);
|
||||||
tc_stat.ready = check_all_headers();
|
tagcache_commit_finalize();
|
||||||
tc_stat.readyvalid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -5351,3 +5386,4 @@ int tagcache_get_max_commit_step(void)
|
||||||
{
|
{
|
||||||
return (int)(SORTED_TAGS_COUNT)+1;
|
return (int)(SORTED_TAGS_COUNT)+1;
|
||||||
}
|
}
|
||||||
|
#endif /*!defined(PLUGIN)*/
|
||||||
|
|
|
@ -204,6 +204,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename);
|
||||||
#endif
|
#endif
|
||||||
void tagcache_unload_ramcache(void);
|
void tagcache_unload_ramcache(void);
|
||||||
#endif
|
#endif
|
||||||
|
void tagcache_commit_finalize(void);
|
||||||
void tagcache_init(void) INIT_ATTR;
|
void tagcache_init(void) INIT_ATTR;
|
||||||
bool tagcache_is_initialized(void);
|
bool tagcache_is_initialized(void);
|
||||||
bool tagcache_is_fully_initialized(void);
|
bool tagcache_is_fully_initialized(void);
|
||||||
|
|
|
@ -31,6 +31,15 @@ If a subdirectory of an `ignored' directory should still be scanned, place a
|
||||||
file named \fname{database.unignore} in it. The files in that directory and
|
file named \fname{database.unignore} in it. The files in that directory and
|
||||||
its subdirectories will be scanned and added to the database.
|
its subdirectories will be scanned and added to the database.
|
||||||
|
|
||||||
|
\subsubsection{Issues During Database Commit}
|
||||||
|
|
||||||
|
You may have files on your \dap{} whose contents might not be displayed
|
||||||
|
correctly or even crash the database.
|
||||||
|
Placing a file named \fname{/.rockbox/database_commit.ignore}
|
||||||
|
will prevent the device from committing the database automatically
|
||||||
|
you can manually commit the database using the db_commit plugin in APPS
|
||||||
|
with logging
|
||||||
|
|
||||||
\subsection{\label{ref:databasemenu}The Database Menu}
|
\subsection{\label{ref:databasemenu}The Database Menu}
|
||||||
|
|
||||||
\begin{description}
|
\begin{description}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue