refactor(task): rename lv_task to lv_tmr and remove priorities

fixes #1925
This commit is contained in:
Gabor Kiss-Vamosi
2020-11-24 17:56:11 +01:00
parent 77e7fe7fea
commit 6bafb34769
21 changed files with 543 additions and 665 deletions

View File

@@ -27,6 +27,11 @@ extern "C" {
* GLOBAL PROTOTYPES
**********************/
static LV_ATTRIBUTE_TMR_HANDLER uint32_t lv_task_handler(void)
{
return lv_tmr_handler();
}
/**********************
* MACROS
**********************/

View File

@@ -632,11 +632,11 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */
#endif
/* Define a custom attribute to `lv_task_handler` function */
#ifndef LV_ATTRIBUTE_TASK_HANDLER
# ifdef CONFIG_LV_ATTRIBUTE_TASK_HANDLER
# define LV_ATTRIBUTE_TASK_HANDLER CONFIG_LV_ATTRIBUTE_TASK_HANDLER
#ifndef LV_ATTRIBUTE_TMR_HANDLER
# ifdef CONFIG_LV_ATTRIBUTE_TMR_HANDLER
# define LV_ATTRIBUTE_TMR_HANDLER CONFIG_LV_ATTRIBUTE_TMR_HANDLER
# else
# define LV_ATTRIBUTE_TASK_HANDLER
# define LV_ATTRIBUTE_TMR_HANDLER
# endif
#endif

View File

@@ -367,7 +367,7 @@ void lv_disp_clean_dcache(lv_disp_t * disp)
* @param disp pointer to a display
* @return pointer to the display refresher task. (NULL on error)
*/
lv_task_t * _lv_disp_get_refr_task(lv_disp_t * disp)
lv_tmr_t * _lv_disp_get_refr_task(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {

View File

@@ -145,7 +145,7 @@ void lv_disp_clean_dcache(lv_disp_t * disp);
* @param disp pointer to a display
* @return pointer to the display refresher task. (NULL on error)
*/
lv_task_t * _lv_disp_get_refr_task(lv_disp_t * disp);
lv_tmr_t * _lv_disp_get_refr_task(lv_disp_t * disp);
/*------------------------------------------------
* To improve backward compatibility

View File

@@ -14,7 +14,7 @@
#include "lv_refr.h"
#include "../lv_hal/lv_hal_tick.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_tmr.h"
#include "../lv_misc/lv_math.h"
/*********************
@@ -70,7 +70,7 @@ void _lv_indev_init(void)
* Called periodically to read the input devices
* @param param pointer to and input device to read
*/
void _lv_indev_read_task(lv_task_t * task)
void _lv_indev_read_task(lv_tmr_t * task)
{
LV_LOG_TRACE("indev read task started");
@@ -361,7 +361,7 @@ lv_obj_t * lv_indev_get_obj_act(void)
* @param indev pointer to an input device
* @return pointer to the indev read refresher task. (NULL on error)
*/
lv_task_t * lv_indev_get_read_task(lv_disp_t * indev)
lv_tmr_t * lv_indev_get_read_task(lv_disp_t * indev)
{
if(!indev) {
LV_LOG_WARN("lv_indev_get_read_task: indev was NULL");

View File

@@ -38,7 +38,7 @@ void _lv_indev_init(void);
* Called periodically to read the input devices
* @param task pointer to the task itself
*/
void _lv_indev_read_task(lv_task_t * task);
void _lv_indev_read_task(lv_tmr_t * task);
/**
* Get the currently processed input device. Can be used in action functions too.
@@ -171,7 +171,7 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point);
* @param indev pointer to an inout device
* @return pointer to the indev read refresher task. (NULL on error)
*/
lv_task_t * lv_indev_get_read_task(lv_disp_t * indev);
lv_tmr_t * lv_indev_get_read_task(lv_disp_t * indev);
/**********************
* MACROS

View File

@@ -15,7 +15,7 @@
#include "../lv_themes/lv_theme.h"
#include "../lv_draw/lv_draw.h"
#include "../lv_misc/lv_anim.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_tmr.h"
#include "../lv_misc/lv_async.h"
#include "../lv_misc/lv_fs.h"
#include "../lv_misc/lv_gc.h"
@@ -100,7 +100,7 @@ void lv_init(void)
/*Initialize the lv_misc modules*/
_lv_mem_init();
_lv_task_core_init();
_lv_tmr_core_init();
#if LV_USE_FILESYSTEM
_lv_fs_init();

View File

@@ -11,7 +11,7 @@
#include "lv_disp.h"
#include "../lv_hal/lv_hal_tick.h"
#include "../lv_hal/lv_hal_disp.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_tmr.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_gc.h"
@@ -144,7 +144,7 @@ void _lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p)
lv_area_copy(&disp->inv_areas[disp->inv_p], &scr_area);
}
disp->inv_p++;
lv_task_set_prio(disp->refr_task, LV_REFR_TASK_PRIO);
lv_tmr_pause(disp->refr_task, false);
}
}
@@ -172,20 +172,20 @@ void _lv_refr_set_disp_refreshing(lv_disp_t * disp)
* Called periodically to handle the refreshing
* @param task pointer to the task itself
*/
void _lv_disp_refr_task(lv_task_t * task)
void _lv_disp_refr_task(lv_tmr_t * tmr)
{
LV_LOG_TRACE("lv_refr_task: started");
uint32_t start = lv_tick_get();
uint32_t elaps = 0;
disp_refr = task->user_data;
disp_refr = tmr->user_data;
#if LV_USE_PERF_MONITOR == 0
/* Ensure the task does not run again automatically.
* This is done before refreshing in case refreshing invalidates something else.
*/
lv_task_set_prio(task, LV_TASK_PRIO_OFF);
lv_tmr_pause(tmr, true);
#endif
/*Do nothing if there is no active screen*/

View File

@@ -82,7 +82,7 @@ void _lv_refr_set_disp_refreshing(lv_disp_t * disp);
* Called periodically to handle the refreshing
* @param task pointer to the task itself
*/
void _lv_disp_refr_task(lv_task_t * task);
void _lv_disp_refr_task(lv_tmr_t * task);
/**********************
* STATIC FUNCTIONS

View File

@@ -137,7 +137,7 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
disp_def = disp; /*Temporarily change the default screen to create the default screens on the
new display*/
/*Create a refresh task*/
disp->refr_task = lv_task_create(_lv_disp_refr_task, LV_DISP_DEF_REFR_PERIOD, LV_REFR_TASK_PRIO, disp);
disp->refr_task = lv_tmr_create(_lv_disp_refr_task, LV_DISP_DEF_REFR_PERIOD, disp);
LV_ASSERT_MEM(disp->refr_task);
if(disp->refr_task == NULL) return NULL;
@@ -168,7 +168,7 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
disp_def = disp_def_tmp; /*Revert the default display*/
lv_task_ready(disp->refr_task); /*Be sure the screen will be refreshed immediately on start up*/
lv_tmr_ready(disp->refr_task); /*Be sure the screen will be refreshed immediately on start up*/
/*Can't handle this case later so add an error*/
if(lv_disp_is_true_double_buf(disp) && disp->driver.set_px_cb) {

View File

@@ -21,7 +21,7 @@ extern "C" {
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_ll.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_tmr.h"
/*********************
* DEFINES
@@ -149,7 +149,7 @@ typedef struct _disp_t {
lv_disp_drv_t driver;
/**< A task which periodically checks the dirty areas and refreshes them*/
lv_task_t * refr_task;
lv_tmr_t * refr_task;
/** Screens of the display*/
lv_ll_t scr_ll;

View File

@@ -92,7 +92,7 @@ lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)
indev->group = NULL;
indev->btn_points = NULL;
indev->driver.read_task = lv_task_create(_lv_indev_read_task, LV_INDEV_DEF_READ_PERIOD, LV_TASK_PRIO_HIGH, indev);
indev->driver.read_task = lv_tmr_create(_lv_indev_read_task, LV_INDEV_DEF_READ_PERIOD, indev);
return indev;
}

View File

@@ -20,7 +20,7 @@ extern "C" {
#include <stdbool.h>
#include <stdint.h>
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_tmr.h"
/*********************
* DEFINES
@@ -100,7 +100,7 @@ typedef struct _lv_indev_drv_t {
struct _disp_t * disp;
/**< Task to read the periodically read the input device*/
lv_task_t * read_task;
lv_tmr_t * read_task;
/**< Number of pixels to slide before actually drag the object*/
uint8_t scroll_limit;

View File

@@ -13,7 +13,7 @@
#include <string.h>
#include "../lv_misc/lv_debug.h"
#include "../lv_hal/lv_hal_tick.h"
#include "lv_task.h"
#include "lv_tmr.h"
#include "lv_math.h"
#include "lv_gc.h"
@@ -26,7 +26,6 @@
*********************/
#define LV_ANIM_RESOLUTION 1024
#define LV_ANIM_RES_SHIFT 10
#define LV_ANIM_TASK_PRIO LV_TASK_PRIO_HIGH
/**********************
* TYPEDEFS
@@ -35,7 +34,7 @@
/**********************
* STATIC PROTOTYPES
**********************/
static void anim_task(lv_task_t * param);
static void anim_task(lv_tmr_t * param);
static void anim_mark_list_change(void);
static bool anim_ready_handler(lv_anim_t * a);
@@ -44,7 +43,7 @@ static bool anim_ready_handler(lv_anim_t * a);
**********************/
static uint32_t last_task_run;
static bool anim_list_changed;
static lv_task_t * _lv_anim_task;
static lv_tmr_t * _lv_anim_tmr;
const lv_anim_path_t lv_anim_path_def = {.cb = lv_anim_path_linear};
/**********************
@@ -62,7 +61,7 @@ void _lv_anim_core_init(void)
{
_lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t));
last_task_run = lv_tick_get();
_lv_anim_task = lv_task_create(anim_task, LV_DISP_DEF_REFR_PERIOD, LV_ANIM_TASK_PRIO, NULL);
_lv_anim_tmr = lv_tmr_create(anim_task, LV_DISP_DEF_REFR_PERIOD, NULL);
anim_mark_list_change(); /*Turn off the animation task*/
anim_list_changed = false; /*The list has not actually changed*/
}
@@ -439,7 +438,7 @@ lv_anim_value_t lv_anim_path_step(const lv_anim_path_t * path, const lv_anim_t *
* Periodically handle the animations.
* @param param unused
*/
static void anim_task(lv_task_t * param)
static void anim_task(lv_tmr_t * param)
{
(void)param;
@@ -555,8 +554,8 @@ static void anim_mark_list_change(void)
{
anim_list_changed = true;
if(_lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)) == NULL)
lv_task_set_prio(_lv_anim_task, LV_TASK_PRIO_OFF);
lv_tmr_pause(_lv_anim_tmr, true);
else
lv_task_set_prio(_lv_anim_task, LV_ANIM_TASK_PRIO);
lv_tmr_pause(_lv_anim_tmr, false);
}
#endif

View File

@@ -21,7 +21,7 @@
* STATIC PROTOTYPES
**********************/
static void lv_async_task_cb(lv_task_t * task);
static void lv_async_task_cb(lv_tmr_t * task);
/**********************
* STATIC VARIABLES
@@ -45,7 +45,7 @@ lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data)
/* Create a new task */
/* Use highest priority so that it will run before a refresh */
lv_task_t * task = lv_task_create(lv_async_task_cb, 0, LV_TASK_PRIO_HIGHEST, info);
lv_tmr_t * task = lv_tmr_create(lv_async_task_cb, 0, info);
if(task == NULL) {
lv_mem_free(info);
@@ -57,7 +57,7 @@ lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data)
/* Set the task's user data */
task->user_data = info;
lv_task_set_repeat_count(task, 1);
lv_tmr_set_repeat_count(task, 1);
return LV_RES_OK;
}
@@ -65,7 +65,7 @@ lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data)
* STATIC FUNCTIONS
**********************/
static void lv_async_task_cb(lv_task_t * task)
static void lv_async_task_cb(lv_tmr_t * task)
{
lv_async_info_t * info = (lv_async_info_t *)task->user_data;

View File

@@ -14,7 +14,7 @@ extern "C" {
* INCLUDES
*********************/
#include "lv_task.h"
#include "lv_tmr.h"
#include "lv_types.h"
/*********************

View File

@@ -17,7 +17,7 @@ extern "C" {
#include <stdbool.h>
#include "lv_mem.h"
#include "lv_ll.h"
#include "lv_task.h"
#include "lv_tmr.h"
#include "../lv_draw/lv_img_cache.h"
#include "../lv_draw/lv_draw_mask.h"
@@ -26,7 +26,7 @@ extern "C" {
*********************/
#define LV_ITERATE_ROOTS(f) \
f(lv_ll_t, _lv_task_ll) /*Linked list to store the lv_tasks*/ \
f(lv_ll_t, _lv_tmr_ll) /*Linked list to store the lv_tmr-s*/ \
f(lv_ll_t, _lv_disp_ll) /*Linked list of screens*/ \
f(lv_ll_t, _lv_indev_ll) /*Linked list of screens*/ \
f(lv_ll_t, _lv_drv_ll) \
@@ -36,11 +36,10 @@ extern "C" {
f(lv_ll_t, _lv_img_defoder_ll) \
f(lv_ll_t, _lv_obj_style_trans_ll) \
f(lv_img_cache_entry_t*, _lv_img_cache_array) \
f(lv_task_t*, _lv_task_act) \
f(lv_tmr_t*, _lv_tmr_act) \
f(lv_mem_buf_arr_t , _lv_mem_buf) \
f(_lv_draw_mask_saved_arr_t , _lv_draw_mask_list) \
f(void * , _lv_theme_material_styles) \
f(void * , _lv_theme_template_styles) \
f(void * , _lv_theme_mono_styles) \
f(void * , _lv_theme_empty_styles) \
f(uint8_t *, _lv_font_decompr_buf) \

View File

@@ -1,439 +0,0 @@
/**
* @file lv_task.c
* An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically.
* A priority (5 levels + disable) can be assigned to lv_tasks.
*/
/*********************
* INCLUDES
*********************/
#include <stddef.h>
#include "lv_task.h"
#include "../lv_misc/lv_debug.h"
#include "../lv_hal/lv_hal_tick.h"
#include "lv_gc.h"
#if defined(LV_GC_INCLUDE)
#include LV_GC_INCLUDE
#endif /* LV_ENABLE_GC */
/*********************
* DEFINES
*********************/
#define IDLE_MEAS_PERIOD 500 /*[ms]*/
#define DEF_PRIO LV_TASK_PRIO_MID
#define DEF_PERIOD 500
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static bool lv_task_exec(lv_task_t * task);
static uint32_t lv_task_time_remaining(lv_task_t * task);
/**********************
* STATIC VARIABLES
**********************/
static bool lv_task_run = false;
static uint8_t idle_last = 0;
static bool task_deleted;
static bool task_list_changed;
static bool task_created;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Init the lv_task module
*/
void _lv_task_core_init(void)
{
_lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t));
task_list_changed = false;
/*Initially enable the lv_task handling*/
lv_task_enable(true);
}
/**
* Call it periodically to handle lv_tasks.
* @return the time after which it must be called again
*/
LV_ATTRIBUTE_TASK_HANDLER uint32_t lv_task_handler(void)
{
LV_LOG_TRACE("lv_task_handler started");
/*Avoid concurrent running of the task handler*/
static bool already_running = false;
if(already_running) return 1;
already_running = true;
static uint32_t idle_period_start = 0;
static uint32_t handler_start = 0;
static uint32_t busy_time = 0;
static uint32_t time_till_next;
if(lv_task_run == false) {
already_running = false; /*Release mutex*/
return 1;
}
handler_start = lv_tick_get();
/* Run all task from the highest to the lowest priority
* If a lower priority task is executed check task again from the highest priority
* but on the priority of executed tasks don't run tasks before the executed*/
lv_task_t * task_interrupter = NULL;
lv_task_t * next;
bool end_flag;
do {
end_flag = true;
task_deleted = false;
task_created = false;
LV_GC_ROOT(_lv_task_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
while(LV_GC_ROOT(_lv_task_act)) {
/* The task might be deleted if it runs only once ('once = 1')
* So get next element until the current is surely valid*/
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), LV_GC_ROOT(_lv_task_act));
/*We reach priority of the turned off task. There is nothing more to do.*/
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_OFF) {
break;
}
/*Here is the interrupter task. Don't execute it again.*/
if(LV_GC_ROOT(_lv_task_act) == task_interrupter) {
task_interrupter = NULL; /*From this point only task after the interrupter comes, so
the interrupter is not interesting anymore*/
LV_GC_ROOT(_lv_task_act) = next;
continue; /*Load the next task*/
}
/*Just try to run the tasks with highest priority.*/
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) {
lv_task_exec(LV_GC_ROOT(_lv_task_act));
}
/*Tasks with higher priority than the interrupted shall be run in every case*/
else if(task_interrupter) {
if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) {
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
if(!task_created && !task_deleted) {
/*Check all tasks again from the highest priority */
task_interrupter = LV_GC_ROOT(_lv_task_act);
end_flag = false;
break;
}
}
}
}
/* It is no interrupter task or we already reached it earlier.
* Just run the remaining tasks*/
else {
if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {
if(!task_created && !task_deleted) {
task_interrupter = LV_GC_ROOT(_lv_task_act); /*Check all tasks again from the highest priority */
end_flag = false;
break;
}
}
}
/*If a task was created or deleted then this or the next item might be corrupted*/
if(task_created || task_deleted) {
task_interrupter = NULL;
break;
}
if(task_list_changed) {
task_interrupter = NULL;
end_flag = false;
task_list_changed = false;
break;
}
LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/
}
} while(!end_flag);
busy_time += lv_tick_elaps(handler_start);
uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
if(idle_period_time >= IDLE_MEAS_PERIOD) {
idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/
idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
busy_time = 0;
idle_period_start = lv_tick_get();
}
time_till_next = LV_NO_TASK_READY;
next = _lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
while(next) {
if(next->prio != LV_TASK_PRIO_OFF) {
uint32_t delay = lv_task_time_remaining(next);
if(delay < time_till_next)
time_till_next = delay;
}
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), next); /*Find the next task*/
}
already_running = false; /*Release the mutex*/
LV_LOG_TRACE("lv_task_handler ready");
return time_till_next;
}
/**
* Create an "empty" task. It needs to initialized with at least
* `lv_task_set_cb` and `lv_task_set_period`
* @return pointer to the created task
*/
lv_task_t * lv_task_create_basic(void)
{
lv_task_t * new_task = NULL;
lv_task_t * tmp;
/*Create task lists in order of priority from high to low*/
tmp = _lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
/*It's the first task*/
if(NULL == tmp) {
new_task = _lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));
LV_ASSERT_MEM(new_task);
if(new_task == NULL) return NULL;
}
/*Insert the new task to proper place according to its priority*/
else {
do {
if(tmp->prio <= DEF_PRIO) {
new_task = _lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);
LV_ASSERT_MEM(new_task);
if(new_task == NULL) return NULL;
break;
}
tmp = _lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp);
} while(tmp != NULL);
/*Only too high priority tasks were found. Add the task to the end*/
if(tmp == NULL) {
new_task = _lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));
LV_ASSERT_MEM(new_task);
if(new_task == NULL) return NULL;
}
}
task_list_changed = true;
new_task->period = DEF_PERIOD;
new_task->task_cb = NULL;
new_task->prio = DEF_PRIO;
new_task->repeat_count = -1;
new_task->last_run = lv_tick_get();
new_task->user_data = NULL;
task_created = true;
return new_task;
}
/**
* Create a new lv_task
* @param task_xcb a callback which is the task itself. It will be called periodically.
* (the 'x' in the argument name indicates that its not a fully generic function because it not follows
* the `func_name(object, callback, ...)` convention)
* @param period call period in ms unit
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
* @param user_data custom parameter
* @return pointer to the new task
*/
lv_task_t * lv_task_create(lv_task_cb_t task_xcb, uint32_t period, lv_task_prio_t prio, void * user_data)
{
lv_task_t * new_task = lv_task_create_basic();
LV_ASSERT_MEM(new_task);
if(new_task == NULL) return NULL;
lv_task_set_cb(new_task, task_xcb);
lv_task_set_period(new_task, period);
lv_task_set_prio(new_task, prio);
new_task->user_data = user_data;
return new_task;
}
/**
* Set the callback the task (the function to call periodically)
* @param task pointer to a task
* @param task_cb the function to call periodically
*/
void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb)
{
task->task_cb = task_cb;
}
/**
* Delete a lv_task
* @param task pointer to task created by task
*/
void lv_task_del(lv_task_t * task)
{
_lv_ll_remove(&LV_GC_ROOT(_lv_task_ll), task);
task_list_changed = true;
lv_mem_free(task);
if(LV_GC_ROOT(_lv_task_act) == task) task_deleted = true; /*The active task was deleted*/
}
/**
* Set new priority for a lv_task
* @param task pointer to a lv_task
* @param prio the new priority
*/
void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio)
{
if(task->prio == prio) return;
/*Find the tasks with new priority*/
lv_task_t * i;
_LV_LL_READ(&LV_GC_ROOT(_lv_task_ll), i) {
if(i->prio <= prio) {
if(i != task) _lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, i);
break;
}
}
/*There was no such a low priority so far then add the node to the tail*/
if(i == NULL) {
_lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, NULL);
}
task_list_changed = true;
task->prio = prio;
}
/**
* Set new period for a lv_task
* @param task pointer to a lv_task
* @param period the new period
*/
void lv_task_set_period(lv_task_t * task, uint32_t period)
{
task->period = period;
}
/**
* Make a lv_task ready. It will not wait its period.
* @param task pointer to a lv_task.
*/
void lv_task_ready(lv_task_t * task)
{
task->last_run = lv_tick_get() - task->period - 1;
}
/**
* Set the number of times a task will repeat.
* @param task pointer to a lv_task.
* @param repeat_count -1 : infinity; 0 : stop ; n>0: residual times
*/
void lv_task_set_repeat_count(lv_task_t * task, int32_t repeat_count)
{
task->repeat_count = repeat_count;
}
/**
* Reset a lv_task.
* It will be called the previously set period milliseconds later.
* @param task pointer to a lv_task.
*/
void lv_task_reset(lv_task_t * task)
{
task->last_run = lv_tick_get();
}
/**
* Enable or disable the whole lv_task handling
* @param en: true: lv_task handling is running, false: lv_task handling is suspended
*/
void lv_task_enable(bool en)
{
lv_task_run = en;
}
/**
* Get idle percentage
* @return the lv_task idle in percentage
*/
uint8_t lv_task_get_idle(void)
{
return idle_last;
}
/**
* Iterate through the tasks
* @param task NULL to start iteration or the previous return value to get the next task
* @return the next task or NULL if there is no more task
*/
lv_task_t * lv_task_get_next(lv_task_t * task)
{
if(task == NULL) return _lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
else return _lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), task);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Execute task if its the priority is appropriate
* @param task pointer to lv_task
* @return true: execute, false: not executed
*/
static bool lv_task_exec(lv_task_t * task)
{
bool exec = false;
if(lv_task_time_remaining(task) == 0) {
task->last_run = lv_tick_get();
task_deleted = false;
task_created = false;
if(task->task_cb) task->task_cb(task);
LV_ASSERT_MEM_INTEGRITY();
/*Delete if it was a one shot lv_task*/
if(task_deleted == false) { /*The task might be deleted by itself as well*/
if(task->repeat_count > 0) {
task->repeat_count--;
}
if(task->repeat_count == 0) {
lv_task_del(task);
}
}
exec = true;
}
return exec;
}
/**
* Find out how much time remains before a task must be run.
* @param task pointer to lv_task
* @return the time remaining, or 0 if it needs to be run again
*/
static uint32_t lv_task_time_remaining(lv_task_t * task)
{
/*Check if at least 'period' time elapsed*/
uint32_t elp = lv_tick_elaps(task->last_run);
if(elp >= task->period)
return 0;
return task->period - elp;
}

