diff options
author | William Wilgus <wilgus.william@gmail.com> | 2023-10-04 08:51:10 -0400 |
---|---|---|
committer | William Wilgus <wilgus.william@gmail.com> | 2023-10-05 21:24:37 -0400 |
commit | 1ed640da24eb97255328c4498035ba524f6265fc (patch) | |
tree | e89771f51a031cc114d36f6dd9c261b04cd4667d | |
parent | 6634a60bf0750159ffc34bdff548fac0817e72bc (diff) | |
download | rockbox-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
-rw-r--r-- | apps/plugin.c | 2 | ||||
-rw-r--r-- | apps/plugin.h | 2 | ||||
-rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
-rw-r--r-- | apps/plugins/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/SUBDIRS | 1 | ||||
-rw-r--r-- | apps/plugins/SUBDIRS.app_build | 1 | ||||
-rw-r--r-- | apps/plugins/tagcache/SOURCES | 2 | ||||
-rw-r--r-- | apps/plugins/tagcache/tagcache.c | 581 | ||||
-rw-r--r-- | apps/plugins/tagcache/tagcache.h | 25 | ||||
-rw-r--r-- | apps/plugins/tagcache/tagcache.make | 30 | ||||
-rw-r--r-- | apps/tagcache.c | 70 | ||||
-rw-r--r-- | apps/tagcache.h | 1 | ||||
-rw-r--r-- | manual/rockbox_interface/tagcache.tex | 9 |
13 files changed, 707 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 | ||
838 | static int plugin_buffer_handle; | 838 | static 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 | |||
22 | codebuster,games | 22 | codebuster,games |
23 | credits,viewers | 23 | credits,viewers |
24 | cube,demos | 24 | cube,demos |
25 | db_commit,apps | ||
25 | db_folder_select,viewers | 26 | db_folder_select,viewers |
26 | demystify,demos | 27 | demystify,demos |
27 | dice,games | 28 | dice,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 |
6 | db_folder_select.c | 6 | db_folder_select.c |
7 | tagcache/tagcache.c | ||
7 | #endif | 8 | #endif |
8 | chessclock.c | 9 | chessclock.c |
9 | credits.c | 10 | credits.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) |
33 | pictureflow | 33 | pictureflow |
34 | tagcache | ||
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 |
19 | pictureflow | 19 | pictureflow |
20 | tagcache | ||
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 @@ | |||
1 | tagcache.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 | |||
29 | static void thread_create(void); | ||
30 | static void thread(void); /* the thread running it all */ | ||
31 | static void allocate_tempbuf(void); | ||
32 | static void free_tempbuf(void); | ||
33 | static bool do_timed_yield(void); | ||
34 | static 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 */ | ||
77 | static 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 */ | ||
90 | int 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 | |||
103 | static 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*/ | ||
114 | static 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 */ | ||
131 | bool 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 | |||
161 | static bool logdump(bool append); | ||
162 | static unsigned char logbuffer[MAX_LOG_SIZE + 1]; | ||
163 | static int logindex; | ||
164 | static bool logwrap; | ||
165 | static bool logenabled = true; | ||
166 | |||
167 | static 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 | |||
178 | static 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 */ | ||
189 | static 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 | |||
222 | int 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 | |||
267 | static 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 | |||
365 | static 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 | |||
409 | static 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 | |||
417 | static 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 | |||
427 | static 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 | |||
446 | enum 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(¤t_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 ******************/ | ||
491 | static 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 | |||
569 | static 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 | |||
10 | TCPLUG_SRCDIR := $(APPSDIR)/plugins/tagcache | ||
11 | TCPLUG_BUILDDIR := $(BUILDDIR)/apps/plugins/tagcache | ||
12 | |||
13 | ROCKS += $(TCPLUG_BUILDDIR)/db_commit.rock | ||
14 | |||
15 | TCPLUG_FLAGS = $(PLUGINFLAGS) -fno-strict-aliasing -Wno-unused \ | ||
16 | -I$(TCPLUG_SRCDIR) -ffunction-sections \ | ||
17 | -fdata-sections -Wl,--gc-sections | ||
18 | TCPLUG_SRC := $(call preprocess, $(TCPLUG_SRCDIR)/SOURCES) | ||
19 | TCPLUG_OBJ := $(call c2obj, $(TCPLUG_SRC)) | ||
20 | |||
21 | # add source files to OTHER_SRC to get automatic dependencies | ||
22 | OTHER_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__ |
735 | static bool do_timed_yield(void) | 739 | static 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 | ||
2359 | static bool tempbuf_insert(char *str, int id, int idx_id, bool unique) | 2365 | static 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 | ||
3509 | void 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 | ||
3482 | static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) | 3518 | static 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 |
205 | void tagcache_unload_ramcache(void); | 205 | void tagcache_unload_ramcache(void); |
206 | #endif | 206 | #endif |
207 | void tagcache_commit_finalize(void); | ||
207 | void tagcache_init(void) INIT_ATTR; | 208 | void tagcache_init(void) INIT_ATTR; |
208 | bool tagcache_is_initialized(void); | 209 | bool tagcache_is_initialized(void); |
209 | bool tagcache_is_fully_initialized(void); | 210 | bool tagcache_is_fully_initialized(void); |
diff --git a/manual/rockbox_interface/tagcache.tex b/manual/rockbox_interface/tagcache.tex index 3fae3c5c04..a0d9834779 100644 --- a/manual/rockbox_interface/tagcache.tex +++ b/manual/rockbox_interface/tagcache.tex | |||
@@ -31,6 +31,15 @@ If a subdirectory of an `ignored' directory should still be scanned, place a | |||
31 | file named \fname{database.unignore} in it. The files in that directory and | 31 | file named \fname{database.unignore} in it. The files in that directory and |
32 | its subdirectories will be scanned and added to the database. | 32 | its subdirectories will be scanned and added to the database. |
33 | 33 | ||
34 | \subsubsection{Issues During Database Commit} | ||
35 | |||
36 | You may have files on your \dap{} whose contents might not be displayed | ||
37 | correctly or even crash the database. | ||
38 | Placing a file named \fname{/.rockbox/database_commit.ignore} | ||
39 | will prevent the device from committing the database automatically | ||
40 | you can manually commit the database using the db_commit plugin in APPS | ||
41 | with logging | ||
42 | |||
34 | \subsection{\label{ref:databasemenu}The Database Menu} | 43 | \subsection{\label{ref:databasemenu}The Database Menu} |
35 | 44 | ||
36 | \begin{description} | 45 | \begin{description} |