summaryrefslogtreecommitdiff
path: root/lib/lvgl/src/misc/lv_timer.c
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-06-01 15:41:47 +1000
committerjacqueline <me@jacqueline.id.au>2023-06-01 15:41:47 +1000
commitdd27c3530432ea0b09f01e604bf577f31d8ef841 (patch)
treebbf86cf81a78f0ff0b07f31f1c390db473f26fd3 /lib/lvgl/src/misc/lv_timer.c
parent6fd588e970470b15936187980829916d0dbe77bb (diff)
downloadtangara-fw-dd27c3530432ea0b09f01e604bf577f31d8ef841.tar.gz
convert lvgl from submodule to a plain old directory
Diffstat (limited to 'lib/lvgl/src/misc/lv_timer.c')
m---------lib/lvgl0
-rw-r--r--lib/lvgl/src/misc/lv_timer.c341
2 files changed, 341 insertions, 0 deletions
diff --git a/lib/lvgl b/lib/lvgl
deleted file mode 160000
-Subproject 0732400e7b564dd0e7dc4a924619d8e19c5b23a
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;
+}