Description
How can I tell if a screen-change is currently animating? My LVGL main loop has two possible actions:
- Call lv_timer_handler()
- If present, pop a command-packet from a FreeRTOS queue and process it. This may involve calling lv_scr_load_anim()
What LVGL version are you using?
8.3.x
What do you want to achieve?
I’d like to defer processing a command packet while a screen animation is running, so that my screen changes can occur back-to-back, rather than a new screen change destroying the old screen immediately while a screen change is already in progress.
What have you tried so far?
I’ve tried stashing the current screen pointer and waiting for it to update, but this is tedious. Do I need to wait until disp->scr_to_load is NULL? Is there a direct way to do so?
what if you try to use events?
That’s an interesting idea! Just to confirm, you mean I should monitor for LV_EVENT_SCREEN_UNLOAD_START to notice that the animation has begun, then perhaps LV_EVENT_SCREEN_UNLOADED to notice when the previous screen was unloaded?
Are both of your actions processed in one thread?
Yes. Other threads submit work using the queue that the main thread processes.
I can offer you create semaphore when lv_scr_load_anim()
is called.Give it when new screen loaded (in LV_EVENT_SCREEN_LOADED event handler). And skip action 2 if semaphore not taken (xSemaphoreTake in non-blocking mode - TickToWait=0).
EDIT: delete semaphore if it successfully taken.
I think something like that should work, since all LVGL calls and queue processing are all on the same thread, I think a simple boolean should work, something like this:
bool animationRunning = false;
void threadFunc(){
if(queueHasItem() && !animationRunning){
queuePopAndProcessItem();
}
//This would trigger calls to update animationRunning accordingly
lv_timer_handler();
}
Is there a way to listen for all calls to lv_scr_load_anim()
by LV_EVENT_SCREEN_UNLOAD_START ? Or, would I have to wrap all calls to lv_scr_load_anim()
? Is there a root object I could listen to where all LV_EVENT_SCREEN_UNLOAD_START would trigger, maybe the display object?
In principle, you can do it without a semaphore, and use a regular variable - since as far as I remember, event handlers are called inside lv_timer_handler()
I have not used such events, but I can assume that you can use lv_obj_add_event_cb()
for root screen objects - which you use when call lv_scr_load_anim().
EDIT: and as far as I understand you need to use
LV_EVENT_SCREEN_LOADED
A screen was loaded, called when all animations are finished
I can call lv_obj_add_event_cb() on the root screen object, but it seems I need to then enable event bubbling for the event target, which means I’d need to wrap each call to lv_scr_load_anim() before LV_EVENT_SCREEN_LOADED would bubble up to the root screen object.
I think I’ve got it(would need disp param for multiple displays):
bool lv_disp_anim_running(void)
{
lv_obj_t * act_scr = lv_scr_act();
if(!act_scr) return false;
lv_disp_t * d = lv_obj_get_disp(act_scr);
if(!d) return false;
return d->scr_to_load != NULL;
}