1 /**
2  * @file lv_timer.c
3  */
4 
5 /*********************
6  *      INCLUDES
7  *********************/
8 #include "lv_timer.h"
9 #include "../hal/lv_hal_tick.h"
10 #include "lv_assert.h"
11 #include "lv_mem.h"
12 #include "lv_ll.h"
13 #include "lv_gc.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 #define IDLE_MEAS_PERIOD 500 /*[ms]*/
19 #define DEF_PERIOD 500
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 
25 /**********************
26  *  STATIC PROTOTYPES
27  **********************/
28 static bool lv_timer_exec(lv_timer_t * timer);
29 static uint32_t lv_timer_time_remaining(lv_timer_t * timer);
30 
31 /**********************
32  *  STATIC VARIABLES
33  **********************/
34 static bool lv_timer_run = false;
35 static uint8_t idle_last = 0;
36 static bool timer_deleted;
37 static bool timer_created;
38 
39 /**********************
40  *      MACROS
41  **********************/
42 #if LV_LOG_TRACE_TIMER
43     #define TIMER_TRACE(...) LV_LOG_TRACE(__VA_ARGS__)
44 #else
45     #define TIMER_TRACE(...)
46 #endif
47 
48 /**********************
49  *   GLOBAL FUNCTIONS
50  **********************/
51 
52 /**
53  * Init the lv_timer module
54  */
_lv_timer_core_init(void)55 void _lv_timer_core_init(void)
56 {
57     _lv_ll_init(&LV_GC_ROOT(_lv_timer_ll), sizeof(lv_timer_t));
58 
59     /*Initially enable the lv_timer handling*/
60     lv_timer_enable(true);
61 }
62 
63 /**
64  * Call it periodically to handle lv_timers.
65  * @return the time after which it must be called again
66  */
lv_timer_handler(void)67 LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
68 {
69     TIMER_TRACE("begin");
70 
71     /*Avoid concurrent running of the timer handler*/
72     static bool already_running = false;
73     if(already_running) {
74         TIMER_TRACE("already running, concurrent calls are not allow, returning");
75         return 1;
76     }
77     already_running = true;
78 
79     if(lv_timer_run == false) {
80         already_running = false; /*Release mutex*/
81         return 1;
82     }
83 
84     static uint32_t idle_period_start = 0;
85     static uint32_t busy_time         = 0;
86 
87     uint32_t handler_start = lv_tick_get();
88 
89     if(handler_start == 0) {
90         static uint32_t run_cnt = 0;
91         run_cnt++;
92         if(run_cnt > 100) {
93             run_cnt = 0;
94             LV_LOG_WARN("It seems lv_tick_inc() is not called.");
95         }
96     }
97 
98     /*Run all timer from the list*/
99     lv_timer_t * next;
100     do {
101         timer_deleted             = false;
102         timer_created             = false;
103         LV_GC_ROOT(_lv_timer_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
104         while(LV_GC_ROOT(_lv_timer_act)) {
105             /*The timer might be deleted if it runs only once ('repeat_count = 1')
106              *So get next element until the current is surely valid*/
107             next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), LV_GC_ROOT(_lv_timer_act));
108 
109             if(lv_timer_exec(LV_GC_ROOT(_lv_timer_act))) {
110                 /*If a timer was created or deleted then this or the next item might be corrupted*/
111                 if(timer_created || timer_deleted) {
112                     TIMER_TRACE("Start from the first timer again because a timer was created or deleted");
113                     break;
114                 }
115             }
116 
117             LV_GC_ROOT(_lv_timer_act) = next; /*Load the next timer*/
118         }
119     } while(LV_GC_ROOT(_lv_timer_act));
120 
121     uint32_t time_till_next = LV_NO_TIMER_READY;
122     next = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
123     while(next) {
124         if(!next->paused) {
125             uint32_t delay = lv_timer_time_remaining(next);
126             if(delay < time_till_next)
127                 time_till_next = delay;
128         }
129 
130         next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), next); /*Find the next timer*/
131     }
132 
133     busy_time += lv_tick_elaps(handler_start);
134     uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
135     if(idle_period_time >= IDLE_MEAS_PERIOD) {
136         idle_last         = (busy_time * 100) / idle_period_time;  /*Calculate the busy percentage*/
137         idle_last         = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
138         busy_time         = 0;
139         idle_period_start = lv_tick_get();
140     }
141 
142     already_running = false; /*Release the mutex*/
143 
144     TIMER_TRACE("finished (%d ms until the next timer call)", time_till_next);
145     return time_till_next;
146 }
147 
148 /**
149  * Create an "empty" timer. It needs to initialized with at least
150  * `lv_timer_set_cb` and `lv_timer_set_period`
151  * @return pointer to the created timer
152  */
lv_timer_create_basic(void)153 lv_timer_t * lv_timer_create_basic(void)
154 {
155     return lv_timer_create(NULL, DEF_PERIOD, NULL);
156 }
157 
158 /**
159  * Create a new lv_timer
160  * @param timer_xcb a callback which is the timer itself. It will be called periodically.
161  *                 (the 'x' in the argument name indicates that it's not a fully generic function because it not follows
162  *                  the `func_name(object, callback, ...)` convention)
163  * @param period call period in ms unit
164  * @param user_data custom parameter
165  * @return pointer to the new timer
166  */
lv_timer_create(lv_timer_cb_t timer_xcb,uint32_t period,void * user_data)167 lv_timer_t * lv_timer_create(lv_timer_cb_t timer_xcb, uint32_t period, void * user_data)
168 {
169     lv_timer_t * new_timer = NULL;
170 
171     new_timer = _lv_ll_ins_head(&LV_GC_ROOT(_lv_timer_ll));
172     LV_ASSERT_MALLOC(new_timer);
173     if(new_timer == NULL) return NULL;
174 
175     new_timer->period = period;
176     new_timer->timer_cb = timer_xcb;
177     new_timer->repeat_count = -1;
178     new_timer->paused = 0;
179     new_timer->last_run = lv_tick_get();
180     new_timer->user_data = user_data;
181 
182     timer_created = true;
183 
184     return new_timer;
185 }
186 
187 /**
188  * Set the callback the timer (the function to call periodically)
189  * @param timer pointer to a timer
190  * @param timer_cb the function to call periodically
191  */
lv_timer_set_cb(lv_timer_t * timer,lv_timer_cb_t timer_cb)192 void lv_timer_set_cb(lv_timer_t * timer, lv_timer_cb_t timer_cb)
193 {
194     timer->timer_cb = timer_cb;
195 }
196 
197 /**
198  * Delete a lv_timer
199  * @param timer pointer to timer created by timer
200  */
lv_timer_del(lv_timer_t * timer)201 void lv_timer_del(lv_timer_t * timer)
202 {
203     _lv_ll_remove(&LV_GC_ROOT(_lv_timer_ll), timer);
204     timer_deleted = true;
205 
206     lv_mem_free(timer);
207 }
208 
209 /**
210  * Pause/resume a timer.
211  * @param timer pointer to an lv_timer
212  */
lv_timer_pause(lv_timer_t * timer)213 void lv_timer_pause(lv_timer_t * timer)
214 {
215     timer->paused = true;
216 }
217 
lv_timer_resume(lv_timer_t * timer)218 void lv_timer_resume(lv_timer_t * timer)
219 {
220     timer->paused = false;
221 }
222 
223 /**
224  * Set new period for a lv_timer
225  * @param timer pointer to a lv_timer
226  * @param period the new period
227  */
lv_timer_set_period(lv_timer_t * timer,uint32_t period)228 void lv_timer_set_period(lv_timer_t * timer, uint32_t period)
229 {
230     timer->period = period;
231 }
232 
233 /**
234  * Make a lv_timer ready. It will not wait its period.
235  * @param timer pointer to a lv_timer.
236  */
lv_timer_ready(lv_timer_t * timer)237 void lv_timer_ready(lv_timer_t * timer)
238 {
239     timer->last_run = lv_tick_get() - timer->period - 1;
240 }
241 
242 /**
243  * Set the number of times a timer will repeat.
244  * @param timer pointer to a lv_timer.
245  * @param repeat_count -1 : infinity;  0 : stop ;  n >0: residual times
246  */
lv_timer_set_repeat_count(lv_timer_t * timer,int32_t repeat_count)247 void lv_timer_set_repeat_count(lv_timer_t * timer, int32_t repeat_count)
248 {
249     timer->repeat_count = repeat_count;
250 }
251 
252 /**
253  * Reset a lv_timer.
254  * It will be called the previously set period milliseconds later.
255  * @param timer pointer to a lv_timer.
256  */
lv_timer_reset(lv_timer_t * timer)257 void lv_timer_reset(lv_timer_t * timer)
258 {
259     timer->last_run = lv_tick_get();
260 }
261 
262 /**
263  * Enable or disable the whole lv_timer handling
264  * @param en true: lv_timer handling is running, false: lv_timer handling is suspended
265  */
lv_timer_enable(bool en)266 void lv_timer_enable(bool en)
267 {
268     lv_timer_run = en;
269 }
270 
271 /**
272  * Get idle percentage
273  * @return the lv_timer idle in percentage
274  */
lv_timer_get_idle(void)275 uint8_t lv_timer_get_idle(void)
276 {
277     return idle_last;
278 }
279 
280 /**
281  * Iterate through the timers
282  * @param timer NULL to start iteration or the previous return value to get the next timer
283  * @return the next timer or NULL if there is no more timer
284  */
lv_timer_get_next(lv_timer_t * timer)285 lv_timer_t * lv_timer_get_next(lv_timer_t * timer)
286 {
287     if(timer == NULL) return _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
288     else return _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), timer);
289 }
290 
291 /**********************
292  *   STATIC FUNCTIONS
293  **********************/
294 
295 /**
296  * Execute timer if its remaining time is zero
297  * @param timer pointer to lv_timer
298  * @return true: execute, false: not executed
299  */
lv_timer_exec(lv_timer_t * timer)300 static bool lv_timer_exec(lv_timer_t * timer)
301 {
302     if(timer->paused) return false;
303 
304     bool exec = false;
305     if(lv_timer_time_remaining(timer) == 0) {
306         /* Decrement the repeat count before executing the timer_cb.
307          * If any timer is deleted `if(timer->repeat_count == 0)` is not executed below
308          * but at least the repeat count is zero and the timer can be deleted in the next round*/
309         int32_t original_repeat_count = timer->repeat_count;
310         if(timer->repeat_count > 0) timer->repeat_count--;
311         timer->last_run = lv_tick_get();
312         TIMER_TRACE("calling timer callback: %p", *((void **)&timer->timer_cb));
313         if(timer->timer_cb && original_repeat_count != 0) timer->timer_cb(timer);
314         TIMER_TRACE("timer callback %p finished", *((void **)&timer->timer_cb));
315         LV_ASSERT_MEM_INTEGRITY();
316         exec = true;
317     }
318 
319     if(timer_deleted == false) { /*The timer might be deleted by itself as well*/
320         if(timer->repeat_count == 0) { /*The repeat count is over, delete the timer*/
321             TIMER_TRACE("deleting timer with %p callback because the repeat count is over", *((void **)&timer->timer_cb));
322             lv_timer_del(timer);
323         }
324     }
325 
326     return exec;
327 }
328 
329 /**
330  * Find out how much time remains before a timer must be run.
331  * @param timer pointer to lv_timer
332  * @return the time remaining, or 0 if it needs to be run again
333  */
lv_timer_time_remaining(lv_timer_t * timer)334 static uint32_t lv_timer_time_remaining(lv_timer_t * timer)
335 {
336     /*Check if at least 'period' time elapsed*/
337     uint32_t elp = lv_tick_elaps(timer->last_run);
338     if(elp >= timer->period)
339         return 0;
340     return timer->period - elp;
341 }
342