View File

@@ -1,183 +0,0 @@
/**
* @file lv_task.c
* An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically.
* A priority (5 levels + disable) can be assigned to lv_tasks.
*/
#ifndef LV_TASK_H
#define LV_TASK_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_conf_internal.h"
#include <stdint.h>
#include <stdbool.h>
#include "lv_mem.h"
#include "lv_ll.h"
/*********************
* DEFINES
*********************/
#ifndef LV_ATTRIBUTE_TASK_HANDLER
#define LV_ATTRIBUTE_TASK_HANDLER
#endif
#define LV_NO_TASK_READY 0xFFFFFFFF
/**********************
* TYPEDEFS
**********************/
struct _lv_task_t;
/**
* Tasks execute this type type of functions.
*/
typedef void (*lv_task_cb_t)(struct _lv_task_t *);
/**
* Possible priorities for lv_tasks
*/
enum {
LV_TASK_PRIO_OFF = 0,
LV_TASK_PRIO_LOWEST,
LV_TASK_PRIO_LOW,
LV_TASK_PRIO_MID,
LV_TASK_PRIO_HIGH,
LV_TASK_PRIO_HIGHEST,
_LV_TASK_PRIO_NUM,
};
typedef uint8_t lv_task_prio_t;
/**
* Descriptor of a lv_task
*/
typedef struct _lv_task_t {
uint32_t period; /**< How often the task should run */
uint32_t last_run; /**< Last time the task ran */
lv_task_cb_t task_cb; /**< Task function */
void * user_data; /**< Custom user data */
int32_t repeat_count; /**< 1: Task times; -1 : infinity; 0 : stop ; n>0: residual times */
uint8_t prio : 3; /**< Task priority */
} lv_task_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Init the lv_task module
*/
void _lv_task_core_init(void);
//! @cond Doxygen_Suppress
/**
* Call it periodically to handle lv_tasks.
* @return time till it needs to be run next (in ms)
*/
LV_ATTRIBUTE_TASK_HANDLER uint32_t lv_task_handler(void);
//! @endcond
/**
* Create an "empty" task. It needs to initialized with at least
* `lv_task_set_cb` and `lv_task_set_period`
* @return pointer to the created task
*/
lv_task_t * lv_task_create_basic(void);
/**
* Create a new lv_task
* @param task_xcb a callback which is the task itself. It will be called periodically.
* (the 'x' in the argument name indicates that its not a fully generic function because it not follows
* the `func_name(object, callback, ...)` convention)
* @param period call period in ms unit
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
* @param user_data custom parameter
* @return pointer to the new task
*/
lv_task_t * lv_task_create(lv_task_cb_t task_xcb, uint32_t period, lv_task_prio_t prio, void * user_data);
/**
* Delete a lv_task
* @param task pointer to task_cb created by task
*/
void lv_task_del(lv_task_t * task);
/**
* Set the callback the task (the function to call periodically)
* @param task pointer to a task
* @param task_cb the function to call periodically
*/
void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb);
/**
* Set new priority for a lv_task
* @param task pointer to a lv_task
* @param prio the new priority
*/
void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio);
/**
* Set new period for a lv_task
* @param task pointer to a lv_task
* @param period the new period
*/
void lv_task_set_period(lv_task_t * task, uint32_t period);
/**
* Make a lv_task ready. It will not wait its period.
* @param task pointer to a lv_task.
*/
void lv_task_ready(lv_task_t * task);
/**
* Set the number of times a task will repeat.
* @param task pointer to a lv_task.
* @param repeat_count -1 : infinity; 0 : stop ; n>0: residual times
*/
void lv_task_set_repeat_count(lv_task_t * task, int32_t repeat_count);
/**
* Reset a lv_task.
* It will be called the previously set period milliseconds later.
* @param task pointer to a lv_task.
*/
void lv_task_reset(lv_task_t * task);
/**
* Enable or disable the whole lv_task handling
* @param en: true: lv_task handling is running, false: lv_task handling is suspended
*/
void lv_task_enable(bool en);
/**
* Get idle percentage
* @return the lv_task idle in percentage
*/
uint8_t lv_task_get_idle(void);
/**
* Iterate through the tasks
* @param task NULL to start iteration or the previous return value to get the next task
* @return the next task or NULL if there is no more task
*/
lv_task_t * lv_task_get_next(lv_task_t * task);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

