lv_task.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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. * INCLUDES
  8. *********************/
  9. #include <stddef.h>
  10. #include "lv_task.h"
  11. #include "../lv_hal/lv_hal_tick.h"
  12. #include "../../lv_conf.h"
  13. /*********************
  14. * DEFINES
  15. *********************/
  16. #define IDLE_MEAS_PERIOD 500 /*[ms]*/
  17. /**********************
  18. * TYPEDEFS
  19. **********************/
  20. /**********************
  21. * STATIC PROTOTYPES
  22. **********************/
  23. static bool lv_task_exec (lv_task_t* lv_task_p);
  24. /**********************
  25. * STATIC VARIABLES
  26. **********************/
  27. static lv_ll_t lv_task_ll; /*Linked list to store the lv_tasks*/
  28. static bool lv_task_run = false;
  29. static uint8_t idle_last = 0;
  30. /**********************
  31. * MACROS
  32. **********************/
  33. /**********************
  34. * GLOBAL FUNCTIONS
  35. **********************/
  36. /**
  37. * Init the lv_task module
  38. */
  39. void lv_task_init(void)
  40. {
  41. lv_ll_init(&lv_task_ll, sizeof(lv_task_t));
  42. /*Initially enable the lv_task handling*/
  43. lv_task_enable(true);
  44. }
  45. /**
  46. * Call it periodically to handle lv_tasks.
  47. */
  48. LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
  49. {
  50. static uint32_t idle_period_start = 0;
  51. static uint32_t handler_start = 0;
  52. static uint32_t busy_time = 0;
  53. if(lv_task_run == false) return;
  54. handler_start = lv_tick_get();
  55. /* Run all task from the highest to the lowest priority
  56. * If a lower priority task is executed check task again from the highest priority
  57. * but on the priority of executed tasks don't run tasks before the executed*/
  58. lv_task_t * task_interruper = NULL;
  59. lv_task_t * next;
  60. bool end_flag;
  61. do {
  62. end_flag = true;
  63. lv_task_t * act = lv_ll_get_head(&lv_task_ll);
  64. while(act){
  65. /* The task might be deleted if it runs only once ('once = 1')
  66. * So get next element until the current is surely valid*/
  67. next = lv_ll_get_next(&lv_task_ll, act);
  68. /*Here is the interrupter task. Don't execute it again.*/
  69. if(act == task_interruper) {
  70. task_interruper = NULL; /*From this point only task after the interrupter comes, so the interrupter is not interesting anymore*/
  71. act = next;
  72. continue; /*Load the next task*/
  73. }
  74. /*Just try to run the tasks with highest priority.*/
  75. if(act->prio == LV_TASK_PRIO_HIGHEST) {
  76. lv_task_exec(act);
  77. }
  78. /*Tasks with higher priority then the interrupted shall be run in every case*/
  79. else if(task_interruper) {
  80. if(act->prio > task_interruper->prio) {
  81. if(lv_task_exec(act)) {
  82. task_interruper = act; /*Check all tasks again from the highest priority */
  83. end_flag = false;
  84. break;
  85. }
  86. }
  87. }
  88. /* It is no interrupter task or we already reached it earlier.
  89. * Just run the remaining tasks*/
  90. else {
  91. if(lv_task_exec(act)) {
  92. task_interruper = act; /*Check all tasks again from the highest priority */
  93. end_flag = false;
  94. break;
  95. }
  96. }
  97. act = next; /*Load the next task*/
  98. }
  99. } while(!end_flag);
  100. busy_time += lv_tick_elaps(handler_start);
  101. uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
  102. if(idle_period_time >= IDLE_MEAS_PERIOD) {
  103. idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/
  104. idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
  105. busy_time = 0;
  106. idle_period_start = lv_tick_get();
  107. }
  108. }
  109. /**
  110. * Create a new lv_task
  111. * @param task a function which is the task itself
  112. * @param period call period in ms unit
  113. * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
  114. * @param param free parameter
  115. * @return pointer to the new task
  116. */
  117. lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param)
  118. {
  119. lv_task_t* new_lv_task = NULL;
  120. lv_task_t* tmp;
  121. /*Create task lists in order of priority from high to low*/
  122. tmp = lv_ll_get_head(&lv_task_ll);
  123. if(NULL == tmp) { /*First task*/
  124. new_lv_task = lv_ll_ins_head(&lv_task_ll);
  125. }
  126. else{
  127. do{
  128. if(tmp->prio <= prio){
  129. new_lv_task = lv_ll_ins_prev(&lv_task_ll, tmp);
  130. break;
  131. }
  132. tmp = lv_ll_get_next(&lv_task_ll,tmp);
  133. }while(tmp != NULL);
  134. if(tmp == NULL) { /*Only too high priority tasks were found*/
  135. new_lv_task = lv_ll_ins_tail(&lv_task_ll);
  136. }
  137. }
  138. lv_mem_assert(new_lv_task);
  139. new_lv_task->period = period;
  140. new_lv_task->task = task;
  141. new_lv_task->prio = prio;
  142. new_lv_task->param = param;
  143. new_lv_task->once = 0;
  144. new_lv_task->last_run = lv_tick_get();
  145. return new_lv_task;
  146. }
  147. /**
  148. * Delete a lv_task
  149. * @param lv_task_p pointer to task created by lv_task_p
  150. */
  151. void lv_task_del(lv_task_t* lv_task_p)
  152. {
  153. lv_ll_rem(&lv_task_ll, lv_task_p);
  154. lv_mem_free(lv_task_p);
  155. }
  156. /**
  157. * Set new priority for a lv_task
  158. * @param lv_task_p pointer to a lv_task
  159. * @param prio the new priority
  160. */
  161. void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio)
  162. {
  163. /*Find the tasks with new priority*/
  164. lv_task_t * i;
  165. LL_READ(lv_task_ll, i) {
  166. if(i->prio <= prio) {
  167. if(i != lv_task_p) lv_ll_move_before(&lv_task_ll, lv_task_p, i);
  168. break;
  169. }
  170. }
  171. /*There was no such a low priority so far then add the node to the tail*/
  172. if(i == NULL) {
  173. lv_ll_move_before(&lv_task_ll, lv_task_p, NULL);
  174. }
  175. lv_task_p->prio = prio;
  176. }
  177. /**
  178. * Set new period for a lv_task
  179. * @param lv_task_p pointer to a lv_task
  180. * @param period the new period
  181. */
  182. void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period)
  183. {
  184. lv_task_p->period = period;
  185. }
  186. /**
  187. * Make a lv_task ready. It will not wait its period.
  188. * @param lv_task_p pointer to a lv_task.
  189. */
  190. void lv_task_ready(lv_task_t* lv_task_p)
  191. {
  192. lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1;
  193. }
  194. /**
  195. * Delete the lv_task after one call
  196. * @param lv_task_p pointer to a lv_task.
  197. */
  198. void lv_task_once(lv_task_t * lv_task_p)
  199. {
  200. lv_task_p->once = 1;
  201. }
  202. /**
  203. * Reset a lv_task.
  204. * It will be called the previously set period milliseconds later.
  205. * @param lv_task_p pointer to a lv_task.
  206. */
  207. void lv_task_reset(lv_task_t* lv_task_p)
  208. {
  209. lv_task_p->last_run = lv_tick_get();
  210. }
  211. /**
  212. * Enable or disable the whole lv_task handling
  213. * @param en: true: lv_task handling is running, false: lv_task handling is suspended
  214. */
  215. void lv_task_enable(bool en)
  216. {
  217. lv_task_run = en;
  218. }
  219. /**
  220. * Get idle percentage
  221. * @return the lv_task idle in percentage
  222. */
  223. uint8_t lv_task_get_idle(void)
  224. {
  225. return idle_last;
  226. }
  227. /**********************
  228. * STATIC FUNCTIONS
  229. **********************/
  230. /**
  231. * Execute task if its the priority is appropriate
  232. * @param lv_task_p pointer to lv_task
  233. * @return true: execute, false: not executed
  234. */
  235. static bool lv_task_exec (lv_task_t* lv_task_p)
  236. {
  237. bool exec = false;
  238. /*Execute if at least 'period' time elapsed*/
  239. uint32_t elp = lv_tick_elaps(lv_task_p->last_run);
  240. if(elp >= lv_task_p->period) {
  241. lv_task_p->last_run = lv_tick_get();
  242. lv_task_p->task(lv_task_p->param);
  243. /*Delete if it was a one shot lv_task*/
  244. if(lv_task_p->once != 0) lv_task_del(lv_task_p);
  245. exec = true;
  246. }
  247. return exec;
  248. }