Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/libs/lvgl/lv_misc/lv_task.c
1476 views
1
/**
2
* @file lv_task.c
3
* An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically.
4
* A priority (5 levels + disable) can be assigned to lv_tasks.
5
*/
6
7
/*********************
8
* INCLUDES
9
*********************/
10
#include <stddef.h>
11
#include "lv_task.h"
12
#include "../lv_hal/lv_hal_tick.h"
13
#include "lv_gc.h"
14
15
#if defined(LV_GC_INCLUDE)
16
# include LV_GC_INCLUDE
17
#endif /* LV_ENABLE_GC */
18
19
/*********************
20
* DEFINES
21
*********************/
22
#define IDLE_MEAS_PERIOD 500 /*[ms]*/
23
24
/**********************
25
* TYPEDEFS
26
**********************/
27
28
/**********************
29
* STATIC PROTOTYPES
30
**********************/
31
static bool lv_task_exec(lv_task_t * lv_task_p);
32
33
/**********************
34
* STATIC VARIABLES
35
**********************/
36
static bool lv_task_run = false;
37
static uint8_t idle_last = 0;
38
static bool task_deleted;
39
static bool task_created;
40
41
/**********************
42
* MACROS
43
**********************/
44
45
/**********************
46
* GLOBAL FUNCTIONS
47
**********************/
48
49
/**
50
* Init the lv_task module
51
*/
52
void lv_task_init(void)
53
{
54
lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t));
55
56
/*Initially enable the lv_task handling*/
57
lv_task_enable(true);
58
}
59
60
/**
61
* Call it periodically to handle lv_tasks.
62
*/
63
LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
64
{
65
LV_LOG_TRACE("lv_task_handler started");
66
67
/*Avoid concurrent running of the task handler*/
68
static bool task_handler_mutex = false;
69
if(task_handler_mutex) return;
70
task_handler_mutex = true;
71
72
static uint32_t idle_period_start = 0;
73
static uint32_t handler_start = 0;
74
static uint32_t busy_time = 0;
75
76
if(lv_task_run == false) return;
77
78
handler_start = lv_tick_get();
79
80
/* Run all task from the highest to the lowest priority
81
* If a lower priority task is executed check task again from the highest priority
82
* but on the priority of executed tasks don't run tasks before the executed*/
83
lv_task_t * task_interrupter = NULL;
84
lv_task_t * next;
85
bool end_flag;
86
do {
87
end_flag = true;
88
task_deleted = false;
89
task_created = false;
90
LV_GC_ROOT(_lv_task_act) = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
91
while(LV_GC_ROOT(_lv_task_act)) {
92
/* The task might be deleted if it runs only once ('once = 1')
93
* So get next element until the current is surely valid*/
94
next = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), LV_GC_ROOT(_lv_task_act));
95
96
/*We reach priority of the turned off task. There is nothing more to do.*/
97
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_OFF) {
98
break;
99
}
100
101
/*Here is the interrupter task. Don't execute it again.*/
102
if(LV_GC_ROOT(_lv_task_act) == task_interrupter) {
103
task_interrupter = NULL; /*From this point only task after the interrupter comes, so the interrupter is not interesting anymore*/
104
LV_GC_ROOT(_lv_task_act) = next;
105
continue; /*Load the next task*/
106
}
107
108
/*Just try to run the tasks with highest priority.*/
109
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) {
110
lv_task_exec(LV_GC_ROOT(_lv_task_act));
111
}
112
/*Tasks with higher priority then the interrupted shall be run in every case*/
113
else if(task_interrupter) {
114
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) {
115
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
116
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
117
end_flag = false;
118
break;
119
}
120
}
121
}
122
/* It is no interrupter task or we already reached it earlier.
123
* Just run the remaining tasks*/
124
else {
125
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
126
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
127
end_flag = false;
128
break;
129
}
130
}
131
132
if(task_deleted) break; /*If a task was deleted then this or the next item might be corrupted*/
133
if(task_created) break; /*If a task was deleted then this or the next item might be corrupted*/
134
135
LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/
136
}
137
} while(!end_flag);
138
139
busy_time += lv_tick_elaps(handler_start);
140
uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
141
if(idle_period_time >= IDLE_MEAS_PERIOD) {
142
143
idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/
144
idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
145
busy_time = 0;
146
idle_period_start = lv_tick_get();
147
148
149
}
150
151
task_handler_mutex = false; /*Release the mutex*/
152
153
LV_LOG_TRACE("lv_task_handler ready");
154
}
155
156
/**
157
* Create a new lv_task
158
* @param task a function which is the task itself
159
* @param period call period in ms unit
160
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
161
* @param param free parameter
162
* @return pointer to the new task
163
*/
164
lv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio, void * param)
165
{
166
lv_task_t * new_lv_task = NULL;
167
lv_task_t * tmp;
168
169
/*Create task lists in order of priority from high to low*/
170
tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
171
if(NULL == tmp) { /*First task*/
172
new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));
173
lv_mem_assert(new_lv_task);
174
if(new_lv_task == NULL) return NULL;
175
} else {
176
do {
177
if(tmp->prio <= prio) {
178
new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);
179
lv_mem_assert(new_lv_task);
180
if(new_lv_task == NULL) return NULL;
181
break;
182
}
183
tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp);
184
} while(tmp != NULL);
185
186
if(tmp == NULL) { /*Only too high priority tasks were found*/
187
new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));
188
lv_mem_assert(new_lv_task);
189
if(new_lv_task == NULL) return NULL;
190
}
191
}
192
193
new_lv_task->period = period;
194
new_lv_task->task = task;
195
new_lv_task->prio = prio;
196
new_lv_task->param = param;
197
new_lv_task->once = 0;
198
new_lv_task->last_run = lv_tick_get();
199
200
task_created = true;
201
202
return new_lv_task;
203
}
204
205
/**
206
* Delete a lv_task
207
* @param lv_task_p pointer to task created by lv_task_p
208
*/
209
void lv_task_del(lv_task_t * lv_task_p)
210
{
211
lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p);
212
213
lv_mem_free(lv_task_p);
214
215
if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true; /*The active task was deleted*/
216
}
217
218
/**
219
* Set new priority for a lv_task
220
* @param lv_task_p pointer to a lv_task
221
* @param prio the new priority
222
*/
223
void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio)
224
{
225
/*Find the tasks with new priority*/
226
lv_task_t * i;
227
LL_READ(LV_GC_ROOT(_lv_task_ll), i) {
228
if(i->prio <= prio) {
229
if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i);
230
break;
231
}
232
}
233
234
/*There was no such a low priority so far then add the node to the tail*/
235
if(i == NULL) {
236
lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL);
237
}
238
239
240
lv_task_p->prio = prio;
241
}
242
243
/**
244
* Set new period for a lv_task
245
* @param lv_task_p pointer to a lv_task
246
* @param period the new period
247
*/
248
void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period)
249
{
250
lv_task_p->period = period;
251
}
252
253
/**
254
* Make a lv_task ready. It will not wait its period.
255
* @param lv_task_p pointer to a lv_task.
256
*/
257
void lv_task_ready(lv_task_t * lv_task_p)
258
{
259
lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1;
260
}
261
262
/**
263
* Delete the lv_task after one call
264
* @param lv_task_p pointer to a lv_task.
265
*/
266
void lv_task_once(lv_task_t * lv_task_p)
267
{
268
lv_task_p->once = 1;
269
}
270
271
/**
272
* Reset a lv_task.
273
* It will be called the previously set period milliseconds later.
274
* @param lv_task_p pointer to a lv_task.
275
*/
276
void lv_task_reset(lv_task_t * lv_task_p)
277
{
278
lv_task_p->last_run = lv_tick_get();
279
}
280
281
/**
282
* Enable or disable the whole lv_task handling
283
* @param en: true: lv_task handling is running, false: lv_task handling is suspended
284
*/
285
void lv_task_enable(bool en)
286
{
287
lv_task_run = en;
288
}
289
290
/**
291
* Get idle percentage
292
* @return the lv_task idle in percentage
293
*/
294
uint8_t lv_task_get_idle(void)
295
{
296
return idle_last;
297
}
298
299
300
/**********************
301
* STATIC FUNCTIONS
302
**********************/
303
304
/**
305
* Execute task if its the priority is appropriate
306
* @param lv_task_p pointer to lv_task
307
* @return true: execute, false: not executed
308
*/
309
static bool lv_task_exec(lv_task_t * lv_task_p)
310
{
311
bool exec = false;
312
313
/*Execute if at least 'period' time elapsed*/
314
uint32_t elp = lv_tick_elaps(lv_task_p->last_run);
315
if(elp >= lv_task_p->period) {
316
lv_task_p->last_run = lv_tick_get();
317
task_deleted = false;
318
task_created = false;
319
lv_task_p->task(lv_task_p->param);
320
321
/*Delete if it was a one shot lv_task*/
322
if(task_deleted == false) { /*The task might be deleted by itself as well*/
323
if(lv_task_p->once != 0) {
324
lv_task_del(lv_task_p);
325
}
326
}
327
exec = true;
328
}
329
330
return exec;
331
}
332
333
334