340
src/lv_misc/lv_tmr.c Normal file
View File

@@ -0,0 +1,340 @@
/**
* @file lv_tmr.c
*/
/*********************
* INCLUDES
*********************/
#include <stddef.h>
#include "lv_tmr.h"
#include "../lv_misc/lv_debug.h"
#include "../lv_hal/lv_hal_tick.h"
#include "lv_gc.h"
#if defined(LV_GC_INCLUDE)
#include LV_GC_INCLUDE
#endif /* LV_ENABLE_GC */
/*********************
* DEFINES
*********************/
#define IDLE_MEAS_PERIOD 500 /*[ms]*/
#define DEF_PERIOD 500
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static bool lv_tmr_exec(lv_tmr_t * tmr);
static uint32_t lv_tmr_time_remaining(lv_tmr_t * tmr);
/**********************
* STATIC VARIABLES
**********************/
static bool lv_tmr_run = false;
static uint8_t idle_last = 0;
static bool tmr_deleted;
static bool tmr_created;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Init the lv_tmr module
*/
void _lv_tmr_core_init(void)
{
_lv_ll_init(&LV_GC_ROOT(_lv_tmr_ll), sizeof(lv_tmr_t));
/*Initially enable the lv_tmr handling*/
lv_tmr_enable(true);
}
/**
* Call it periodically to handle lv_tmrs.
* @return the time after which it must be called again
*/
LV_ATTRIBUTE_TASK_HANDLER uint32_t lv_tmr_handler(void)
{
LV_LOG_TRACE("lv_tmr_handler started");
/*Avoid concurrent running of the tmr handler*/
static bool already_running = false;
if(already_running) return 1;
already_running = true;
static uint32_t idle_period_start = 0;
static uint32_t handler_start = 0;
static uint32_t busy_time = 0;
static uint32_t time_till_next;
if(lv_tmr_run == false) {
already_running = false; /*Release mutex*/
return 1;
}
handler_start = lv_tick_get();
/* Run all tmr from the highest to the lowest priority
* If a lower priority tmr is executed check tmr again from the highest priority
* but on the priority of executed tmrs don't run tmrs before the executed*/
lv_tmr_t * next;
bool end_flag;
do {
end_flag = true;
tmr_deleted = false;
tmr_created = false;
LV_GC_ROOT(_lv_tmr_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_tmr_ll));
while(LV_GC_ROOT(_lv_tmr_act)) {
/* The tmr might be deleted if it runs only once ('repeat_count = 1')
* So get next element until the current is surely valid*/
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_tmr_ll), LV_GC_ROOT(_lv_tmr_act));
if(lv_tmr_exec(LV_GC_ROOT(_lv_tmr_act))) {
if(!tmr_created && !tmr_deleted) {
end_flag = false;
break;
}
}
/*If a tmr was created or deleted then this or the next item might be corrupted*/
if(tmr_created || tmr_deleted) {
break;
}
LV_GC_ROOT(_lv_tmr_act) = next; /*Load the next tmr*/
}
} while(!end_flag);
busy_time += lv_tick_elaps(handler_start);
uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
if(idle_period_time >= IDLE_MEAS_PERIOD) {
idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD; /*Calculate the busy percentage*/
idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
busy_time = 0;
idle_period_start = lv_tick_get();
}
time_till_next = LV_NO_TMR_READY;
next = _lv_ll_get_head(&LV_GC_ROOT(_lv_tmr_ll));
while(next) {
if(next->repeat_count) {
uint32_t delay = lv_tmr_time_remaining(next);
if(delay < time_till_next)
time_till_next = delay;
}
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_tmr_ll), next); /*Find the next tmr*/
}
already_running = false; /*Release the mutex*/
LV_LOG_TRACE("lv_tmr_handler ready");
return time_till_next;
}
/**
* Create an "empty" tmr. It needs to initialized with at least
* `lv_tmr_set_cb` and `lv_tmr_set_period`
* @return pointer to the created tmr
*/
lv_tmr_t * lv_tmr_create_basic(void)
{
lv_tmr_t * new_tmr = NULL;
new_tmr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_tmr_ll));
LV_ASSERT_MEM(new_tmr);
if(new_tmr == NULL) return NULL;
new_tmr->period = DEF_PERIOD;
new_tmr->tmr_cb = NULL;
new_tmr->repeat_count = -1;
new_tmr->paused = 0;
new_tmr->last_run = lv_tick_get();
new_tmr->user_data = NULL;
tmr_created = true;
return new_tmr;
}
/**
* Create a new lv_tmr
* @param tmr_xcb a callback which is the tmr itself. It will be called periodically.
* (the 'x' in the argument name indicates that its not a fully generic function because it not follows
* the `func_name(object, callback, ...)` convention)
* @param period call period in ms unit
* @param prio priority of the tmr (LV_TASK_PRIO_OFF means the tmr is stopped)
* @param user_data custom parameter
* @return pointer to the new tmr
*/
lv_tmr_t * lv_tmr_create(lv_tmr_cb_t tmr_xcb, uint32_t period, void * user_data)
{
lv_tmr_t * new_tmr = lv_tmr_create_basic();
LV_ASSERT_MEM(new_tmr);
if(new_tmr == NULL) return NULL;
lv_tmr_set_cb(new_tmr, tmr_xcb);
lv_tmr_set_period(new_tmr, period);
new_tmr->user_data = user_data;
return new_tmr;
}
/**
* Set the callback the tmr (the function to call periodically)
* @param tmr pointer to a tmr
* @param tmr_cb the function to call periodically
*/
void lv_tmr_set_cb(lv_tmr_t * tmr, lv_tmr_cb_t tmr_cb)
{
tmr->tmr_cb = tmr_cb;
}
/**
* Delete a lv_tmr
* @param tmr pointer to tmr created by tmr
*/
void lv_tmr_del(lv_tmr_t * tmr)
{
_lv_ll_remove(&LV_GC_ROOT(_lv_tmr_ll), tmr);
tmr_deleted = true;
lv_mem_free(tmr);
}
/**
* Pause/resume a timer.
* @param tmr pointer to an lv_tmr
* @param pause true: pause the timer; false: resume
*/
void lv_tmr_pause(lv_tmr_t * tmr, bool pause)
{
tmr->paused = pause;
}
/**
* Set new period for a lv_tmr
* @param tmr pointer to a lv_tmr
* @param period the new period
*/
void lv_tmr_set_period(lv_tmr_t * tmr, uint32_t period)
{
tmr->period = period;
}
/**
* Make a lv_tmr ready. It will not wait its period.
* @param tmr pointer to a lv_tmr.
*/
void lv_tmr_ready(lv_tmr_t * tmr)
{
tmr->last_run = lv_tick_get() - tmr->period - 1;
}
/**
* Set the number of times a tmr will repeat.
* @param tmr pointer to a lv_tmr.
* @param repeat_count -1 : infinity; 0 : stop ; n >0: residual times
*/
void lv_tmr_set_repeat_count(lv_tmr_t * tmr, int32_t repeat_count)
{
tmr->repeat_count = repeat_count;
}
/**
* Reset a lv_tmr.
* It will be called the previously set period milliseconds later.
* @param tmr pointer to a lv_tmr.
*/
void lv_tmr_reset(lv_tmr_t * tmr)
{
tmr->last_run = lv_tick_get();
}
/**
* Enable or disable the whole lv_tmr handling
* @param en: true: lv_tmr handling is running, false: lv_tmr handling is suspended
*/
void lv_tmr_enable(bool en)
{
lv_tmr_run = en;
}
/**
* Get idle percentage
* @return the lv_tmr idle in percentage
*/
uint8_t lv_tmr_get_idle(void)
{
return idle_last;
}
/**
* Iterate through the tmrs
* @param tmr NULL to start iteration or the previous return value to get the next tmr
* @return the next tmr or NULL if there is no more tmr
*/
lv_tmr_t * lv_tmr_get_next(lv_tmr_t * tmr)
{
if(tmr == NULL) return _lv_ll_get_head(&LV_GC_ROOT(_lv_tmr_ll));
else return _lv_ll_get_next(&LV_GC_ROOT(_lv_tmr_ll), tmr);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Execute tmr if its the priority is appropriate
* @param tmr pointer to lv_tmr
* @return true: execute, false: not executed
*/
static bool lv_tmr_exec(lv_tmr_t * tmr)
{
if(tmr->paused) return false;
bool exec = false;
if(lv_tmr_time_remaining(tmr) == 0) {
tmr->last_run = lv_tick_get();
tmr_deleted = false;
tmr_created = false;
if(tmr->tmr_cb) tmr->tmr_cb(tmr);
LV_ASSERT_MEM_INTEGRITY();
/*Delete if it was a one shot lv_tmr*/
if(tmr_deleted == false) { /*The tmr might be deleted by itself as well*/
if(tmr->repeat_count > 0) {
tmr->repeat_count--;
}
if(tmr->repeat_count == 0) {
lv_tmr_del(tmr);
}
}
exec = true;
}
return exec;
}
/**
* Find out how much time remains before a tmr must be run.
* @param tmr pointer to lv_tmr
* @return the time remaining, or 0 if it needs to be run again
*/
static uint32_t lv_tmr_time_remaining(lv_tmr_t * tmr)
{
/*Check if at least 'period' time elapsed*/
uint32_t elp = lv_tick_elaps(tmr->last_run);
if(elp >= tmr->period)
return 0;
return tmr->period - elp;
}

157
src/lv_misc/lv_tmr.h Normal file
View File

@@ -0,0 +1,157 @@
/**
* @file lv_tmr.h
*/
#ifndef LV_TMR_H
#define LV_TMR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_conf_internal.h"
#include <stdint.h>
#include <stdbool.h>
#include "lv_mem.h"
#include "lv_ll.h"
/*********************
* DEFINES
*********************/
#ifndef LV_ATTRIBUTE_TMR_HANDLER
#define LV_ATTRIBUTE_TMR_HANDLER
#endif
#define LV_NO_TMR_READY 0xFFFFFFFF
/**********************
* TYPEDEFS
**********************/
struct _lv_tmr_t;
/**
* Tasks execute this type type of functions.
*/
typedef void (*lv_tmr_cb_t)(struct _lv_tmr_t *);
/**
* Descriptor of a lv_tmr
*/
typedef struct _lv_tmr_t {
uint32_t period; /**< How often the tmr should run */
uint32_t last_run; /**< Last time the tmr ran */
lv_tmr_cb_t tmr_cb; /**< Task function */
void * user_data; /**< Custom user data */
int32_t repeat_count; /**< 1: One time; -1 : infinity; n>0: residual times */
uint32_t paused :1;
} lv_tmr_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Init the lv_tmr module
*/
void _lv_tmr_core_init(void);
//! @cond Doxygen_Suppress
/**
* Call it periodically to handle lv_tmrs.
* @return time till it needs to be run next (in ms)
*/
LV_ATTRIBUTE_TMR_HANDLER uint32_t lv_tmr_handler(void);
//! @endcond
/**
* Create an "empty" tmr. It needs to initialized with at least
* `lv_tmr_set_cb` and `lv_tmr_set_period`
* @return pointer to the created tmr
*/
lv_tmr_t * lv_tmr_create_basic(void);
/**
* Create a new lv_tmr
* @param tmr_xcb a callback to call periodically.
* (the 'x' in the argument name indicates that its not a fully generic function because it not follows
* the `func_name(object, callback, ...)` convention)
* @param period call period in ms unit
* @param user_data custom parameter
* @return pointer to the new timer
*/
lv_tmr_t * lv_tmr_create(lv_tmr_cb_t tmr_xcb, uint32_t period, void * user_data);
/**
* Delete a lv_tmr
* @param tmr pointer to an lv_tmr
*/
void lv_tmr_del(lv_tmr_t * tmr);
/**
* Pause/resume a timer.
* @param tmr pointer to an lv_tmr
* @param pause true: pause the timer; false: resume
*/
void lv_tmr_pause(lv_tmr_t * tmr, bool pause);
/**
* Set the callback the tmr (the function to call periodically)
* @param tmr pointer to a tmr
* @param tmr_cb the function to call periodically
*/
void lv_tmr_set_cb(lv_tmr_t * tmr, lv_tmr_cb_t tmr_cb);
/**
* Make a lv_tmr ready. It will not wait its period.
* @param tmr pointer to a lv_tmr.
*/
void lv_tmr_ready(lv_tmr_t * tmr);
/**
* Set the number of times a tmr will repeat.
* @param tmr pointer to a lv_tmr.
* @param repeat_count -1 : infinity; 0 : stop ; n>0: residual times
*/
void lv_tmr_set_repeat_count(lv_tmr_t * tmr, int32_t repeat_count);
/**
* Reset a lv_tmr.
* It will be called the previously set period milliseconds later.
* @param tmr pointer to a lv_tmr.
*/
void lv_tmr_reset(lv_tmr_t * tmr);
/**
* Enable or disable the whole lv_tmr handling
* @param en: true: lv_tmr handling is running, false: lv_tmr handling is suspended
*/
void lv_tmr_enable(bool en);
/**
* Get idle percentage
* @return the lv_tmr idle in percentage
*/
uint8_t lv_tmr_get_idle(void);
/**
* Iterate through the tmrs
* @param tmr NULL to start iteration or the previous return value to get the next tmr
* @return the next tmr or NULL if there is no more tmr
*/
lv_tmr_t * lv_tmr_get_next(lv_tmr_t * tmr);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif