acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_timer.c (9593B)
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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 213 void lv_timer_pause(lv_timer_t * timer) 214 { 215 timer->paused = true; 216 } 217 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 }