summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2023-10-04 08:51:10 -0400
committerWilliam Wilgus <wilgus.william@gmail.com>2023-10-05 21:24:37 -0400
commit1ed640da24eb97255328c4498035ba524f6265fc (patch)
treee89771f51a031cc114d36f6dd9c261b04cd4667d /apps
parent6634a60bf0750159ffc34bdff548fac0817e72bc (diff)
downloadrockbox-1ed640da24eb97255328c4498035ba524f6265fc.tar.gz
rockbox-1ed640da24eb97255328c4498035ba524f6265fc.zip
[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
Diffstat (limited to 'apps')
-rw-r--r--apps/plugin.c2
-rw-r--r--apps/plugin.h2
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/SUBDIRS1
-rw-r--r--apps/plugins/SUBDIRS.app_build1
-rw-r--r--apps/plugins/tagcache/SOURCES2
-rw-r--r--apps/plugins/tagcache/tagcache.c581
-rw-r--r--apps/plugins/tagcache/tagcache.h25
-rw-r--r--apps/plugins/tagcache/tagcache.make30
-rw-r--r--apps/tagcache.c70
-rw-r--r--apps/tagcache.h1
12 files changed, 698 insertions, 19 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index b1188fc183..e916918f23 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -832,7 +832,7 @@ static const struct plugin_api rockbox_api = {
832 832
833 /* new stuff at the end, sort into place next time 833 /* new stuff at the end, sort into place next time
834 the API gets incompatible */ 834 the API gets incompatible */
835 835 tagcache_commit_finalize,
836}; 836};
837 837
838static int plugin_buffer_handle; 838static int plugin_buffer_handle;
diff --git a/apps/plugin.h b/apps/plugin.h
index 11adf61e9c..4f9027987f 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -969,7 +969,7 @@ struct plugin_api {
969#endif 969#endif
970 /* new stuff at the end, sort into place next time 970 /* new stuff at the end, sort into place next time
971 the API gets incompatible */ 971 the API gets incompatible */
972 972 void (*tagcache_commit_finalize)(void);
973}; 973};
974 974
975/* plugin header */ 975/* plugin header */
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 9ec38ab76b..49016fef13 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -22,6 +22,7 @@ clock,apps
22codebuster,games 22codebuster,games
23credits,viewers 23credits,viewers
24cube,demos 24cube,demos
25db_commit,apps
25db_folder_select,viewers 26db_folder_select,viewers
26demystify,demos 27demystify,demos
27dice,games 28dice,games
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 7edc8a3c51..b857f26ba5 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -4,6 +4,7 @@ battery_bench.c
4#endif 4#endif
5#ifdef HAVE_TAGCACHE 5#ifdef HAVE_TAGCACHE
6db_folder_select.c 6db_folder_select.c
7tagcache/tagcache.c
7#endif 8#endif
8chessclock.c 9chessclock.c
9credits.c 10credits.c
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
index 4cb57edb1b..b9c18b5fd9 100644
--- a/apps/plugins/SUBDIRS
+++ b/apps/plugins/SUBDIRS
@@ -31,6 +31,7 @@ rockboy
31 31
32#if defined(HAVE_TAGCACHE) 32#if defined(HAVE_TAGCACHE)
33pictureflow 33pictureflow
34tagcache
34#endif 35#endif
35 36
36#if PLUGIN_BUFFER_SIZE > 0x20000 37#if PLUGIN_BUFFER_SIZE > 0x20000
diff --git a/apps/plugins/SUBDIRS.app_build b/apps/plugins/SUBDIRS.app_build
index 1fc283d6c4..fbf83f01da 100644
--- a/apps/plugins/SUBDIRS.app_build
+++ b/apps/plugins/SUBDIRS.app_build
@@ -17,6 +17,7 @@ reversi
17 17
18#ifdef HAVE_TAGCACHE 18#ifdef HAVE_TAGCACHE
19pictureflow 19pictureflow
20tagcache
20#endif 21#endif
21 22
22/* For all the swcodec targets */ 23/* For all the swcodec targets */
diff --git a/apps/plugins/tagcache/SOURCES b/apps/plugins/tagcache/SOURCES
new file mode 100644
index 0000000000..2541f3e87c
--- /dev/null
+++ b/apps/plugins/tagcache/SOURCES
@@ -0,0 +1,2 @@
1tagcache.c
2
diff --git a/apps/plugins/tagcache/tagcache.c b/apps/plugins/tagcache/tagcache.c
new file mode 100644
index 0000000000..25ba9bc301
--- /dev/null
+++ b/apps/plugins/tagcache/tagcache.c
@@ -0,0 +1,581 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2023 by William Wilgus
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*Plugin Includes*/
23
24#include "plugin.h"
25/* Redefinitons of ANSI C functions. */
26#include "lib/wrappers.h"
27#include "lib/helper.h"
28
29static void thread_create(void);
30static void thread(void); /* the thread running it all */
31static void allocate_tempbuf(void);
32static void free_tempbuf(void);
33static bool do_timed_yield(void);
34static void _log(const char *fmt, ...);
35/*Aliases*/
36#if 0
37#ifdef ROCKBOX_HAS_LOGF
38 #define logf rb->logf
39#else
40 #define logf(...) {}
41#endif
42#endif
43
44
45#define logf _log
46#define sleep rb->sleep
47#define qsort rb->qsort
48
49#define write(x,y,z) rb->write(x,y,z)
50#define ftruncate rb->ftruncate
51#define remove rb->remove
52
53#define vsnprintf rb->vsnprintf
54#define mkdir rb->mkdir
55#define filesize rb->filesize
56
57#define strtok_r rb->strtok_r
58#define strncasecmp rb->strncasecmp
59#define strcasecmp rb->strcasecmp
60
61#define current_tick (*rb->current_tick)
62#define crc_32(x,y,z) rb->crc_32(x,y,z)
63
64
65#ifndef SIMULATOR
66#define errno (*rb->__errno())
67#endif
68#define ENOENT 2 /* No such file or directory */
69#define EEXIST 17 /* File exists */
70#define MAX_LOG_SIZE 16384
71
72#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF)
73#define EV_ACTION MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02)
74#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01)
75
76/* communication to the worker thread */
77static struct
78{
79 int user_index;
80 bool exiting; /* signal to the thread that we want to exit */
81 bool resume;
82 unsigned int id; /* worker thread id */
83 struct event_queue queue; /* thread event queue */
84 long last_useraction_tick;
85} gThread;
86
87
88/*Support Fns*/
89/* open but with a builtin printf for assembling the path */
90int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...)
91{
92 va_list ap;
93 va_start(ap, pathfmt);
94 vsnprintf(buf, size, pathfmt, ap);
95 va_end(ap);
96 if ((oflag & O_PATH) == O_PATH)
97 return -1;
98 int handle = open(buf, oflag, 0666);
99 //logf("Open: %s %d flag: %x", buf, handle, oflag);
100 return handle;
101}
102
103static void sleep_yield(void)
104{
105 rb->queue_remove_from_head(&gThread.queue, EV_ACTION);
106 rb->queue_post(&gThread.queue, EV_ACTION, 0);
107 sleep(1);
108 #undef yield
109 rb->yield();
110 #define yield sleep_yield
111}
112
113/* make sure tag can be displayed by font pf*/
114static bool text_is_displayable(struct font *pf, unsigned char *src)
115{
116 unsigned short code;
117 const unsigned char *ptr = src;
118 while(*ptr)
119 {
120 ptr = rb->utf8decode(ptr, &code);
121
122 if(!rb->font_get_bits(pf, code))
123 {
124 return false;
125 }
126 }
127 return true;
128}
129
130/* callback for each tag if false returned tag will not be added */
131bool user_check_tag(int index_type, char* build_idx_buf)
132{
133 static struct font *pf = NULL;
134 if (!pf)
135 pf = rb->font_get(FONT_UI);
136
137 if (index_type == tag_artist || index_type == tag_album ||
138 index_type == tag_genre || index_type == tag_title ||
139 index_type == tag_composer || index_type == tag_comment ||
140 index_type == tag_albumartist || index_type == tag_virt_canonicalartist)
141 {
142 /* this could be expanded with more rules / transformations */
143 if (rb->utf8length(build_idx_buf) != strlen(build_idx_buf))
144 {
145 if (!text_is_displayable(pf, build_idx_buf))
146 {
147 logf("Can't display (%d) %s", index_type, build_idx_buf);
148 }
149 }
150 }
151 return true;
152}
153
154/* undef features we don't need */
155#undef HAVE_DIRCACHE
156#undef HAVE_TC_RAMCACHE
157#undef HAVE_EEPROM_SETTINGS
158/* paste the whole tagcache.c file */
159#include "../tagcache.c"
160
161static bool logdump(bool append);
162static unsigned char logbuffer[MAX_LOG_SIZE + 1];
163static int logindex;
164static bool logwrap;
165static bool logenabled = true;
166
167static void check_logindex(void)
168{
169 if(logindex >= MAX_LOG_SIZE)
170 {
171 /* wrap */
172 logdump(true);
173 //logwrap = true;
174 logindex = 0;
175 }
176}
177
178static int log_push(void *userp, int c)
179{
180 (void)userp;
181
182 logbuffer[logindex++] = c;
183 check_logindex();
184
185 return 1;
186}
187
188/* our logf function */
189static void _log(const char *fmt, ...)
190{
191 if (!logenabled)
192 {
193 rb->splash(10, "log not enabled");
194 return;
195 }
196
197
198 #ifdef USB_ENABLE_SERIAL
199 int old_logindex = logindex;
200 #endif
201 va_list ap;
202
203 va_start(ap, fmt);
204
205#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
206 char buf[1024];
207 vsnprintf(buf, sizeof buf, fmt, ap);
208 DEBUGF("%s\n", buf);
209 /* restart va_list otherwise the result if undefined when vuprintf is called */
210 va_end(ap);
211 va_start(ap, fmt);
212#endif
213
214 rb->vuprintf(log_push, NULL, fmt, ap);
215 va_end(ap);
216
217 /* add trailing zero */
218 log_push(NULL, '\0');
219}
220
221
222int compute_nb_lines(int w, struct font* font)
223{
224 int i, nb_lines;
225 int cur_x, delta_x;
226
227 if(logindex>= MAX_LOG_SIZE || (logindex == 0 && !logwrap))
228 return 0;
229
230 if(logwrap)
231 i = logindex;
232 else
233 i = 0;
234
235 cur_x = 0;
236 nb_lines = 0;
237
238 do {
239 if(logbuffer[i] == '\0')
240 {
241 cur_x = 0;
242 nb_lines++;
243 }
244 else
245 {
246 /* does character fit on this line ? */
247 delta_x = rb->font_get_width(font, logbuffer[i]);
248
249 if(cur_x + delta_x > w)
250 {
251 cur_x = 0;
252 nb_lines++;
253 }
254
255 /* update pointer */
256 cur_x += delta_x;
257 }
258
259 i++;
260 if(i >= MAX_LOG_SIZE)
261 i = 0;
262 } while(i != logindex);
263
264 return nb_lines;
265}
266
267static bool logdisplay(void)
268{
269
270 int w, h, i, index;
271 int fontnr;
272 static int delta_y = -1;
273 int cur_x, cur_y, delta_x;
274 struct font* font;
275
276 char buf[2];
277
278 fontnr = FONT_FIRSTUSERFONT;
279 font = rb->font_get(fontnr);
280 buf[1] = '\0';
281 w = LCD_WIDTH;
282 h = LCD_HEIGHT;
283
284 if (delta_y < 0) /* init, get the horizontal size of each line */
285 {
286 rb->font_getstringsize("A", NULL, &delta_y, fontnr);
287 /* start at the end of the log */
288 gThread.user_index = compute_nb_lines(w, font) - h/delta_y -1;
289 /* user_index will be number of the first line to display (warning: line!=log entry) */
290 /* if negative, will be set 0 to zero later */
291 }
292
293
294 rb->lcd_clear_display();
295
296 if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE)
297 gThread.user_index = 0;
298
299
300 if(logwrap)
301 i = logindex;
302 else
303 i = 0;
304
305 index = 0;
306 cur_x = 0;
307 cur_y = 0;
308
309 /* nothing to print ? */
310 if(logindex == 0 && !logwrap)
311 goto end_print;
312
313 do {
314 if(logbuffer[i] == '\0')
315 {
316 /* should be display a newline ? */
317 if(index >= gThread.user_index)
318 cur_y += delta_y;
319 cur_x = 0;
320 index++;
321 }
322 else
323 {
324 /* does character fit on this line ? */
325 delta_x = rb->font_get_width(font, logbuffer[i]);
326
327 if(cur_x + delta_x > w)
328 {
329 /* should be display a newline ? */
330 if(index >= gThread.user_index)
331 cur_y += delta_y;
332 cur_x = 0;
333 index++;
334 }
335
336 /* should we print character ? */
337 if(index >= gThread.user_index)
338 {
339 buf[0] = logbuffer[i];
340 rb->lcd_putsxy(cur_x, cur_y, buf);
341 }
342
343 /* update pointer */
344 cur_x += delta_x;
345 }
346 i++;
347 /* did we fill the screen ? */
348 if(cur_y > h - delta_y)
349 {
350 if (TIME_AFTER(current_tick, gThread.last_useraction_tick + HZ))
351 gThread.user_index++;
352 break;
353 }
354
355 if(i >= MAX_LOG_SIZE)
356 i = 0;
357 } while(i != logindex);
358
359 end_print:
360 rb->lcd_update();
361
362 return false;
363}
364
365static bool logdump(bool append)
366{
367 int fd;
368 int flags = O_CREAT|O_WRONLY|O_TRUNC;
369 /* nothing to print ? */
370 if(!logenabled || (logindex == 0 && !logwrap))
371 {
372 /* nothing is logged just yet */
373 return false;
374 }
375 if (!append)
376 {
377 flags = O_CREAT|O_WRONLY|O_APPEND;
378 }
379
380 fd = open(ROCKBOX_DIR "/db_commit_log.txt", flags, 0666);
381 logenabled = false;
382 if(-1 != fd) {
383 int i;
384
385 if(logwrap)
386 i = logindex;
387 else
388 i = 0;
389
390 do {
391 if(logbuffer[i]=='\0')
392 rb->fdprintf(fd, "\n");
393 else
394 rb->fdprintf(fd, "%c", logbuffer[i]);
395
396 i++;
397 if(i >= MAX_LOG_SIZE)
398 i = 0;
399 } while(i != logindex);
400
401 close(fd);
402 }
403
404 logenabled = true;
405
406 return false;
407}
408
409static void allocate_tempbuf(void)
410{
411 tempbuf_size = 0;
412 tempbuf = rb->plugin_get_audio_buffer(&tempbuf_size);
413 tempbuf_size &= ~0x03;
414
415}
416
417static void free_tempbuf(void)
418{
419 if (tempbuf_size == 0)
420 return ;
421
422 rb->plugin_release_audio_buffer();
423 tempbuf = NULL;
424 tempbuf_size = 0;
425}
426
427static bool do_timed_yield(void)
428{
429 /* Sorting can lock up for quite a while, so yield occasionally */
430 static long wakeup_tick = 0;
431 if (TIME_AFTER(current_tick, wakeup_tick))
432 {
433
434 yield();
435
436 wakeup_tick = current_tick + (HZ/5);
437 return true;
438 }
439 return false;
440}
441
442/*-----------------------------------------------------------------------------*/
443/******* plugin_start ******* */
444/*-----------------------------------------------------------------------------*/
445
446enum plugin_status plugin_start(const void* parameter)
447{
448 (void) parameter;
449
450 /* Turn off backlight timeout */
451 backlight_ignore_timeout();
452
453 memset(&tc_stat, 0, sizeof(struct tagcache_stat));
454 memset(&current_tcmh, 0, sizeof(struct master_header));
455 filenametag_fd = -1;
456
457 strlcpy(tc_stat.db_path, rb->global_settings->tagcache_db_path, sizeof(tc_stat.db_path));
458 if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */
459 strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path));
460 tc_stat.initialized = true;
461
462 memset(&gThread, 0, sizeof(gThread));
463 logf("started");
464 logdump(false);
465
466 thread_create();
467 gThread.user_index = 0;
468 logdisplay(); /* get something on the screen while user waits */
469
470 allocate_tempbuf();
471
472 commit();
473
474 if (tc_stat.ready)
475 rb->tagcache_commit_finalize();
476
477 free_tempbuf();
478
479 logdump(true);
480 gThread.user_index++;
481 logdisplay();
482 rb->thread_wait(gThread.id);
483 rb->queue_delete(&gThread.queue);
484
485 /* Turn on backlight timeout (revert to settings) */
486 backlight_use_settings();
487 return PLUGIN_OK;
488}
489
490/****************** main thread + helper ******************/
491static void thread(void)
492{
493 struct queue_event ev;
494 while (!gThread.exiting)
495 {
496 rb->queue_wait_w_tmo(&gThread.queue, &ev, 1);
497 switch (ev.id)
498 {
499 case SYS_USB_CONNECTED:
500 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
501 logenabled = false;
502 break;
503 case SYS_USB_DISCONNECTED:
504 logenabled = true;
505 /*fall through*/
506 case EV_STARTUP:
507 logf("Thread Started");
508 break;
509 case EV_EXIT:
510 return;
511 default:
512 break;
513 }
514 logdisplay();
515
516 int action = rb->get_action(CONTEXT_STD, HZ/10);
517
518 switch( action )
519 {
520 case ACTION_NONE:
521 break;
522 case ACTION_STD_NEXT:
523 case ACTION_STD_NEXTREPEAT:
524 gThread.last_useraction_tick = current_tick;
525 gThread.user_index++;
526 break;
527 case ACTION_STD_PREV:
528 case ACTION_STD_PREVREPEAT:
529 gThread.last_useraction_tick = current_tick;
530 gThread.user_index--;
531 break;
532 case ACTION_STD_OK:
533 gThread.last_useraction_tick = current_tick;
534 gThread.user_index = 0;
535 break;
536 case SYS_POWEROFF:
537 case ACTION_STD_CANCEL:
538 gThread.exiting = true;
539 return;
540#ifdef HAVE_TOUCHSCREEN
541 case ACTION_TOUCHSCREEN:
542 {
543 gThread.last_useraction_tick = current_tick;
544 short x, y;
545 static int prev_y;
546
547 action = action_get_touchscreen_press(&x, &y);
548
549 if(action & BUTTON_REL)
550 prev_y = 0;
551 else
552 {
553 if(prev_y != 0)
554 gThread.user_index += (prev_y - y) / delta_y;
555
556 prev_y = y;
557 }
558 }
559#endif
560 default:
561 break;
562 }
563
564
565 yield();
566 }
567}
568
569static void thread_create(void)
570{
571 /* put the thread's queue in the bcast list */
572 rb->queue_init(&gThread.queue, true);
573 /*Note: tagcache_stack is defined in apps/tagcache.c */
574 gThread.last_useraction_tick = current_tick;
575 gThread.id = rb->create_thread(thread, tagcache_stack, sizeof(tagcache_stack),
576 0, "db_commit"
577 IF_PRIO(, PRIORITY_USER_INTERFACE)
578 IF_COP(, CPU));
579 rb->queue_post(&gThread.queue, EV_STARTUP, 0);
580 yield();
581}
diff --git a/apps/plugins/tagcache/tagcache.h b/apps/plugins/tagcache/tagcache.h
new file mode 100644
index 0000000000..e416289741
--- /dev/null
+++ b/apps/plugins/tagcache/tagcache.h
@@ -0,0 +1,25 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef _TC_PLUGIN_
22#define _TC_PLUGIN_
23#endif /*_TC_PLUGIN_ */
24
25
diff --git a/apps/plugins/tagcache/tagcache.make b/apps/plugins/tagcache/tagcache.make
new file mode 100644
index 0000000000..5d6d65cb0e
--- /dev/null
+++ b/apps/plugins/tagcache/tagcache.make
@@ -0,0 +1,30 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10TCPLUG_SRCDIR := $(APPSDIR)/plugins/tagcache
11TCPLUG_BUILDDIR := $(BUILDDIR)/apps/plugins/tagcache
12
13ROCKS += $(TCPLUG_BUILDDIR)/db_commit.rock
14
15TCPLUG_FLAGS = $(PLUGINFLAGS) -fno-strict-aliasing -Wno-unused \
16 -I$(TCPLUG_SRCDIR) -ffunction-sections \
17 -fdata-sections -Wl,--gc-sections
18TCPLUG_SRC := $(call preprocess, $(TCPLUG_SRCDIR)/SOURCES)
19TCPLUG_OBJ := $(call c2obj, $(TCPLUG_SRC))
20
21# add source files to OTHER_SRC to get automatic dependencies
22OTHER_SRC += $(APPSDIR)/tagcache.c $(TCPLUG_SRC)
23
24$(TCPLUG_BUILDDIR)/db_commit.rock: $(TCPLUG_OBJ)
25
26# special pattern rule for compiling with extra flags
27$(TCPLUG_BUILDDIR)/%.o: $(TCPLUG_SRCDIR)/%.c $(TCPLUG_SRCDIR)/tagcache.make
28 $(SILENT)mkdir -p $(dir $@)
29 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(TCPLUG_FLAGS) -c $< -o $@
30
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 170a066a36..b0c2eac28f 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -55,6 +55,7 @@
55 * 55 *
56 */ 56 */
57 57
58#if !defined(PLUGIN)
58 59
59/*#define LOGF_ENABLE*/ 60/*#define LOGF_ENABLE*/
60/*#define LOGF_CLAUSES define to enable logf clause matching (LOGF_ENABLE req'd) */ 61/*#define LOGF_CLAUSES define to enable logf clause matching (LOGF_ENABLE req'd) */
@@ -91,7 +92,7 @@
91#include "lang.h" 92#include "lang.h"
92#include "eeprom_settings.h" 93#include "eeprom_settings.h"
93#endif 94#endif
94 95#endif /*!defined(PLUGIN)*/
95/* 96/*
96 * Define this to support non-native endian tagcache files. 97 * Define this to support non-native endian tagcache files.
97 * Databases are always written in native endian so this is 98 * Databases are always written in native endian so this is
@@ -132,6 +133,9 @@
132/* Idle time before committing events in the command queue. */ 133/* Idle time before committing events in the command queue. */
133#define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2 134#define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2
134 135
136/* Dont commit database_tmp data. */
137#define TAGCACHE_FILE_NOCOMMIT "database_commit.ignore"
138
135/* Temporary database containing new tags to be committed to the main db. */ 139/* Temporary database containing new tags to be committed to the main db. */
136#define TAGCACHE_FILE_TEMP "database_tmp.tcd" 140#define TAGCACHE_FILE_TEMP "database_tmp.tcd"
137 141
@@ -730,7 +734,7 @@ static bool update_master_header(void)
730 return true; 734 return true;
731} 735}
732 736
733 737#if !defined(PLUGIN)
734#ifndef __PCTOOL__ 738#ifndef __PCTOOL__
735static bool do_timed_yield(void) 739static bool do_timed_yield(void)
736{ 740{
@@ -2355,6 +2359,8 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
2355 2359
2356 #undef ADD_TAG 2360 #undef ADD_TAG
2357} 2361}
2362#endif /*!defined(PLUGIN)*/
2363
2358 2364
2359static bool tempbuf_insert(char *str, int id, int idx_id, bool unique) 2365static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
2360{ 2366{
@@ -3064,18 +3070,22 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
3064 } 3070 }
3065 str_setlen(build_idx_buf, entry.tag_length[index_type]); 3071 str_setlen(build_idx_buf, entry.tag_length[index_type]);
3066 3072
3067 if (TAGCACHE_IS_UNIQUE(index_type)) 3073#if defined(PLUGIN)
3068 error = !tempbuf_insert(build_idx_buf, i, -1, true); 3074 if (user_check_tag(index_type, build_idx_buf))
3069 else 3075#endif /*defined(PLUGIN)*/
3070 error = !tempbuf_insert(build_idx_buf, i,
3071 tcmh.tch.entry_count + i, false);
3072
3073 if (error)
3074 { 3076 {
3075 logf("insert error"); 3077 if (TAGCACHE_IS_UNIQUE(index_type))
3076 goto error_exit; 3078 error = !tempbuf_insert(build_idx_buf, i, -1, true);
3077 } 3079 else
3080 error = !tempbuf_insert(build_idx_buf, i,
3081 tcmh.tch.entry_count + i, false);
3078 3082
3083 if (error)
3084 {
3085 logf("insert error");
3086 goto error_exit;
3087 }
3088 }
3079 /* Skip to next. */ 3089 /* Skip to next. */
3080 lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] - 3090 lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] -
3081 entry.tag_length[index_type], SEEK_CUR); 3091 entry.tag_length[index_type], SEEK_CUR);
@@ -3299,7 +3309,20 @@ static bool commit(void)
3299 while (write_lock) 3309 while (write_lock)
3300 sleep(1); 3310 sleep(1);
3301 3311
3302 tmpfd = open_db_fd(TAGCACHE_FILE_TEMP, O_RDONLY); 3312#if !defined(PLUGIN)
3313 int fd = open_db_fd(TAGCACHE_FILE_NOCOMMIT, O_RDONLY);
3314 if (fd >= 0)
3315 {
3316 logf("canceling commit");
3317 tc_stat.commit_delayed = true;
3318 close(fd);
3319 tmpfd = -1;
3320 }
3321 else
3322#endif /*!defined(PLUGIN)*/
3323 {
3324 tmpfd = open_db_fd(TAGCACHE_FILE_TEMP, O_RDONLY);
3325 }
3303 if (tmpfd < 0) 3326 if (tmpfd < 0)
3304 { 3327 {
3305 logf("nothing to commit"); 3328 logf("nothing to commit");
@@ -3361,6 +3384,14 @@ static bool commit(void)
3361 } 3384 }
3362#endif /* HAVE_TC_RAMCACHE */ 3385#endif /* HAVE_TC_RAMCACHE */
3363 3386
3387#if defined(PLUGIN)
3388 if (tempbuf_size == 0)
3389 {
3390 tempbuf = rb->plugin_get_audio_buffer(&tempbuf_size);
3391 tempbuf_size &= ~0x03;
3392 }
3393#endif /*defined(PLUGIN)*/
3394
3364 /* And finally fail if there are no buffers available. */ 3395 /* And finally fail if there are no buffers available. */
3365 if (tempbuf_size == 0) 3396 if (tempbuf_size == 0)
3366 { 3397 {
@@ -3433,8 +3464,7 @@ static bool commit(void)
3433 close(masterfd); 3464 close(masterfd);
3434 3465
3435 logf("tagcache committed"); 3466 logf("tagcache committed");
3436 tc_stat.ready = check_all_headers(); 3467 tagcache_commit_finalize();
3437 tc_stat.readyvalid = true;
3438 3468
3439#if defined(HAVE_TC_RAMCACHE) 3469#if defined(HAVE_TC_RAMCACHE)
3440 if (ramcache_buffer_stolen) 3470 if (ramcache_buffer_stolen)
@@ -3476,7 +3506,13 @@ commit_error:
3476 return rc; 3506 return rc;
3477} 3507}
3478 3508
3509void tagcache_commit_finalize(void)
3510{
3511 tc_stat.ready = check_all_headers();
3512 tc_stat.readyvalid = true;
3513}
3479 3514
3515#if !defined(PLUGIN)
3480#ifndef __PCTOOL__ 3516#ifndef __PCTOOL__
3481 3517
3482static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) 3518static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
@@ -5116,8 +5152,7 @@ static void tagcache_thread(void)
5116 if (!tc_stat.ready) 5152 if (!tc_stat.ready)
5117 { 5153 {
5118 sleep(HZ); 5154 sleep(HZ);
5119 tc_stat.ready = check_all_headers(); 5155 tagcache_commit_finalize();
5120 tc_stat.readyvalid = true;
5121 } 5156 }
5122 5157
5123 while (1) 5158 while (1)
@@ -5351,3 +5386,4 @@ int tagcache_get_max_commit_step(void)
5351{ 5386{
5352 return (int)(SORTED_TAGS_COUNT)+1; 5387 return (int)(SORTED_TAGS_COUNT)+1;
5353} 5388}
5389#endif /*!defined(PLUGIN)*/
diff --git a/apps/tagcache.h b/apps/tagcache.h
index 9cf796fafd..a20a13900a 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -204,6 +204,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename);
204#endif 204#endif
205void tagcache_unload_ramcache(void); 205void tagcache_unload_ramcache(void);
206#endif 206#endif
207void tagcache_commit_finalize(void);
207void tagcache_init(void) INIT_ATTR; 208void tagcache_init(void) INIT_ATTR;
208bool tagcache_is_initialized(void); 209bool tagcache_is_initialized(void);
209bool tagcache_is_fully_initialized(void); 210bool tagcache_is_fully_initialized(void);