1.. _timer:
2
3================
4Timer (lv_timer)
5================
6
7LVGL has a built-in Timer system. You can register a function to have it
8be called periodically. The Timers are handled and called in
9:cpp:func:`lv_timer_handler`, which needs to be called every few milliseconds.
10See :ref:`timer_handler` for more information.
11
12By default, LVGL itself uses Timers to:
13
14- refresh each display --- during the creation of each :ref:`Display`, a Timer is
15  created for that Display.  That Timer refreshes the display based on the configured
16  value of :c:macro:`LV_DEF_REFR_PERIOD`, and also sends all display-related events,
17  like :cpp:enumerator:`LV_EVENT_REFR_START`, :cpp:enumerator:`LV_EVENT_REFR_READY`,
18  etc.
19- read input devices --- during the creation of each :ref:`indev`, a Timer is
20  created for that Input Device based on the configured value of
21  :c:macro:`LV_DEF_REFR_PERIOD`.  That Timer causes that input device to be read and
22  also sends all input-device-related events, like :cpp:enumerator:`LV_EVENT_CLICKED`,
23  :cpp:enumerator:`LV_EVENT_PRESSED`, etc.
24- update system-monitor values --- if :c:macro:`LV_USE_SYSMON` is set to ``1`` in
25  ``lv_conf.h``, one or more timers are created to periodically compute and
26  monitor system performance statistics and LVGL's memory usage.
27
28Timers are non-preemptive, which means a Timer cannot interrupt another
29Timer. Therefore, you can call any LVGL related function in a Timer.
30
31
32
33Creating a Timer
34****************
35
36To create a new Timer, use
37:cpp:expr:`lv_timer_create(timer_cb, period_ms, user_data)`. It returns an
38:cpp:type:`lv_timer_t` ``*`` which can be used later to modify the
39parameters of the Timer, pause it, or delete it when it is no longer needed.
40:cpp:func:`lv_timer_create_basic` can also be used to create a new Timer without
41specifying any parameters.
42
43A Timer callback should have this prototype:  ``void (*lv_timer_cb_t)(lv_timer_t *)``.
44
45For example:
46
47.. code-block:: c
48
49   void my_timer(lv_timer_t * timer)
50   {
51     /* Use the user_data */
52     uint32_t * user_data = lv_timer_get_user_data(timer);
53     printf("my_timer called with user data: %d\n", *user_data);
54
55     /* Do something with LVGL */
56     if(something_happened) {
57       something_happened = false;
58       lv_button_create(lv_screen_active());
59     }
60   }
61
62   ...
63
64   static uint32_t user_data = 10;
65   lv_timer_t * timer = lv_timer_create(my_timer, 500,  &user_data);
66
67
68
69Ready and Reset
70***************
71
72:cpp:expr:`lv_timer_ready(timer)` makes a Timer run on the next call of
73:cpp:func:`lv_timer_handler`.
74
75:cpp:expr:`lv_timer_reset(timer)` resets the period of a Timer. It will be
76called again after its currently-set period (in milliseconds) has elapsed.
77
78
79
80Setting Parameters
81******************
82
83You can modify these Timer parameters at any time during its life:
84
85- :cpp:expr:`lv_timer_set_cb(timer, new_cb)`
86- :cpp:expr:`lv_timer_set_period(timer, new_period_ms)`
87- :cpp:expr:`lv_timer_set_user_data(timer, user_data)`
88
89
90
91Repeat Count
92************
93
94When a Timer is created, its repeat-count is set to ``-1`` to cause it to repeat
95indefinitely.  You can make a Timer repeat only a given number of times with
96:cpp:expr:`lv_timer_set_repeat_count(timer, count)`.  By default, once the Timer has
97run ``count`` times, it will be automatically deleted.
98
99You can use :cpp:expr:`lv_timer_set_auto_delete(timer, false)` if you want the timer
100to instead be paused after it has run ``count`` times.  This can be handy if you
101reuse that timer repeatedly and want to avoid the CPU and :cpp:func:`lv_malloc`
102overhead of repeatedly creating and deleting a timer.  If you use this option, you
103will need to set its repeat count (to either ``-1`` or a positive repeat count, since
104it will have decremented to ``0``) and :ref:`resume <timer_pause_and_resume>` it to
105make it active again.
106
107
108
109.. _timer_pause_and_resume:
110
111Pause and Resume
112****************
113
114:cpp:expr:`lv_timer_pause(timer)` pauses the specified Timer.
115
116:cpp:expr:`lv_timer_resume(timer)` resumes the specified Timer.
117
118
119
120Measuring Idle Time
121*******************
122
123You can get the idle percentage time of :cpp:func:`lv_timer_handler` with
124:cpp:func:`lv_timer_get_idle`. Note that it does not measure the idle time of
125the overall system, only of :cpp:func:`lv_timer_handler`.  This can be misleading if
126you are using an operating system and DMA and/or GPU are used during rendering, as it
127does not actually measure the time the OS spends in an idle thread.
128
129If you are using an OS and wish to get the time the CPU is spending in an idle
130thread, one way of doing so is configuring :c:macro:`LV_USE_SYSMON` and
131:c:macro:`LV_USE_PERF_MONITOR` to ``1`` in ``lv_conf.h`` (if they are not already),
132and setting the macro :c:macro:`LV_SYSMON_GET_IDLE` to the name of a function that
133fetches the percent of CPU time spent in the OS's idle thread.  An example of such
134a function is :cpp:func:`lv_os_get_idle_percent` in ``lv_freertos.c``.  While the
135configuration is set this way, some system performance statistics (including CPU
136load) will appear on the display in a partially-transparent label whose location is
137set by the :c:macro:`LV_USE_PERF_MONITOR_POS` macro.
138
139
140
141Enable and Disable
142******************
143
144You can temporarily disable Timer handling with :cpp:expr:`lv_timer_enable(false)`.
145Be advised:  this also pauses handling of Timers that refresh Display(s) and read
146from input devices, so don't forget to re-enable it with
147:cpp:expr:`lv_timer_enable(true)` as soon as the need for the pause is over.
148
149
150
151Timer Handler Resume Callback
152*****************************
153
154When the Timer system has been disabled (causing :cpp:func:`lv_timer_handler` to
155return early before it has processed any timers), if you want to take some action
156when the Timer system is re-enabled again, set a resume callback using
157:cpp:expr:`lv_timer_handler_set_resume_cb(cb, user_data)`. The callback should have
158this prototype:  ``void (*lv_timer_handler_resume_cb_t)(void*)``.
159
160
161
162Asynchronous calls
163******************
164
165There are several cases in which you may not want to perform an action immediately.
166Some examples are:
167
168- you cannot delete a Widget because something else is still using it,
169- you don't want to block execution now, or
170- you detect the need to delete a Widget in a thread other than the thread making
171  LVGL calls (e.g. in a case where you are using a :ref:`Gateway Thread <Gateway
172  Thread>` to make all LVGL calls in a multi-threaded environment).
173
174For these cases,
175:cpp:expr:`lv_async_call(my_function, data_p)` can be used to call ``my_function`` on
176the next invocation of :cpp:func:`lv_timer_handler`.  As a side effect, this also
177ensures it is called in a thread in which it is safe to make LVGL calls.
178``data_p`` will be passed to the function when it's called. Note that only the data's
179pointer is saved, so whatever it is pointing to needs to remain valid until the
180function is called, so it can point to ``static``, global or dynamically allocated
181data. If you want to cancel an asynchronous call, call
182:cpp:expr:`lv_async_call_cancel(my_function, data_p)`, which will remove all
183asynchronous calls matching ``my_function`` and ``data_p``.
184
185Note that if :cpp:expr:`lv_async_call(my_function, data_p)` is called from a thread
186other than the one that normally makes LVGL calls, you are still obligated to protect
187the LVGL data structure using a MUTEX.
188
189For example:
190
191.. code-block:: c
192
193   void my_screen_clean_up(void * scr)
194   {
195     /* Free some resources related to `scr`*/
196
197     /* Finally delete the screen */
198     lv_obj_delete(scr);
199   }
200
201   ...
202
203   /* Do something with the Widget on the current screen */
204
205   /* Delete screen on next call of `lv_timer_handler`, not right now. */
206   lv_lock();
207   lv_async_call(my_screen_clean_up, lv_screen_active());
208   lv_unlock();
209
210   /* The screen is still valid so you can do other things with it */
211
212If you just want to delete a Widget and don't need to clean anything up
213in ``my_screen_cleanup`` you could just use :cpp:expr:`lv_obj_delete_async(widget)` which
214will delete the Widget on the next call to :cpp:func:`lv_timer_handler`.
215
216
217
218.. _timer_api:
219
220API
221***
222