summaryrefslogtreecommitdiffstats
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/doom/d_deh.c3
-rw-r--r--apps/plugins/lastfm_scrobbler.c350
-rw-r--r--apps/plugins/pictureflow/pictureflow.c47
-rw-r--r--apps/plugins/properties.c3
-rw-r--r--apps/plugins/sliding_puzzle.c4
-rw-r--r--apps/plugins/test_usb.c136
-rw-r--r--apps/plugins/xworld/engine.c2
9 files changed, 344 insertions, 203 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 332dd1bde4..f2ab4843c2 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -178,6 +178,7 @@ test_resize,apps
test_sampr,apps
test_scanrate,apps
test_touchscreen,apps
+test_usb,apps
test_viewports,apps
test_greylib_bitmap_scale,viewers
text_editor,apps
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index c169b61cd1..942f9a5b20 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -226,5 +226,6 @@ test_sampr.c
#ifdef HAVE_TOUCHSCREEN
test_touchscreen.c
#endif
+test_usb.c
test_viewports.c
#endif /* HAVE_TEST_PLUGINS */
diff --git a/apps/plugins/doom/d_deh.c b/apps/plugins/doom/d_deh.c
index 1a399e3b49..0a67aa0aad 100644
--- a/apps/plugins/doom/d_deh.c
+++ b/apps/plugins/doom/d_deh.c
@@ -63,7 +63,7 @@ char* strlwr(char* str)
typedef struct {
const byte *inp; // Pointer to string
size_t size; // Bytes remaining in string
- int fd; // Current file descriptor
+ int fd; // Current file descriptor
} DEHFILE;
// killough 10/98: emulate IO whether input really comes from a file or not
@@ -2868,6 +2868,7 @@ boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, int fpout)
if (*t == '=') break;
buffer[i] = *t; // copy it
}
+ if (i == 0) i = 1; /* Just in case */
buffer[--i] = '\0'; // terminate the key before the '='
if (!*t) // end of string with no equal sign
{
diff --git a/apps/plugins/lastfm_scrobbler.c b/apps/plugins/lastfm_scrobbler.c
index 7bd213b6d2..3269f1820b 100644
--- a/apps/plugins/lastfm_scrobbler.c
+++ b/apps/plugins/lastfm_scrobbler.c
@@ -26,6 +26,7 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
*/
#include "plugin.h"
+#include "lib/configfile.h"
#ifndef UNTAGGED
#define UNTAGGED "<UNTAGGED>"
@@ -39,7 +40,7 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
/****************** constants ******************/
#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF)
-#define EV_OTHINSTANCE MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFE)
+#define EV_FLUSHCACHE MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFE)
#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01)
#define EV_TRACKCHANGE MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02)
#define EV_TRACKFINISH MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x03)
@@ -55,6 +56,9 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
#define ITEM_HDR "#ARTIST #ALBUM #TITLE #TRACKNUM #LENGTH #RATING #TIMESTAMP #MUSICBRAINZ_TRACKID\n"
+#define CFG_FILE "/lastfm_scrobbler.cfg"
+#define CFG_VER 1
+
#if CONFIG_RTC
static time_t timestamp;
#define BASE_FILENAME HOME_DIR "/.scrobbler.log"
@@ -70,125 +74,7 @@ static time_t timestamp;
#define THREAD_STACK_SIZE 4*DEFAULT_STACK_SIZE
-#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
- (CONFIG_KEYPAD == IRIVER_H300_PAD)
-#define SCROBBLE_OFF BUTTON_OFF
-#define SCROBBLE_OFF_TXT "STOP"
-#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
- (CONFIG_KEYPAD == IPOD_3G_PAD) || \
- (CONFIG_KEYPAD == IPOD_1G2G_PAD)
-#define SCROBBLE_OFF BUTTON_MENU
-#define SCROBBLE_OFF_TXT "MENU"
-#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD || \
- CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
- (CONFIG_KEYPAD == SANSA_C200_PAD) || \
- (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
- (CONFIG_KEYPAD == SANSA_M200_PAD)
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
-#define SCROBBLE_OFF BUTTON_HOME
-#define SCROBBLE_OFF_TXT "HOME"
-#elif (CONFIG_KEYPAD == IRIVER_H10_PAD || \
- CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD || \
- CONFIG_KEYPAD == SONY_NWZ_PAD || \
- CONFIG_KEYPAD == XDUOO_X3_PAD || \
- CONFIG_KEYPAD == IHIFI_770_PAD || \
- CONFIG_KEYPAD == IHIFI_800_PAD || \
- CONFIG_KEYPAD == XDUOO_X3II_PAD || \
- CONFIG_KEYPAD == XDUOO_X20_PAD || \
- CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD || \
- CONFIG_KEYPAD == EROSQ_PAD)
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == GIGABEAT_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == GIGABEAT_S_PAD \
- || CONFIG_KEYPAD == SAMSUNG_YPR0_PAD \
- || CONFIG_KEYPAD == CREATIVE_ZEN_PAD
-#define SCROBBLE_OFF BUTTON_BACK
-#define SCROBBLE_OFF_TXT "BACK"
-#elif CONFIG_KEYPAD == MROBE500_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == MROBE100_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
-#define SCROBBLE_OFF BUTTON_REC
-#define BATTERY_RC_OFF BUTTON_RC_REC
-#define SCROBBLE_OFF_TXT "REC"
-#elif CONFIG_KEYPAD == COWON_D2_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
-#define SCROBBLE_OFF BUTTON_BACK
-#define SCROBBLE_OFF_TXT "BACK"
-#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == ONDAVX747_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == ONDAVX777_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \
- (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
-#define SCROBBLE_OFF BUTTON_RIGHT
-#define SCROBBLE_OFF_TXT "RIGHT"
-#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
-#define SCROBBLE_OFF BUTTON_REC
-#define SCROBBLE_OFF_TXT "REC"
-#elif CONFIG_KEYPAD == MPIO_HD200_PAD
-#define SCROBBLE_OFF BUTTON_REC
-#define SCROBBLE_OFF_TXT "REC"
-#elif CONFIG_KEYPAD == MPIO_HD300_PAD
-#define SCROBBLE_OFF BUTTON_REC
-#define SCROBBLE_OFF_TXT "REC"
-#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif (CONFIG_KEYPAD == HM60X_PAD) || (CONFIG_KEYPAD == HM801_PAD)
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "POWER"
-#elif CONFIG_KEYPAD == DX50_PAD
-#define SCROBBLE_OFF BUTTON_POWER_LONG
-#define SCROBBLE_OFF_TXT "Power Long"
-#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "Power"
-#elif CONFIG_KEYPAD == FIIO_M3K_PAD
-#define SCROBBLE_OFF BUTTON_POWER
-#define SCROBBLE_OFF_TXT "Power"
-#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
-/* use touchscreen */
-#else
-#error "No keymap defined!"
-#endif
-#if defined(HAVE_TOUCHSCREEN)
-#ifndef SCROBBLE_OFF
-#define SCROBBLE_OFF BUTTON_TOPLEFT
-#endif
-#ifndef SCROBBLE_OFF_TXT
-#define SCROBBLE_OFF_TXT "TOPLEFT"
-#endif
-#endif
/****************** prototypes ******************/
-int plugin_main(const void* parameter); /* main loop */
enum plugin_status plugin_start(const void* parameter); /* entry */
/****************** globals ******************/
@@ -198,7 +84,8 @@ static struct
{
bool exiting; /* signal to the thread that we want to exit */
unsigned int id; /* worker thread id */
- struct event_queue queue; /* thread event queue */
+ struct event_queue queue; /* thread event queue */
+ struct queue_sender_list queue_send;
long stack[THREAD_STACK_SIZE / sizeof(long)];
} gThread;
@@ -211,6 +98,86 @@ static struct
bool force_flush;
} gCache;
+static struct
+{
+ int savepct;
+ bool playback;
+ bool verbose;
+} gConfig;
+
+static struct configdata config[] =
+{
+ {TYPE_INT, 0, 100, { .int_p = &gConfig.savepct }, "SavePct", NULL},
+ {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.playback }, "Playback", NULL},
+ {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.verbose }, "Verbose", NULL},
+};
+const int gCfg_sz = sizeof(config)/sizeof(*config);
+/****************** config functions *****************/
+static void config_set_defaults(void)
+{
+ gConfig.savepct = 50;
+ gConfig.playback = false;
+ gConfig.verbose = true;
+}
+
+static int config_settings_menu(void)
+{
+ int selection = 0;
+
+ struct viewport parentvp[NB_SCREENS];
+ FOR_NB_SCREENS(l)
+ {
+ rb->viewport_set_defaults(&parentvp[l], l);
+ rb->viewport_set_fullscreen(&parentvp[l], l);
+ }
+
+ MENUITEM_STRINGLIST(settings_menu, ID2P(LANG_SETTINGS), NULL,
+ ID2P(LANG_RESUME_PLAYBACK),
+ "Save Threshold",
+ "Verbose",
+ ID2P(VOICE_BLANK),
+ ID2P(LANG_CANCEL_0),
+ ID2P(LANG_SAVE_EXIT));
+
+ do {
+ selection=rb->do_menu(&settings_menu,&selection, parentvp, true);
+ switch(selection) {
+
+ case 0:
+ rb->set_bool(str(LANG_RESUME_PLAYBACK), &gConfig.playback);
+ break;
+ case 1:
+ rb->set_int("Save Threshold", "%", UNIT_PERCENT,
+ &gConfig.savepct, NULL, 10, 0, 100, NULL );
+ break;
+ case 2:
+ rb->set_bool("Verbose", &gConfig.verbose);
+ break;
+ case 3: /*sep*/
+ continue;
+ case 4:
+ return -1;
+ break;
+ case 5:
+ {
+ int res = configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
+ if (res >= 0)
+ {
+ logf("Scrobbler cfg saved %s %d bytes", CFG_FILE, gCfg_sz);
+ return PLUGIN_OK;
+ }
+ logf("Scrobbler cfg FAILED (%d) %s", res, CFG_FILE);
+ return PLUGIN_ERROR;
+ }
+ case MENU_ATTACHED_USB:
+ return PLUGIN_USB_CONNECTED;
+ default:
+ return PLUGIN_OK;
+ }
+ } while ( selection >= 0 );
+ return 0;
+}
+
/****************** helper fuctions ******************/
int scrobbler_init(void)
@@ -326,6 +293,13 @@ static inline char* str_chk_valid(char *s, char *alt)
return (s != NULL ? s : alt);
}
+static unsigned long scrobbler_get_threshold(unsigned long length)
+{
+ /* length is assumed to be in miliseconds */
+ return length / 100 * gConfig.savepct;
+
+}
+
static void scrobbler_add_to_cache(const struct mp3entry *id)
{
static uint32_t last_crc = 0;
@@ -339,7 +313,7 @@ static void scrobbler_add_to_cache(const struct mp3entry *id)
logf("SCROBBLER: add_to_cache[%d]", gCache.pos);
- if (id->elapsed > id->length / 2)
+ if (id->elapsed >= scrobbler_get_threshold(id->length))
rating = 'L'; /* Listened */
char tracknum[11] = { "" };
@@ -410,9 +384,9 @@ static void scrobbler_change_event(unsigned short id, void *ev_data)
logf("%s", __func__);
struct mp3entry *id3 = ((struct track_event *)ev_data)->id3;
- /* check if track was resumed > %50 played ( likely got saved )
+ /* check if track was resumed > %threshold played ( likely got saved )
check for blank artist or track name */
- if ((id3->elapsed > id3->length / 2)
+ if ((id3->elapsed > scrobbler_get_threshold(id3->length))
|| (!id3->artist && !id3->albumartist) || !id3->title)
{
gCache.pending = false;
@@ -448,25 +422,32 @@ static void scrobbler_finish_event(unsigned short id, void *ev_data)
{
(void)id;
struct track_event *te = ((struct track_event *)ev_data);
- struct mp3entry *id3 = te->id3;
logf("%s %s %s", __func__, gCache.pending?"True":"False", track_event_info(te));
/* add entry using the currently ending track */
if (gCache.pending && (te->flags & TEF_CURRENT) && !(te->flags & TEF_REWIND))
{
gCache.pending = false;
- if (id3->elapsed*2 >= id3->length)
- scrobbler_add_to_cache(te->id3);
- else
- {
- logf("%s Discarding < 50%% played", __func__);
- }
+ scrobbler_add_to_cache(te->id3);
}
}
-/****************** main thread + helper ******************/
+/****************** main thread + helpers ******************/
+static void events_unregister(void)
+{
+ /* we don't want any more events */
+ rb->remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
+ rb->remove_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event);
+}
+
+static void events_register(void)
+{
+ rb->add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
+ rb->add_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event);
+}
+
void thread(void)
{
bool in_usb = false;
@@ -487,6 +468,7 @@ void thread(void)
in_usb = false;
/*fall through*/
case EV_STARTUP:
+ events_register();
rb->beep_play(1500, 100, 1000);
break;
case SYS_POWEROFF:
@@ -500,10 +482,11 @@ void thread(void)
if (!in_usb)
scrobbler_flush_cache();
#endif
+ events_unregister();
return;
- case EV_OTHINSTANCE:
+ case EV_FLUSHCACHE:
scrobbler_flush_cache();
- rb->splashf(HZ * 2, "%s Cache Flushed", str(LANG_AUDIOSCROBBLER));
+ rb->queue_reply(&gThread.queue, 0);
break;
default:
logf("default %ld", ev.id);
@@ -520,6 +503,7 @@ void thread_create(void)
0, "Last.Fm_TSR"
IF_PRIO(, PRIORITY_BACKGROUND)
IF_COP(, CPU));
+ rb->queue_enable_queue_send(&gThread.queue, &gThread.queue_send, gThread.id);
rb->queue_post(&gThread.queue, EV_STARTUP, 0);
rb->yield();
}
@@ -527,79 +511,77 @@ void thread_create(void)
void thread_quit(void)
{
if (!gThread.exiting) {
+ gThread.exiting = true;
rb->queue_post(&gThread.queue, EV_EXIT, 0);
rb->thread_wait(gThread.id);
- /* we don't want any more events */
- rb->remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
- rb->remove_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event);
/* remove the thread's queue from the broadcast list */
rb->queue_delete(&gThread.queue);
- gThread.exiting = true;
}
}
/* callback to end the TSR plugin, called before a new one gets loaded */
static bool exit_tsr(bool reenter)
{
- logf("%s", __func__);
- bool is_exit = false;
- int button;
- if (reenter)
- {
- logf(" reenter other instance ");
- rb->queue_post(&gThread.queue, EV_OTHINSTANCE, 0);
- return false; /* dont let it start again */
- }
- rb->lcd_clear_display();
- rb->lcd_puts_scroll(0, 0, "Scrobbler is currently running.");
- rb->lcd_puts_scroll(0, 1, "Press " SCROBBLE_OFF_TXT " to exit");
- rb->lcd_puts_scroll(0, 2, "Anything else will resume");
-
- rb->lcd_update();
- rb->button_clear_queue();
- while (1)
+ MENUITEM_STRINGLIST(menu, ID2P(LANG_AUDIOSCROBBLER), NULL, ID2P(LANG_SETTINGS),
+ "Flush Cache", "Exit Plugin", ID2P(LANG_BACK));
+
+ const struct text_message quit_prompt = {
+ (const char*[]){ ID2P(LANG_AUDIOSCROBBLER),
+ "is currently running.",
+ "Quit scrobbler?" }, 3
+ };
+
+ while(true)
{
- button = rb->button_get(true);
- if (IS_SYSEVENT(button))
- continue;
- if (button == SCROBBLE_OFF)
+ int result = reenter ? rb->do_menu(&menu, NULL, NULL, false) : 2;
+ switch(result)
{
- rb->queue_post(&gThread.queue, EV_EXIT, 0);
- rb->thread_wait(gThread.id);
- /* remove the thread's queue from the broadcast list */
- rb->queue_delete(&gThread.queue);
- is_exit = true;
- }
- else is_exit = false;
+ case 0: /* settings */
+ config_settings_menu();
+ break;
+ case 1: /* flush cache */
+ rb->queue_send(&gThread.queue, EV_FLUSHCACHE, 0);
+ if (gConfig.verbose)
+ rb->splashf(2*HZ, "%s Cache Flushed", str(LANG_AUDIOSCROBBLER));
+ break;
- break;
- }
- FOR_NB_SCREENS(idx)
- rb->screens[idx]->scroll_stop();
+ case 2: /* exit plugin - quit */
+ if(rb->gui_syncyesno_run(&quit_prompt, NULL, NULL) == YESNO_YES)
+ {
+ thread_quit();
+ if (reenter)
+ rb->plugin_tsr(NULL); /* remove TSR cb */
+ return !reenter;
+ }
- if (is_exit)
- thread_quit();
+ if(!reenter)
+ return false;
- return is_exit;
+ break;
+
+ case 3: /* back to menu */
+ return false;
+ }
+ }
}
/****************** main ******************/
-
-int plugin_main(const void* parameter)
+static int plugin_main(const void* parameter)
{
(void)parameter;
rb->memset(&gThread, 0, sizeof(gThread));
- rb->splashf(HZ / 2, "%s Started",str(LANG_AUDIOSCROBBLER));
+ if (gConfig.verbose)
+ rb->splashf(HZ / 2, "%s Started",str(LANG_AUDIOSCROBBLER));
logf("%s: %s Started", __func__, str(LANG_AUDIOSCROBBLER));
rb->plugin_tsr(exit_tsr); /* stay resident */
- rb->add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
- rb->add_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event);
thread_create();
- return 0;
+ if (gConfig.playback)
+ return PLUGIN_GOTO_WPS;
+ return PLUGIN_OK;
}
/***************** Plugin Entry Point *****************/
@@ -612,6 +594,16 @@ enum plugin_status plugin_start(const void* parameter)
language_strings = rb->language_strings;
if (scrobbler_init() < 0)
return PLUGIN_ERROR;
+
+ if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0)
+ {
+ /* If the loading failed, save a new config file */
+ config_set_defaults();
+ configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
+
+ rb->splash(HZ, ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS));
+ }
+
int ret = plugin_main(parameter);
- return (ret==0) ? PLUGIN_OK : PLUGIN_ERROR;
+ return ret;
}
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index a2782b6a2b..2f075a7e61 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -268,7 +268,6 @@ typedef fb_data pix_t;
/* some magic numbers for cache_version. */
#define CACHE_REBUILD 0
-#define CACHE_UPDATE 1
/* Error return values */
#define SUCCESS 0
@@ -306,6 +305,8 @@ struct pf_config_t
bool resize;
bool show_fps;
+
+ bool update_albumart;
};
struct pf_index_t {
@@ -511,6 +512,7 @@ static struct configdata config[] =
{ TYPE_ENUM, 0, 2, { .int_p = &pf_cfg.year_sort_order }, "year order",
year_sort_order_conf },
{ TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.show_year }, "show year", NULL },
+ { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.update_albumart }, "update albumart", NULL }
};
#define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata))
@@ -667,9 +669,10 @@ static bool confirm_quit(void)
return true;
}
-static void config_save(int cache_version)
+static void config_save(int cache_version, bool update_albumart)
{
pf_cfg.cache_version = cache_version;
+ pf_cfg.update_albumart = update_albumart;
configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
}
@@ -684,12 +687,13 @@ static void config_set_defaults(struct pf_config_t *cfg)
cfg->last_album = 0;
cfg->backlight_mode = 0;
cfg->resize = true;
- cfg->cache_version = 0;
+ cfg->cache_version = CACHE_REBUILD;
cfg->show_album_name = (LCD_HEIGHT > 100)
? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM;
cfg->sort_albums_by = SORT_BY_ARTIST_AND_NAME;
cfg->year_sort_order = ASCENDING;
cfg->show_year = false;
+ cfg->update_albumart = false;
}
static inline PFreal fmul(PFreal a, PFreal b)
@@ -2250,8 +2254,6 @@ static bool incremental_albumart_cache(bool verbose)
unsigned int hash_artist, hash_album;
unsigned int format = FORMAT_NATIVE;
- bool update = (pf_cfg.cache_version == CACHE_UPDATE);
-
if (pf_cfg.resize)
format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT;
@@ -2263,8 +2265,6 @@ static bool incremental_albumart_cache(bool verbose)
aa_cache.inspected++;
if (aa_cache.idx >= pf_idx.album_ct) { aa_cache.idx = 0; } /* Rollover */
- if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file)))
- goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP);
hash_artist = mfnv(get_album_artist(idx));
hash_album = mfnv(get_album_name(idx));
@@ -2272,13 +2272,15 @@ static bool incremental_albumart_cache(bool verbose)
rb->snprintf(aa_cache.pfraw_file, sizeof(aa_cache.pfraw_file),
CACHE_PREFIX "/%x%x.pfraw", hash_album, hash_artist);
- if(rb->file_exists(aa_cache.pfraw_file)) {
- if(update) {
- aa_cache.slides++;
- goto aa_success;
- }
+ if(pf_cfg.update_albumart && rb->file_exists(aa_cache.pfraw_file)) {
+ aa_cache.slides++;
+ goto aa_success;
}
+ if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file)))
+ goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP);
+
+
aa_cache.input_bmp.data = aa_cache.buf;
aa_cache.input_bmp.width = DISPLAY_WIDTH;
aa_cache.input_bmp.height = DISPLAY_HEIGHT;
@@ -3169,14 +3171,14 @@ static inline void set_current_slide(const int slide_index)
{
int old_center_index = center_index;
step = 0;
- center_index = fbound(slide_index, 0, number_of_slides - 1);
+ center_index = fbound(0, slide_index, number_of_slides - 1);
if (old_center_index != center_index)
{
rb->queue_remove_from_head(&thread_q, EV_WAKEUP);
rb->queue_post(&thread_q, EV_WAKEUP, 0);
}
target = center_index;
- slide_frame = slide_index << 16;
+ slide_frame = center_index << 16;
reset_slides();
}
@@ -3609,6 +3611,7 @@ static int settings_menu(void)
break;
/* fallthrough if changed, since cache needs to be rebuilt */
case 10:
+ pf_cfg.update_albumart = false;
pf_cfg.cache_version = CACHE_REBUILD;
rb->remove(EMPTY_SLIDE);
configfile_save(CONFIG_FILE, config,
@@ -3616,7 +3619,8 @@ static int settings_menu(void)
rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART));
break;
case 11:
- pf_cfg.cache_version = CACHE_UPDATE;
+ pf_cfg.update_albumart = true;
+ pf_cfg.cache_version = CACHE_REBUILD;
rb->remove(EMPTY_SLIDE);
configfile_save(CONFIG_FILE, config,
CONFIG_NUM_ITEMS, CONFIG_VERSION);
@@ -4319,13 +4323,13 @@ static int pictureflow_main(const char* selected_file)
pf_idx.buf_sz -= aa_bufsz;
if (!create_empty_slide(pf_cfg.cache_version != CACHE_VERSION)) {
- config_save(CACHE_REBUILD);
+ config_save(CACHE_REBUILD, false);
error_wait("Could not load the empty slide");
return PLUGIN_ERROR;
}
if ((pf_cfg.cache_version != CACHE_VERSION) && !create_albumart_cache()) {
- config_save(CACHE_REBUILD);
+ config_save(CACHE_REBUILD, false);
error_wait("Could not create album art cache");
} else if(aa_cache.inspected < pf_idx.album_ct) {
rb->splash(HZ * 2, "Updating album art cache in background");
@@ -4333,7 +4337,7 @@ static int pictureflow_main(const char* selected_file)
if (pf_cfg.cache_version != CACHE_VERSION)
{
- config_save(CACHE_VERSION);
+ config_save(CACHE_VERSION, pf_cfg.update_albumart);
}
rb->buflib_init(&buf_ctx, (void *)pf_idx.buf, pf_idx.buf_sz);
@@ -4416,7 +4420,12 @@ static int pictureflow_main(const char* selected_file)
break;
case pf_idle:
render_all_slides();
- incremental_albumart_cache(false);
+ if (aa_cache.inspected < pf_idx.album_ct)
+ {
+ buf_ctx_lock();
+ incremental_albumart_cache(false);
+ buf_ctx_unlock();
+ }
break;
}
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index e5f00e307b..c4378a0356 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -313,7 +313,8 @@ enum plugin_status plugin_start(const void* parameter)
int button;
bool quit = false, usb = false;
const char *file = parameter;
- if(!parameter) return PLUGIN_ERROR;
+ if(!parameter || (file[0] != '/')) return PLUGIN_ERROR;
+
#ifdef HAVE_TOUCHSCREEN
rb->touchscreen_set_mode(rb->global_settings->touch_mode);
#endif
diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c
index a34cb77669..af6aa40ea0 100644
--- a/apps/plugins/sliding_puzzle.c
+++ b/apps/plugins/sliding_puzzle.c
@@ -468,8 +468,8 @@ static const char * initial_bmp_path=NULL;
static const char * get_albumart_bmp_path(void)
{
struct mp3entry* track = rb->audio_current_track();
-
- if (!track || !track->path || track->path[0] == '\0')
+ /* Note rb->audio_current_track->path should never be null */
+ if (!track || track->path[0] == '\0')
return NULL;
if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) )
diff --git a/apps/plugins/test_usb.c b/apps/plugins/test_usb.c
new file mode 100644
index 0000000000..6bb77c40be
--- /dev/null
+++ b/apps/plugins/test_usb.c
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#include "plugin.h"
+#include "logf.h"
+
+#undef DEBUGF
+#define DEBUGF(...)
+//#define DEBUGF printf
+
+#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF)
+
+unsigned char stack[DEFAULT_STACK_SIZE];
+struct event_queue queue;
+int thread_id;
+const char* state = "none";
+const char* prev_state = "none";
+
+static void main_loop(void)
+{
+ bool exiting = false;
+ struct queue_event ev;
+
+ while(true) {
+ rb->queue_wait(&queue, &ev);
+
+ /* events that are handled whether exiting or not */
+ switch(ev.id) {
+ case EV_EXIT:
+ return;
+ }
+
+ if(exiting)
+ continue;
+
+ /* events handled only when not exiting */
+ switch(ev.id) {
+ case SYS_USB_CONNECTED:
+ prev_state = state;
+ state = "connected";
+ logf("test_usb: connect ack %ld", *rb->current_tick);
+ DEBUGF("test_usb: connect ack %ld\n", *rb->current_tick);
+ rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
+ break;
+
+ case SYS_USB_DISCONNECTED:
+ prev_state = state;
+ state = "disconnected";
+ logf("test_usb: disconnect %ld", *rb->current_tick);
+ DEBUGF("test_usb: disconnect %ld\n", *rb->current_tick);
+ break;
+
+ case SYS_POWEROFF:
+ case SYS_REBOOT:
+ prev_state = state;
+ state = "exiting";
+ exiting = true;
+ break;
+ }
+ }
+}
+
+static void kill_tsr(void)
+{
+ rb->queue_post(&queue, EV_EXIT, 0);
+ rb->thread_wait(thread_id);
+ rb->queue_delete(&queue);
+}
+
+static bool exit_tsr(bool reenter)
+{
+ MENUITEM_STRINGLIST(menu, "USB test menu", NULL,
+ "Status", "Stop plugin", "Back");
+
+ while(true) {
+ int result = reenter ? rb->do_menu(&menu, NULL, NULL, false) : 1;
+ switch(result) {
+ case 0:
+ rb->splashf(HZ, "State: %s", state);
+ rb->splashf(HZ, "Prev: %s", prev_state);
+ break;
+ case 1:
+ rb->splashf(HZ, "Stopping USB test thread");
+ kill_tsr();
+ return true;
+ case 2:
+ return false;
+ }
+ }
+}
+
+static void run_tsr(void)
+{
+ rb->queue_init(&queue, true);
+ thread_id = rb->create_thread(main_loop, stack, sizeof(stack),
+ 0, "test_usb TSR"
+ IF_PRIO(, PRIORITY_BACKGROUND)
+ IF_COP(, CPU));
+ rb->plugin_tsr(exit_tsr);
+}
+
+enum plugin_status plugin_start(const void* parameter)
+{
+ (void)parameter;
+ MENUITEM_STRINGLIST(menu, "USB test menu", NULL,
+ "Start", "Quit");
+
+ switch(rb->do_menu(&menu, NULL, NULL, false)) {
+ case 0:
+ run_tsr();
+ rb->splashf(HZ, "Thread started");
+ return PLUGIN_OK;
+ case 1:
+ return PLUGIN_OK;
+ default:
+ return PLUGIN_ERROR;
+ }
+}
diff --git a/apps/plugins/xworld/engine.c b/apps/plugins/xworld/engine.c
index b09e320078..d99d9df6c6 100644
--- a/apps/plugins/xworld/engine.c
+++ b/apps/plugins/xworld/engine.c
@@ -293,7 +293,7 @@ void engine_processInput(struct Engine* e) {
e->sys->input.save = false;
}
if (e->sys->input.fastMode) {
- e->vm._fastMode = !&e->vm._fastMode;
+ e->vm._fastMode = !e->vm._fastMode;
e->sys->input.fastMode = false;
}
if (e->sys->input.stateSlot != 0) {