From dd27c3530432ea0b09f01e604bf577f31d8ef841 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 1 Jun 2023 15:41:47 +1000 Subject: convert lvgl from submodule to a plain old directory --- lib/lvgl | 1 - lib/lvgl/src/misc/lv_timer.c | 341 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+), 1 deletion(-) delete mode 160000 lib/lvgl create mode 100644 lib/lvgl/src/misc/lv_timer.c (limited to 'lib/lvgl/src/misc/lv_timer.c') diff --git a/lib/lvgl b/lib/lvgl deleted file mode 160000 index 0732400e..00000000 --- a/lib/lvgl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0732400e7b564dd0e7dc4a924619d8e19c5b23a0 diff --git a/lib/lvgl/src/misc/lv_timer.c b/lib/lvgl/src/misc/lv_timer.c new file mode 100644 index 00000000..d8dd55b7 --- /dev/null +++ b/lib/lvgl/src/misc/lv_timer.c @@ -0,0 +1,341 @@ +/** + * @file lv_timer.c + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_timer.h" +#include "../hal/lv_hal_tick.h" +#include "lv_assert.h" +#include "lv_mem.h" +#include "lv_ll.h" +#include "lv_gc.h" + +/********************* + * DEFINES + *********************/ +#define IDLE_MEAS_PERIOD 500 /*[ms]*/ +#define DEF_PERIOD 500 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool lv_timer_exec(lv_timer_t * timer); +static uint32_t lv_timer_time_remaining(lv_timer_t * timer); + +/********************** + * STATIC VARIABLES + **********************/ +static bool lv_timer_run = false; +static uint8_t idle_last = 0; +static bool timer_deleted; +static bool timer_created; + +/********************** + * MACROS + **********************/ +#if LV_LOG_TRACE_TIMER + #define TIMER_TRACE(...) LV_LOG_TRACE(__VA_ARGS__) +#else + #define TIMER_TRACE(...) +#endif + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Init the lv_timer module + */ +void _lv_timer_core_init(void) +{ + _lv_ll_init(&LV_GC_ROOT(_lv_timer_ll), sizeof(lv_timer_t)); + + /*Initially enable the lv_timer handling*/ + lv_timer_enable(true); +} + +/** + * Call it periodically to handle lv_timers. + * @return the time after which it must be called again + */ +LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void) +{ + TIMER_TRACE("begin"); + + /*Avoid concurrent running of the timer handler*/ + static bool already_running = false; + if(already_running) { + TIMER_TRACE("already running, concurrent calls are not allow, returning"); + return 1; + } + already_running = true; + + if(lv_timer_run == false) { + already_running = false; /*Release mutex*/ + return 1; + } + + static uint32_t idle_period_start = 0; + static uint32_t busy_time = 0; + + uint32_t handler_start = lv_tick_get(); + + if(handler_start == 0) { + static uint32_t run_cnt = 0; + run_cnt++; + if(run_cnt > 100) { + run_cnt = 0; + LV_LOG_WARN("It seems lv_tick_inc() is not called."); + } + } + + /*Run all timer from the list*/ + lv_timer_t * next; + do { + timer_deleted = false; + timer_created = false; + LV_GC_ROOT(_lv_timer_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll)); + while(LV_GC_ROOT(_lv_timer_act)) { + /*The timer might be deleted if it runs only once ('repeat_count = 1') + *So get next element until the current is surely valid*/ + next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), LV_GC_ROOT(_lv_timer_act)); + + if(lv_timer_exec(LV_GC_ROOT(_lv_timer_act))) { + /*If a timer was created or deleted then this or the next item might be corrupted*/ + if(timer_created || timer_deleted) { + TIMER_TRACE("Start from the first timer again because a timer was created or deleted"); + break; + } + } + + LV_GC_ROOT(_lv_timer_act) = next; /*Load the next timer*/ + } + } while(LV_GC_ROOT(_lv_timer_act)); + + uint32_t time_till_next = LV_NO_TIMER_READY; + next = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll)); + while(next) { + if(!next->paused) { + uint32_t delay = lv_timer_time_remaining(next); + if(delay < time_till_next) + time_till_next = delay; + } + + next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), next); /*Find the next timer*/ + } + + busy_time += lv_tick_elaps(handler_start); + uint32_t idle_period_time = lv_tick_elaps(idle_period_start); + if(idle_period_time >= IDLE_MEAS_PERIOD) { + idle_last = (busy_time * 100) / idle_period_time; /*Calculate the busy percentage*/ + idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/ + busy_time = 0; + idle_period_start = lv_tick_get(); + } + + already_running = false; /*Release the mutex*/ + + TIMER_TRACE("finished (%d ms until the next timer call)", time_till_next); + return time_till_next; +} + +/** + * Create an "empty" timer. It needs to initialized with at least + * `lv_timer_set_cb` and `lv_timer_set_period` + * @return pointer to the created timer + */ +lv_timer_t * lv_timer_create_basic(void) +{ + return lv_timer_create(NULL, DEF_PERIOD, NULL); +} + +/** + * Create a new lv_timer + * @param timer_xcb a callback which is the timer itself. It will be called periodically. + * (the 'x' in the argument name indicates that it's not a fully generic function because it not follows + * the `func_name(object, callback, ...)` convention) + * @param period call period in ms unit + * @param user_data custom parameter + * @return pointer to the new timer + */ +lv_timer_t * lv_timer_create(lv_timer_cb_t timer_xcb, uint32_t period, void * user_data) +{ + lv_timer_t * new_timer = NULL; + + new_timer = _lv_ll_ins_head(&LV_GC_ROOT(_lv_timer_ll)); + LV_ASSERT_MALLOC(new_timer); + if(new_timer == NULL) return NULL; + + new_timer->period = period; + new_timer->timer_cb = timer_xcb; + new_timer->repeat_count = -1; + new_timer->paused = 0; + new_timer->last_run = lv_tick_get(); + new_timer->user_data = user_data; + + timer_created = true; + + return new_timer; +} + +/** + * Set the callback the timer (the function to call periodically) + * @param timer pointer to a timer + * @param timer_cb the function to call periodically + */ +void lv_timer_set_cb(lv_timer_t * timer, lv_timer_cb_t timer_cb) +{ + timer->timer_cb = timer_cb; +} + +/** + * Delete a lv_timer + * @param timer pointer to timer created by timer + */ +void lv_timer_del(lv_timer_t * timer) +{ + _lv_ll_remove(&LV_GC_ROOT(_lv_timer_ll), timer); + timer_deleted = true; + + lv_mem_free(timer); +} + +/** + * Pause/resume a timer. + * @param timer pointer to an lv_timer + */ +void lv_timer_pause(lv_timer_t * timer) +{ + timer->paused = true; +} + +void lv_timer_resume(lv_timer_t * timer) +{ + timer->paused = false; +} + +/** + * Set new period for a lv_timer + * @param timer pointer to a lv_timer + * @param period the new period + */ +void lv_timer_set_period(lv_timer_t * timer, uint32_t period) +{ + timer->period = period; +} + +/** + * Make a lv_timer ready. It will not wait its period. + * @param timer pointer to a lv_timer. + */ +void lv_timer_ready(lv_timer_t * timer) +{ + timer->last_run = lv_tick_get() - timer->period - 1; +} + +/** + * Set the number of times a timer will repeat. + * @param timer pointer to a lv_timer. + * @param repeat_count -1 : infinity; 0 : stop ; n >0: residual times + */ +void lv_timer_set_repeat_count(lv_timer_t * timer, int32_t repeat_count) +{ + timer->repeat_count = repeat_count; +} + +/** + * Reset a lv_timer. + * It will be called the previously set period milliseconds later. + * @param timer pointer to a lv_timer. + */ +void lv_timer_reset(lv_timer_t * timer) +{ + timer->last_run = lv_tick_get(); +} + +/** + * Enable or disable the whole lv_timer handling + * @param en true: lv_timer handling is running, false: lv_timer handling is suspended + */ +void lv_timer_enable(bool en) +{ + lv_timer_run = en; +} + +/** + * Get idle percentage + * @return the lv_timer idle in percentage + */ +uint8_t lv_timer_get_idle(void) +{ + return idle_last; +} + +/** + * Iterate through the timers + * @param timer NULL to start iteration or the previous return value to get the next timer + * @return the next timer or NULL if there is no more timer + */ +lv_timer_t * lv_timer_get_next(lv_timer_t * timer) +{ + if(timer == NULL) return _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll)); + else return _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), timer); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Execute timer if its remaining time is zero + * @param timer pointer to lv_timer + * @return true: execute, false: not executed + */ +static bool lv_timer_exec(lv_timer_t * timer) +{ + if(timer->paused) return false; + + bool exec = false; + if(lv_timer_time_remaining(timer) == 0) { + /* Decrement the repeat count before executing the timer_cb. + * If any timer is deleted `if(timer->repeat_count == 0)` is not executed below + * but at least the repeat count is zero and the timer can be deleted in the next round*/ + int32_t original_repeat_count = timer->repeat_count; + if(timer->repeat_count > 0) timer->repeat_count--; + timer->last_run = lv_tick_get(); + TIMER_TRACE("calling timer callback: %p", *((void **)&timer->timer_cb)); + if(timer->timer_cb && original_repeat_count != 0) timer->timer_cb(timer); + TIMER_TRACE("timer callback %p finished", *((void **)&timer->timer_cb)); + LV_ASSERT_MEM_INTEGRITY(); + exec = true; + } + + if(timer_deleted == false) { /*The timer might be deleted by itself as well*/ + if(timer->repeat_count == 0) { /*The repeat count is over, delete the timer*/ + TIMER_TRACE("deleting timer with %p callback because the repeat count is over", *((void **)&timer->timer_cb)); + lv_timer_del(timer); + } + } + + return exec; +} + +/** + * Find out how much time remains before a timer must be run. + * @param timer pointer to lv_timer + * @return the time remaining, or 0 if it needs to be run again + */ +static uint32_t lv_timer_time_remaining(lv_timer_t * timer) +{ + /*Check if at least 'period' time elapsed*/ + uint32_t elp = lv_tick_elaps(timer->last_run); + if(elp >= timer->period) + return 0; + return timer->period - elp; +} -- cgit v1.2.3