From 470989bd708d9a425dbbf2d83b8fcbd0a8d0f488 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 14 Mar 2014 23:15:16 +0100 Subject: [PATCH] events: Rework event subsystem (add_event, send_event) to be more versatile. add_event_ex is added that takes an extra user_data pointer. This pointer is passed to the callback (add_event and add_event_ex have slightly different callbacks types). All callbacks also get the event id passed. Events added with add_event_ex must be removed with remove_event_ex because the user_data pointer must match in addition to the callback pointer. On the other add_event is simplified to omit the oneshort parameter which was almost always false (still there with add_event_ex). As a side effect the ata_idle_notify callbacks are changed as well, they do not take a data parameter anymore which was always NULL anyway. This commit also adds some documentation to events.h Change-Id: I13e29a0f88ef908f175b376d83550f9e0231f772 --- apps/gui/list.c | 13 ++--- apps/gui/statusbar-skinned.c | 3 +- apps/gui/statusbar-skinned.h | 2 +- apps/gui/viewport.c | 17 +++--- apps/gui/wps.c | 52 ++++++++----------- apps/hosted/android/notification.c | 10 ++-- apps/iap/iap-core.c | 5 +- apps/playback.c | 39 ++++++++------ apps/playlist.c | 3 +- apps/plugin.h | 12 ++--- apps/plugins/battery_bench.c | 7 ++- apps/plugins/mpegplayer/mpeg_settings.c | 5 +- apps/plugins/mpegplayer/mpegplayer.c | 5 +- apps/radio/radioart.c | 8 +-- apps/root_menu.c | 5 +- apps/scrobbler.c | 19 +++---- apps/settings.c | 7 +-- apps/shortcuts.c | 5 +- apps/tagcache.c | 6 +-- apps/tagtree.c | 14 ++--- firmware/ata_idle_notify.c | 20 ++++--- firmware/events.c | 61 +++++++++++++++++----- firmware/export/ata_idle_notify.h | 4 +- firmware/export/events.h | 69 ++++++++++++++++++++++--- firmware/logf.c | 5 +- 25 files changed, 247 insertions(+), 149 deletions(-) diff --git a/apps/gui/list.c b/apps/gui/list.c index c393340c57..8663abe8a0 100644 --- a/apps/gui/list.c +++ b/apps/gui/list.c @@ -66,16 +66,17 @@ static bool list_is_dirty(struct gui_synclist *list) return TIME_BEFORE(list->dirty_tick, last_dirty_tick); } -static void list_force_reinit(void *param) +static void list_force_reinit(unsigned short id, void *param, void *last_dirty_tick) { + (void)id; (void)param; - last_dirty_tick = current_tick; + *(int *)last_dirty_tick = current_tick; } void list_init(void) { last_dirty_tick = current_tick; - add_event(GUI_EVENT_THEME_CHANGED, false, list_force_reinit); + add_event_ex(GUI_EVENT_THEME_CHANGED, false, list_force_reinit, &last_dirty_tick); } static void list_init_viewports(struct gui_synclist *list) @@ -611,8 +612,9 @@ bool gui_synclist_keyclick_callback(int action, void* data) */ static struct gui_synclist *current_lists; static bool ui_update_event_registered = false; -static void _lists_uiviewport_update_callback(void *data) +static void _lists_uiviewport_update_callback(unsigned short id, void *data) { + (void)id; (void)data; if (current_lists) gui_synclist_draw(current_lists); @@ -801,8 +803,7 @@ int list_do_action_timeout(struct gui_synclist *lists, int timeout) { if (!ui_update_event_registered) ui_update_event_registered = - add_event(GUI_EVENT_NEED_UI_UPDATE, false, - _lists_uiviewport_update_callback); + add_event(GUI_EVENT_NEED_UI_UPDATE, _lists_uiviewport_update_callback); current_lists = lists; } if(lists->scheduled_talk_tick) diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c index c991d8ea40..c4cc37d539 100644 --- a/apps/gui/statusbar-skinned.c +++ b/apps/gui/statusbar-skinned.c @@ -178,8 +178,9 @@ void sb_skin_update(enum screen_type screen, bool force) } } -void do_sbs_update_callback(void *param) +void do_sbs_update_callback(unsigned short id, void *param) { + (void)id; (void)param; /* the WPS handles changing the actual id3 data in the id3 pointers * we imported, we just want a full update */ diff --git a/apps/gui/statusbar-skinned.h b/apps/gui/statusbar-skinned.h index ac12dfa1aa..237ec45c82 100644 --- a/apps/gui/statusbar-skinned.h +++ b/apps/gui/statusbar-skinned.h @@ -66,5 +66,5 @@ int sb_postproccess(enum screen_type screen, struct wps_data *data); #define sb_preproccess NULL #define sb_postproccess NULL #endif -void do_sbs_update_callback(void *param); +void do_sbs_update_callback(unsigned short id, void *param); #endif /* __STATUSBAR_SKINNED_H__ */ diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c index aeb884a95d..194954c1d2 100644 --- a/apps/gui/viewport.c +++ b/apps/gui/viewport.c @@ -69,7 +69,7 @@ struct viewport_stack_item }; #ifdef HAVE_LCD_BITMAP -static void viewportmanager_redraw(void* data); +static void viewportmanager_redraw(unsigned short id, void* data); static int theme_stack_top[NB_SCREENS]; /* the last item added */ static struct viewport_stack_item theme_stack[NB_SCREENS][VPSTACK_DEPTH]; @@ -80,14 +80,12 @@ static void toggle_events(bool enable) { if (enable) { - add_event(GUI_EVENT_ACTIONUPDATE, false, viewportmanager_redraw); + add_event(GUI_EVENT_ACTIONUPDATE, viewportmanager_redraw); #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - add_event(LCD_EVENT_ACTIVATION, false, do_sbs_update_callback); + add_event(LCD_EVENT_ACTIVATION, do_sbs_update_callback); #endif - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, - do_sbs_update_callback); - add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, - do_sbs_update_callback); + add_event(PLAYBACK_EVENT_TRACK_CHANGE, do_sbs_update_callback); + add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, do_sbs_update_callback); } else { @@ -232,8 +230,9 @@ int viewport_get_nb_lines(const struct viewport *vp) #endif } -static void viewportmanager_redraw(void* data) +static void viewportmanager_redraw(unsigned short id, void* data) { + (void)id; FOR_NB_SCREENS(i) { #ifdef HAVE_LCD_BITMAP @@ -256,7 +255,7 @@ void viewportmanager_init() viewportmanager_theme_enable(i, true, NULL); } #else - add_event(GUI_EVENT_ACTIONUPDATE, false, viewportmanager_redraw); + add_event(GUI_EVENT_ACTIONUPDATE, viewportmanager_redraw); #endif } diff --git a/apps/gui/wps.c b/apps/gui/wps.c index b4c3f40e9f..d1161ea71d 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -74,8 +74,7 @@ /* initial setup of wps_data */ static void wps_state_init(void); -static void track_changed_callback(void *param); -static void nextid3available_callback(void* param); +static void track_info_callback(unsigned short id, void *param); #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps" #ifdef HAVE_REMOTE_LCD @@ -626,8 +625,9 @@ static void play_hop(int direction) * we suppress updates until the wps is activated again (the lcd driver will * call this hook to issue an instant update) * */ -static void wps_lcd_activation_hook(void *param) +static void wps_lcd_activation_hook(unsigned short id, void *param) { + (void)id; (void)param; skin_request_full_update(WPS); /* force timeout in wps main loop, so that the update is instantly */ @@ -1119,7 +1119,7 @@ long gui_wps_show(void) restore = false; restoretimer = RESTORE_WPS_INSTANTLY; #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - add_event(LCD_EVENT_ACTIVATION, false, wps_lcd_activation_hook); + add_event(LCD_EVENT_ACTIVATION, wps_lcd_activation_hook); #endif /* we remove the update delay since it's not very usable in the wps, * e.g. during volume changing or ffwd/rewind */ @@ -1187,36 +1187,28 @@ long gui_wps_show(void) } /* this is called from the playback thread so NO DRAWING! */ -static void track_changed_callback(void *param) +static void track_info_callback(unsigned short id, void *param) { struct wps_state *state = skin_get_global_state(); - state->id3 = ((struct track_event *)param)->id3; - state->nid3 = audio_next_track(); - if (state->id3->cuesheet) + + if (id == PLAYBACK_EVENT_TRACK_CHANGE || id == PLAYBACK_EVENT_CUR_TRACK_READY) { - cue_find_current_track(state->id3->cuesheet, state->id3->elapsed); + state->id3 = ((struct track_event *)param)->id3; + if (state->id3->cuesheet) + { + cue_find_current_track(state->id3->cuesheet, state->id3->elapsed); + } } - skin_request_full_update(WPS); -} -static void nextid3available_callback(void* param) -{ - (void)param; +#ifdef AUDIO_FAST_SKIP_PREVIEW + else if (id == PLAYBACK_EVENT_TRACK_SKIP) + { + state->id3 = audio_current_track(); + } +#endif skin_get_global_state()->nid3 = audio_next_track(); skin_request_full_update(WPS); } -#ifdef AUDIO_FAST_SKIP_PREVIEW -/* this is called on the audio_skip caller thread */ -static void track_skip_callback(void *param) -{ - struct wps_state *state = skin_get_global_state(); - state->id3 = audio_current_track(); - state->nid3 = audio_next_track(); - skin_request_full_update(WPS); - (void)param; -} -#endif /* AUDIO_FAST_SKIP_PREVIEW */ - static void wps_state_init(void) { struct wps_state *state = skin_get_global_state(); @@ -1235,15 +1227,15 @@ static void wps_state_init(void) /* We'll be updating due to restore initialized with true */ skin_request_full_update(WPS); /* add the WPS track event callbacks */ - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback); - add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback); + add_event(PLAYBACK_EVENT_TRACK_CHANGE, track_info_callback); + add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, track_info_callback); #if CONFIG_CODEC == SWCODEC /* Use the same callback as ..._TRACK_CHANGE for when remaining handles have finished */ - add_event(PLAYBACK_EVENT_CUR_TRACK_READY, false, track_changed_callback); + add_event(PLAYBACK_EVENT_CUR_TRACK_READY, track_info_callback); #endif #ifdef AUDIO_FAST_SKIP_PREVIEW - add_event(PLAYBACK_EVENT_TRACK_SKIP, false, track_skip_callback); + add_event(PLAYBACK_EVENT_TRACK_SKIP, track_info_callback); #endif } diff --git a/apps/hosted/android/notification.c b/apps/hosted/android/notification.c index 874cd3bcef..66715d26f9 100644 --- a/apps/hosted/android/notification.c +++ b/apps/hosted/android/notification.c @@ -44,8 +44,9 @@ static const struct dim dim = { .width = 200, .height = 200 }; /* * notify about track change, and show track info */ -static void track_changed_callback(void *param) +static void track_changed_callback(unsigned short id, void *param) { + (void)id; struct mp3entry* id3 = ((struct track_event *)param)->id3; JNIEnv e = *env_ptr; if (id3) @@ -106,8 +107,9 @@ static void track_changed_callback(void *param) /* * notify about track finishing */ -static void track_finished_callback(void *param) +static void track_finished_callback(unsigned short id, void *param) { + (void)id; if (((struct track_event *)param)->flags & TEF_REWIND) return; /* Not a true track end */ @@ -144,6 +146,6 @@ void notification_init(void) finishNotification = e->GetMethodID(env_ptr, class, "finishNotification", "()V"); - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback); - add_event(PLAYBACK_EVENT_TRACK_FINISH, false, track_finished_callback); + add_event(PLAYBACK_EVENT_TRACK_CHANGE track_changed_callback); + add_event(PLAYBACK_EVENT_TRACK_FINISH track_finished_callback); } diff --git a/apps/iap/iap-core.c b/apps/iap/iap-core.c index 7226a908c5..4fa9c09a47 100644 --- a/apps/iap/iap-core.c +++ b/apps/iap/iap-core.c @@ -349,8 +349,9 @@ static void iap_thread(void) } /* called by playback when the next track starts */ -static void iap_track_changed(void *ignored) +static void iap_track_changed(unsigned short id, void *ignored) { + (void)id; (void)ignored; if ((interface_state == IST_EXTENDED) && device.do_notify) { long playlist_pos = playlist_next(0); @@ -401,7 +402,7 @@ static void iap_start(void) if (!tid) panicf("Could not create iap thread"); timeout_register(&iap_task_tmo, iap_task, MS_TO_TICKS(100), (intptr_t)NULL); - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed); + add_event(PLAYBACK_EVENT_TRACK_CHANGE, iap_track_changed); /* Since we cannot allocate memory while in interrupt context * post a message to our own queue to get that done diff --git a/apps/playback.c b/apps/playback.c index 80a0585b17..eba90f9a0a 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -334,17 +334,18 @@ enum audio_start_playback_flags static void audio_start_playback(const struct audio_resume_info *resume_info, unsigned int flags); static void audio_stop_playback(void); -static void buffer_event_buffer_low_callback(void *data); -static void buffer_event_rebuffer_callback(void *data); -static void buffer_event_finished_callback(void *data); +static void buffer_event_buffer_low_callback(unsigned short id, void *data, void *user_data); +static void buffer_event_rebuffer_callback(unsigned short id, void *data); +static void buffer_event_finished_callback(unsigned short id, void *data); void audio_pcmbuf_sync_position(void); /**************************************/ /** --- voice event --- **/ -void playback_voice_event(void *data) +void playback_voice_event(unsigned short id, void *data) { + (void)id; /* Make audio play softly while voice is speaking */ pcmbuf_soft_mode(*(bool *)data); } @@ -1757,7 +1758,7 @@ static int audio_load_track(void) should have been cleared already */ logf("%s(): finishing load: %d", __func__, info->id3_hid); filling = STATE_FILLING; - buffer_event_finished_callback(&info->id3_hid); + buffer_event_finished_callback(BUFFER_EVENT_FINISHED, &info->id3_hid); return LOAD_TRACK_OK; } } @@ -2585,8 +2586,8 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, /* Add these now - finish event for the first id3 will most likely be sent immediately */ - add_event(BUFFER_EVENT_REBUFFER, false, buffer_event_rebuffer_callback); - add_event(BUFFER_EVENT_FINISHED, false, buffer_event_finished_callback); + add_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback); + add_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback); if (old_status == PLAY_STOPPED) { @@ -2647,7 +2648,7 @@ static void audio_stop_playback(void) /* Close all tracks and mark them NULL */ remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback); remove_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback); - remove_event(BUFFER_EVENT_BUFFER_LOW, buffer_event_buffer_low_callback); + remove_event_ex(BUFFER_EVENT_BUFFER_LOW, buffer_event_buffer_low_callback, NULL); track_list_clear(TRACK_LIST_CLEAR_ALL); @@ -3164,8 +3165,8 @@ void audio_playback_handler(struct queue_event *ev) /* End of buffering for now, let's calculate the watermark, register for a low buffer event and unboost */ audio_update_filebuf_watermark(0); - add_event(BUFFER_EVENT_BUFFER_LOW, true, - buffer_event_buffer_low_callback); + add_event_ex(BUFFER_EVENT_BUFFER_LOW, true, + buffer_event_buffer_low_callback, NULL); } /* Fall-through */ case STATE_FINISHED: @@ -3200,27 +3201,31 @@ void audio_playback_handler(struct queue_event *ev) /* --- Buffering callbacks --- */ /* Called when fullness is below the watermark level */ -static void buffer_event_buffer_low_callback(void *data) +static void buffer_event_buffer_low_callback(unsigned short id, void *ev_data, void *user_data) { logf("low buffer callback"); LOGFQUEUE("buffering > audio Q_AUDIO_BUFFERING: buffer low"); audio_queue_post(Q_AUDIO_BUFFERING, BUFFER_EVENT_BUFFER_LOW); - (void)data; + (void)id; + (void)ev_data; + (void)user_data; } /* Called when handles must be discarded in order to buffer new data */ -static void buffer_event_rebuffer_callback(void *data) +static void buffer_event_rebuffer_callback(unsigned short id, void *ev_data) { logf("rebuffer callback"); LOGFQUEUE("buffering > audio Q_AUDIO_BUFFERING: rebuffer"); audio_queue_post(Q_AUDIO_BUFFERING, BUFFER_EVENT_REBUFFER); - (void)data; + (void)id; + (void)ev_data; } /* A handle has completed buffering and all required data is available */ -static void buffer_event_finished_callback(void *data) +static void buffer_event_finished_callback(unsigned short id, void *ev_data) { - int hid = *(const int *)data; + (void)id; + int hid = *(const int *)ev_data; const enum data_type htype = buf_handle_data_type(hid); logf("handle %d finished buffering (type:%u)", hid, (unsigned)htype); @@ -3717,7 +3722,7 @@ void INIT_ATTR playback_init(void) track_list_init(); buffering_init(); pcmbuf_update_frequency(); - add_event(PLAYBACK_EVENT_VOICE_PLAYING, false, playback_voice_event); + add_event(PLAYBACK_EVENT_VOICE_PLAYING, playback_voice_event); #ifdef HAVE_CROSSFADE /* Set crossfade setting for next buffer init which should be about... */ pcmbuf_request_crossfade_enable(global_settings.crossfade); diff --git a/apps/playlist.c b/apps/playlist.c index 0e73781238..a066dd2ea0 100755 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -1223,9 +1223,8 @@ static int compare(const void* p1, const void* p2) * without affecting playlist load up performance. This thread also flushes * any pending control commands when the disk spins up. */ -static void playlist_flush_callback(void *param) +static void playlist_flush_callback(void) { - (void)param; struct playlist_info *playlist; playlist = ¤t_playlist; if (playlist->control_fd >= 0) diff --git a/apps/plugin.h b/apps/plugin.h index ffdfa8fb77..874f6e0069 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -160,12 +160,12 @@ void* plugin_get_buffer(size_t *buffer_size); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 227 +#define PLUGIN_API_VERSION 228 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define PLUGIN_MIN_API_VERSION 227 +#define PLUGIN_MIN_API_VERSION 228 /* plugin return codes */ /* internal returns start at 0x100 to make exit(1..255) work */ @@ -450,8 +450,8 @@ struct plugin_api { void (*storage_spin)(void); void (*storage_spindown)(int seconds); #if USING_STORAGE_CALLBACK - void (*register_storage_idle_func)(void (*function)(void *data)); - void (*unregister_storage_idle_func)(void (*function)(void *data), bool run); + void (*register_storage_idle_func)(void (*function)(void)); + void (*unregister_storage_idle_func)(void (*function)(void), bool run); #endif /* USING_STORAGE_CALLBACK */ void (*reload_directory)(void); char *(*create_numbered_filename)(char *buffer, const char *path, @@ -569,8 +569,8 @@ struct plugin_api { void (*profile_func_exit)(void *this_fn, void *call_site); #endif /* event api */ - bool (*add_event)(unsigned short id, bool oneshot, void (*handler)(void *data)); - void (*remove_event)(unsigned short id, void (*handler)(void *data)); + bool (*add_event)(unsigned short id, void (*handler)(unsigned short id, void *data)); + void (*remove_event)(unsigned short id, void (*handler)(unsigned short id, void *data)); void (*send_event)(unsigned short id, void *data); #if (CONFIG_PLATFORM & PLATFORM_HOSTED) diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c index 93876d0807..174a589d8f 100644 --- a/apps/plugins/battery_bench.c +++ b/apps/plugins/battery_bench.c @@ -359,9 +359,8 @@ static unsigned int charge_state(void) #endif -static void flush_buffer(void* data) +static void flush_buffer(void) { - (void)data; int fd; unsigned int i; @@ -445,7 +444,7 @@ static void thread(void) for this to occur because it requires > 16 hours of no disk activity. */ if (buf_idx == BUF_ELEMENTS) { - flush_buffer(NULL); + flush_buffer(); } /* sleep some time until next measurement */ @@ -479,7 +478,7 @@ static void thread(void) /* unregister flush callback and flush to disk */ rb->unregister_storage_idle_func(flush_buffer, true); #else - flush_buffer(NULL); + flush_buffer(); #endif /* log end of bench and exit reason */ diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index bcef4c66bf..b5c9c6bbc8 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -677,8 +677,9 @@ static uint32_t increment_time(uint32_t val, int32_t amount, uint32_t range) } #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) -static void get_start_time_lcd_enable_hook(void *param) +static void get_start_time_lcd_enable_hook(unsigned short id, void *param) { + (void)id; (void)param; rb->queue_post(rb->button_queue, LCD_ENABLE_EVENT_0, 0); } @@ -698,7 +699,7 @@ static int get_start_time(uint32_t duration) mylcd_update(); #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - rb->add_event(LCD_EVENT_ACTIVATION, false, get_start_time_lcd_enable_hook); + rb->add_event(LCD_EVENT_ACTIVATION, get_start_time_lcd_enable_hook); #endif draw_slider(0, 100, &rc_bound); diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 928c48ab11..467c961912 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -1026,8 +1026,9 @@ static void fps_init(void) #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) /* So we can refresh the overlay */ -static void osd_lcd_enable_hook(void* param) +static void osd_lcd_enable_hook(unsigned short id, void* param) { + (void)id; (void)param; rb->queue_post(rb->button_queue, LCD_ENABLE_EVENT_1, 0); } @@ -1043,7 +1044,7 @@ static void osd_backlight_on_video_mode(bool video_on) #endif } else { #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - rb->add_event(LCD_EVENT_ACTIVATION, false, osd_lcd_enable_hook); + rb->add_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); #endif /* Revert to user's backlight settings */ backlight_use_settings(); diff --git a/apps/radio/radioart.c b/apps/radio/radioart.c index 86a987c14f..283815167a 100644 --- a/apps/radio/radioart.c +++ b/apps/radio/radioart.c @@ -145,7 +145,7 @@ int radio_get_art_hid(struct dim *requested_dim) return -1; } -static void buffer_reset_handler(void *data) +static void buffer_reset_handler(unsigned short id, void *data, void *user_data) { buf = NULL; for(int i=0;iid3; strlcpy(current_track_path, id3->path, MAX_PATH); } @@ -746,7 +747,7 @@ void root_menu(void) if (global_settings.start_in_screen == 0) next_screen = (int)global_status.last_screen; else next_screen = global_settings.start_in_screen - 2; - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, rootmenu_track_changed_callback); + add_event(PLAYBACK_EVENT_TRACK_CHANGE, rootmenu_track_changed_callback); #ifdef HAVE_RTC_ALARM if ( rtc_check_alarm_started(true) ) { diff --git a/apps/scrobbler.c b/apps/scrobbler.c index efd028327c..b8a95f85cb 100644 --- a/apps/scrobbler.c +++ b/apps/scrobbler.c @@ -150,9 +150,8 @@ static void write_cache(void) cache_pos = 0; } -static void scrobbler_flush_callback(void *data) +static void scrobbler_flush_callback(void) { - (void)data; if (scrobbler_initialised && cache_pos) write_cache(); } @@ -200,16 +199,17 @@ static void add_to_cache(const struct mp3entry *id) } -static void scrobbler_change_event(void *data) +static void scrobbler_change_event(unsigned short id, void *ev_data) { - struct mp3entry *id = ((struct track_event *)data)->id3; + (void)id; + struct mp3entry *id3 = ((struct track_event *)ev_data)->id3; /* check if track was resumed > %50 played check for blank artist or track name */ - if (id->elapsed > id->length / 2 || !id->artist || !id->title) + if (id3->elapsed > id3->length / 2 || !id3->artist || !id3->title) { pending = false; - logf("SCROBBLER: skipping file %s", id->path); + logf("SCROBBLER: skipping file %s", id3->path); } else { @@ -219,8 +219,9 @@ static void scrobbler_change_event(void *data) } } -static void scrobbler_finish_event(void *data) +static void scrobbler_finish_event(unsigned short id, void *data) { + (void)id; struct track_event *te = (struct track_event *)data; /* add entry using the currently ending track */ @@ -254,8 +255,8 @@ int scrobbler_init(void) scrobbler_initialised = true; - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event); - add_event(PLAYBACK_EVENT_TRACK_FINISH, false, scrobbler_finish_event); + add_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event); + add_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event); return 1; } diff --git a/apps/settings.c b/apps/settings.c index 58d58788be..f2a923e24d 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -591,15 +591,13 @@ static bool settings_write_config(const char* filename, int options) return true; } #ifndef HAVE_RTC_RAM -static void flush_global_status_callback(void *data) +static void flush_global_status_callback(void) { - (void)data; write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE); } #endif -static void flush_config_block_callback(void *data) +static void flush_config_block_callback(void) { - (void)data; write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE); settings_write_config(CONFIGFILE, SETTINGS_SAVE_CHANGED); } @@ -1307,4 +1305,3 @@ void set_file(const char* filename, char* setting, const int maxlen) strlcpy(setting, fptr, len); settings_save(); } - diff --git a/apps/shortcuts.c b/apps/shortcuts.c index ee8454485d..a9ae8248f1 100644 --- a/apps/shortcuts.c +++ b/apps/shortcuts.c @@ -184,9 +184,8 @@ static void init_shortcut(struct shortcut* sc) static int first_idx_to_writeback = -1; static bool overwrite_shortcuts = false; -static void shortcuts_ata_idle_callback(void* data) +static void shortcuts_ata_idle_callback(void) { - (void)data; int fd; char buf[MAX_PATH]; int current_idx = first_idx_to_writeback; @@ -387,7 +386,7 @@ static int shortcut_menu_get_action(int action, struct gui_synclist *lists) gui_synclist_select_item(lists, shortcut_count - 1); first_idx_to_writeback = 0; overwrite_shortcuts = true; - shortcuts_ata_idle_callback(NULL); + shortcuts_ata_idle_callback(); if (shortcut_count == 0) return ACTION_STD_CANCEL; return ACTION_REDRAW; diff --git a/apps/tagcache.c b/apps/tagcache.c index 3ce0247188..b7d5516e81 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -3195,9 +3195,8 @@ static bool command_queue_is_full(void) return (next == command_queue_ridx); } -static void command_queue_sync_callback(void *data) +static void command_queue_sync_callback(void) { - (void)data; struct master_header myhdr; int masterfd; @@ -3246,7 +3245,7 @@ static void run_command_queue(bool force) return; if (force || command_queue_is_full()) - command_queue_sync_callback(NULL); + command_queue_sync_callback(); else register_storage_idle_func(command_queue_sync_callback); } @@ -4898,4 +4897,3 @@ int tagcache_get_max_commit_step(void) { return (int)(SORTED_TAGS_COUNT)+1; } - diff --git a/apps/tagtree.c b/apps/tagtree.c index ff364ec5e4..b3b94a489e 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -804,10 +804,11 @@ static int nat_compare(const void *p1, const void *p2) return strnatcasecmp(e1->name, e2->name); } -static void tagtree_buffer_event(void *data) +static void tagtree_buffer_event(unsigned short id, void *ev_data) { + (void)id; struct tagcache_search tcs; - struct mp3entry *id3 = ((struct track_event *)data)->id3; + struct mp3entry *id3 = ((struct track_event *)ev_data)->id3; bool runtimedb = global_settings.runtimedb; bool autoresume = global_settings.autoresume_enable; @@ -868,9 +869,10 @@ static void tagtree_buffer_event(void *data) tagcache_search_finish(&tcs); } -static void tagtree_track_finish_event(void *data) +static void tagtree_track_finish_event(unsigned short id, void *ev_data) { - struct track_event *te = (struct track_event *)data; + (void)id; + struct track_event *te = (struct track_event *)ev_data; struct mp3entry *id3 = te->id3; long tagcache_idx = id3->tagcache_idx; @@ -1183,8 +1185,8 @@ void tagtree_init(void) if (rootmenu < 0) rootmenu = 0; - add_event(PLAYBACK_EVENT_TRACK_BUFFER, false, tagtree_buffer_event); - add_event(PLAYBACK_EVENT_TRACK_FINISH, false, tagtree_track_finish_event); + add_event(PLAYBACK_EVENT_TRACK_BUFFER, tagtree_buffer_event); + add_event(PLAYBACK_EVENT_TRACK_FINISH, tagtree_track_finish_event); core_shrink(tagtree_handle, core_get_data(tagtree_handle), tagtree_buf_used); } diff --git a/firmware/ata_idle_notify.c b/firmware/ata_idle_notify.c index 35d192bee0..ee9f3c035f 100644 --- a/firmware/ata_idle_notify.c +++ b/firmware/ata_idle_notify.c @@ -25,12 +25,20 @@ #include "kernel.h" #include "string.h" -void register_storage_idle_func(void (*function)(void *data)) +static void wrapper(unsigned short id, void *ev_data, void *user_data) +{ + (void)id; + (void)ev_data; + void (*func)(void) = user_data; + func(); +} + +void register_storage_idle_func(void (*function)(void)) { #if USING_STORAGE_CALLBACK - add_event(DISK_EVENT_SPINUP, true, function); + add_event_ex(DISK_EVENT_SPINUP, true, wrapper, function); #else - function(NULL); /* just call the function now */ + function(); /* just call the function now */ /* this _may_ cause problems later if the calling function sets a variable expecting the callback to unset it, because the callback will be run before this function exits, so before the var is set */ @@ -38,12 +46,12 @@ void register_storage_idle_func(void (*function)(void *data)) } #if USING_STORAGE_CALLBACK -void unregister_storage_idle_func(void (*func)(void *data), bool run) +void unregister_storage_idle_func(void (*func)(void), bool run) { - remove_event(DISK_EVENT_SPINUP, func); + remove_event_ex(DISK_EVENT_SPINUP, wrapper, func); if (run) - func(NULL); + func(); } bool call_storage_idle_notifys(bool force) diff --git a/firmware/events.c b/firmware/events.c index 74172e1fa0..4a51e7ae87 100644 --- a/firmware/events.c +++ b/firmware/events.c @@ -28,30 +28,41 @@ struct sysevent { unsigned short id; bool oneshot; - void (*callback)(void *data); + bool has_user_data; + union { + void (*callback)(unsigned short id, void *event_data); + struct { + void (*callback2)(unsigned short id, void *event_data, void *user_data); + void *user_data; + }; + } handler; }; static struct sysevent events[MAX_SYS_EVENTS]; -bool add_event(unsigned short id, bool oneshot, void (*handler)(void *data)) +static bool do_add_event(unsigned short id, bool oneshot, bool user_data_valid, + void *handler, void *user_data) { int i; /* Check if the event already exists. */ for (i = 0; i < MAX_SYS_EVENTS; i++) { - if (events[i].callback == handler && events[i].id == id) + if (events[i].handler.callback == handler && events[i].id == id + && (!user_data_valid || (user_data == events[i].handler.callback))) return false; } /* Try to find a free slot. */ for (i = 0; i < MAX_SYS_EVENTS; i++) { - if (events[i].callback == NULL) + if (events[i].handler.callback == NULL) { events[i].id = id; events[i].oneshot = oneshot; - events[i].callback = handler; + if ((events[i].has_user_data = user_data_valid)) + events[i].handler.user_data = user_data; + events[i].handler.callback = handler; return true; } } @@ -60,33 +71,59 @@ bool add_event(unsigned short id, bool oneshot, void (*handler)(void *data)) return false; } -void remove_event(unsigned short id, void (*handler)(void *data)) +bool add_event(unsigned short id, void (*handler)(unsigned short id, void *data)) +{ + return do_add_event(id, false, false, handler, NULL); +} + +bool add_event_ex(unsigned short id, bool oneshot, void (*handler)(unsigned short id, void *event_data, void *user_data), void *user_data) +{ + return do_add_event(id, oneshot, true, handler, user_data); +} + +void do_remove_event(unsigned short id, bool user_data_valid, + void *handler, void *user_data) { int i; for (i = 0; i < MAX_SYS_EVENTS; i++) { - if (events[i].id == id && events[i].callback == handler) + if (events[i].id == id && events[i].handler.callback == handler + && (!user_data_valid || (user_data == events[i].handler.callback))) { - events[i].callback = NULL; + events[i].handler.callback = NULL; return; } } } +void remove_event(unsigned short id, void (*handler)(unsigned short id, void *data)) +{ + do_remove_event(id, false, handler, NULL); +} + +void remove_event_ex(unsigned short id, + void (*handler)(unsigned short id, void *event_data, void *user_data), + void *user_data) +{ + do_remove_event(id, true, handler, user_data); +} + void send_event(unsigned short id, void *data) { int i; for (i = 0; i < MAX_SYS_EVENTS; i++) { - if (events[i].id == id && events[i].callback != NULL) + if (events[i].id == id && events[i].handler.callback != NULL) { - events[i].callback(data); + if (events[i].has_user_data) + events[i].handler.callback2(id, data, events[i].handler.user_data); + else + events[i].handler.callback(id, data); if (events[i].oneshot) - events[i].callback = NULL; + events[i].handler.callback = NULL; } } } - diff --git a/firmware/export/ata_idle_notify.h b/firmware/export/ata_idle_notify.h index 93a53eee34..0443f8e516 100644 --- a/firmware/export/ata_idle_notify.h +++ b/firmware/export/ata_idle_notify.h @@ -48,9 +48,9 @@ enum { */ #define USING_STORAGE_CALLBACK !defined(BOOTLOADER) && !defined(APPLICATION) && !defined(__PCTOOL__) -extern void register_storage_idle_func(void (*function)(void *data)); +extern void register_storage_idle_func(void (*function)(void)); #if USING_STORAGE_CALLBACK -extern void unregister_storage_idle_func(void (*function)(void *data), bool run); +extern void unregister_storage_idle_func(void (*function)(void), bool run); extern bool call_storage_idle_notifys(bool force); #else #define unregister_storage_idle_func(f,r) diff --git a/firmware/export/events.h b/firmware/export/events.h index 859901c0b4..fd7f9df42e 100644 --- a/firmware/export/events.h +++ b/firmware/export/events.h @@ -23,12 +23,24 @@ #define _EVENTS_H #include - -/** Only CLASS defines and firmware/ level events should be defined here. - * apps/ level events are defined in apps/appevents.h - */ - /** + * Synchronouos event system. + * + * Callbacks are subscribed with add_event() or add_event_ex(). events + * are fired using send_event(). + * + * Events are always dispatched synchronously: the callbacks are called + * in the thread context of the event sender, without context switch. This + * also means that callbacks should be as simple as possible to avoid + * blocking the sender and other callbacks + * + * Use the kernel-level event_queue for cross-thread event dispatching. + * */ + +/* + * Only CLASS defines and firmware/ level events should be defined here. + * apps/ level events are defined in apps/appevents.h + * * High byte = Event class definition * Low byte = Event ID */ @@ -40,9 +52,50 @@ #define EVENT_CLASS_RECORDING 0x1000 #define EVENT_CLASS_LCD 0x2000 -bool add_event(unsigned short id, bool oneshot, void (*handler)(void *data)); -void remove_event(unsigned short id, void (*handler)(void *data)); +/** + * Subscribe to an event with a simple callback. The callback will be called + * synchronously everytime the event fires, passing the event id and data to + * the callback. + * + * Must be removed with remove_event(). + */ +bool add_event(unsigned short id, void (*handler)(unsigned short id, void *event_data)); + +/** + * Subscribe to an event with a detailed callback. The callback will be called + * synchronously everytime the event fires, passing the event id and data, as + * well as the user_data pointer passed here, to the callback. + * + * With oneshot == true, the callback is unsubscribed automatically after + * the event fired for the first time. In this case the event need not to be + * removed with remove_event_ex(). + * + * Must be removed with remove_event_ex(). remove_event() will never remove + * events added with this function. + */ +bool add_event_ex(unsigned short id, bool oneshot, void (*handler)(unsigned short id, void *event_data, void *user_data), void *user_data); + +/** + * Unsubscribe a callback from an event. The handler pointer is matched. + * + * This will only work for subscriptions made with add_event(). + */ +void remove_event(unsigned short id, void (*handler)(unsigned short id, void *data)); + +/** + * Unsubscribe a callback from an event. The handler and user_data pointers + * are matched. That means the same user_data that was passed to add_event_ex() + * must be passed to this too. + * + * This will only work for subscriptions made with add_event_ex(). + */ +void remove_event_ex(unsigned short id, void (*handler)(unsigned short id, void *event_data, void *user_data), void *user_data); + +/** + * Fire an event, which synchronously calls all subscribed callbacks. The + * event id and data pointer are passed to the callbacks as well, and + * optionally the user_data pointer from add_event_ex(). + */ void send_event(unsigned short id, void *data); #endif - diff --git a/firmware/logf.c b/firmware/logf.c index a24a635570..ade5458ca9 100644 --- a/firmware/logf.c +++ b/firmware/logf.c @@ -322,7 +322,7 @@ static int logdiskf_push(void *userp, unsigned char c) return true; } -static void flush_buffer(void* data); +static void flush_buffer(void); void _logdiskf(const char* file, const char level, const char *fmt, ...) { @@ -350,9 +350,8 @@ void _logdiskf(const char* file, const char level, const char *fmt, ...) register_storage_idle_func(flush_buffer); } -static void flush_buffer(void* data) +static void flush_buffer(void) { - (void)data; int fd; if(logdiskfindex < 1) return;