diff options
Diffstat (limited to 'src/libs/lvgl/src/lv_misc')
39 files changed, 3968 insertions, 1975 deletions
diff --git a/src/libs/lvgl/src/lv_misc/lv_anim.c b/src/libs/lvgl/src/lv_misc/lv_anim.c index 77bd87b9..4b01b805 100644 --- a/src/libs/lvgl/src/lv_misc/lv_anim.c +++ b/src/libs/lvgl/src/lv_misc/lv_anim.c @@ -11,21 +11,18 @@ #if LV_USE_ANIMATION #include <stddef.h> #include <string.h> -#include "../lv_core/lv_debug.h" +#include "../lv_misc/lv_debug.h" #include "../lv_hal/lv_hal_tick.h" #include "lv_task.h" #include "lv_math.h" #include "lv_gc.h" -#if defined(LV_GC_INCLUDE) -#include LV_GC_INCLUDE -#endif /* LV_ENABLE_GC */ - /********************* * DEFINES *********************/ #define LV_ANIM_RESOLUTION 1024 #define LV_ANIM_RES_SHIFT 10 +#define LV_ANIM_TASK_PRIO LV_TASK_PRIO_HIGH /********************** * TYPEDEFS @@ -35,6 +32,7 @@ * STATIC PROTOTYPES **********************/ static void anim_task(lv_task_t * param); +static void anim_mark_list_change(void); static bool anim_ready_handler(lv_anim_t * a); /********************** @@ -42,6 +40,8 @@ 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; +const lv_anim_path_t lv_anim_path_def = {.cb = lv_anim_path_linear}; /********************** * MACROS @@ -54,11 +54,13 @@ static bool anim_list_changed; /** * Init. the animation module */ -void lv_anim_core_init(void) +void _lv_anim_core_init(void) { - lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t)); + _lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t)); last_task_run = lv_tick_get(); - lv_task_create(anim_task, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, NULL); + _lv_anim_task = lv_task_create(anim_task, LV_DISP_DEF_REFR_PERIOD, LV_ANIM_TASK_PRIO, NULL); + anim_mark_list_change(); /*Turn off the animation task*/ + anim_list_changed = false; /*The list has not actually changed*/ } /** @@ -67,42 +69,50 @@ void lv_anim_core_init(void) * lv_anim_t a; * lv_anim_init(&a); * lv_anim_set_...(&a); - * lv_anim_craete(&a); * @param a pointer to an `lv_anim_t` variable to initialize */ void lv_anim_init(lv_anim_t * a) { - memset(a, 0, sizeof(lv_anim_t)); + _lv_memset_00(a, sizeof(lv_anim_t)); a->time = 500; a->start = 0; a->end = 100; - a->path_cb = lv_anim_path_linear; + _lv_memcpy_small(&a->path, &lv_anim_path_def, sizeof(lv_anim_path_cb_t)); + a->repeat_cnt = 1; + a->early_apply = 1; } /** * Create an animation * @param a an initialized 'anim_t' variable. Not required after call. */ -void lv_anim_create(lv_anim_t * a) +void lv_anim_start(lv_anim_t * a) { LV_LOG_TRACE("animation create started") - /* Do not let two animations for the same 'var' with the same 'fp'*/ + /* Do not let two animations for the same 'var' with the same 'fp'*/ if(a->exec_cb != NULL) lv_anim_del(a->var, a->exec_cb); /*fp == NULL would delete all animations of var*/ + /*If the list is empty the anim task was suspended and it's last run measure is invalid*/ + if(_lv_ll_is_empty(&LV_GC_ROOT(_lv_anim_ll))) { + last_task_run = lv_tick_get() - 1; + } + /*Add the new animation to the animation linked list*/ - lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll)); + lv_anim_t * new_anim = _lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll)); LV_ASSERT_MEM(new_anim); if(new_anim == NULL) return; /*Initialize the animation descriptor*/ - a->playback_now = 0; - memcpy(new_anim, a, sizeof(lv_anim_t)); + a->time_orig = a->time; + _lv_memcpy(new_anim, a, sizeof(lv_anim_t)); /*Set the start value*/ - if(new_anim->exec_cb) new_anim->exec_cb(new_anim->var, new_anim->start); + if(new_anim->early_apply) { + if(new_anim->exec_cb && new_anim->var) new_anim->exec_cb(new_anim->var, new_anim->start); + } /* Creating an animation changed the linked list. * It's important if it happens in a ready callback. (see `anim_task`)*/ - anim_list_changed = true; + anim_mark_list_change(); LV_LOG_TRACE("animation created") } @@ -119,15 +129,15 @@ bool lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb) lv_anim_t * a; lv_anim_t * a_next; bool del = false; - a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + a = _lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); while(a != NULL) { /*'a' might be deleted, so get the next object while 'a' is valid*/ - a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); + a_next = _lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); if(a->var == var && (a->exec_cb == exec_cb || exec_cb == NULL)) { - lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); + _lv_ll_remove(&LV_GC_ROOT(_lv_anim_ll), a); lv_mem_free(a); - anim_list_changed = true; /*Read by `anim_task`. It need to know if a delete occurred in + anim_mark_list_change(); /*Read by `anim_task`. It need to know if a delete occurred in the linked list*/ del = true; } @@ -139,6 +149,25 @@ bool lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb) } /** + * Get the animation of a variable and its `exec_cb`. + * @param var pointer to variable + * @param exec_cb a function pointer which is animating 'var', + * or NULL to delete all the animations of 'var' + * @return pointer to the animation. + */ +lv_anim_t * lv_anim_get(void * var, lv_anim_exec_xcb_t exec_cb) +{ + lv_anim_t * a; + _LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) { + if(a->var == var && a->exec_cb == exec_cb) { + return a; + } + } + + return NULL; +} + +/** * Get the number of currently running animations * @return the number of running animations */ @@ -146,9 +175,9 @@ uint16_t lv_anim_count_running(void) { uint16_t cnt = 0; lv_anim_t * a; - LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) cnt++; + _LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) cnt++; - return cnt++; + return cnt; } /** @@ -158,12 +187,12 @@ uint16_t lv_anim_count_running(void) * @param end end value of the animation * @return the required time [ms] for the animation with the given parameters */ -uint32_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end) +uint16_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end) { int32_t d = LV_MATH_ABS((int32_t)start - end); uint32_t time = (int32_t)((int32_t)(d * 1000) / speed); - if(time > UINT32_MAX) time = UINT32_MAX; + if(time > UINT16_MAX) time = UINT16_MAX; if(time == 0) { time++; @@ -173,17 +202,31 @@ uint32_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_va } /** + * Manually refresh the state of the animations. + * Useful to make the animations running in a blocking process where + * `lv_task_handler` can't run for a while. + * Shouldn't be used directly because it is called in `lv_refr_now()`. + */ +void lv_anim_refr_now(void) +{ + anim_task(NULL); +} + +/** * Calculate the current value of an animation applying linear characteristic * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_linear(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_linear(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + /*Calculate the current step*/ uint32_t step; if(a->time == a->act_time) { step = LV_ANIM_RESOLUTION; /*Use the last value if the time fully elapsed*/ - } else { + } + else { step = ((int32_t)a->act_time * LV_ANIM_RESOLUTION) / a->time; } @@ -202,8 +245,10 @@ lv_anim_value_t lv_anim_path_linear(const lv_anim_t * a) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_ease_in(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_ease_in(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + /*Calculate the current step*/ uint32_t t; if(a->time == a->act_time) @@ -211,7 +256,7 @@ lv_anim_value_t lv_anim_path_ease_in(const lv_anim_t * a) else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; - int32_t step = lv_bezier3(t, 0, 1, 1, 1024); + int32_t step = _lv_bezier3(t, 0, 1, 1, 1024); int32_t new_value; new_value = (int32_t)step * (a->end - a->start); @@ -226,8 +271,10 @@ lv_anim_value_t lv_anim_path_ease_in(const lv_anim_t * a) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_ease_out(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_ease_out(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + /*Calculate the current step*/ uint32_t t; @@ -236,7 +283,7 @@ lv_anim_value_t lv_anim_path_ease_out(const lv_anim_t * a) else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; - int32_t step = lv_bezier3(t, 0, 1023, 1023, 1024); + int32_t step = _lv_bezier3(t, 0, 1023, 1023, 1024); int32_t new_value; new_value = (int32_t)step * (a->end - a->start); @@ -251,8 +298,10 @@ lv_anim_value_t lv_anim_path_ease_out(const lv_anim_t * a) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + /*Calculate the current step*/ uint32_t t; @@ -261,7 +310,7 @@ lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_t * a) else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; - int32_t step = lv_bezier3(t, 0, 100, 924, 1024); + int32_t step = _lv_bezier3(t, 0, 100, 924, 1024); int32_t new_value; new_value = (int32_t)step * (a->end - a->start); @@ -276,8 +325,10 @@ lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_t * a) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_overshoot(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_overshoot(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + /*Calculate the current step*/ uint32_t t; @@ -286,7 +337,7 @@ lv_anim_value_t lv_anim_path_overshoot(const lv_anim_t * a) else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; - int32_t step = lv_bezier3(t, 0, 600, 1300, 1024); + int32_t step = _lv_bezier3(t, 0, 1000, 1300, 1024); int32_t new_value; new_value = (int32_t)step * (a->end - a->start); @@ -301,10 +352,12 @@ lv_anim_value_t lv_anim_path_overshoot(const lv_anim_t * a) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_bounce(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + /*Calculate the current step*/ - uint32_t t; + int32_t t; if(a->time == a->act_time) t = 1024; else @@ -317,33 +370,38 @@ lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a) if(t < 408) { /*Go down*/ t = (t * 2500) >> 10; /*[0..1024] range*/ - } else if(t >= 408 && t < 614) { + } + else if(t >= 408 && t < 614) { /*First bounce back*/ t -= 408; t = t * 5; /*to [0..1024] range*/ t = 1024 - t; - diff = diff / 6; - } else if(t >= 614 && t < 819) { + diff = diff / 20; + } + else if(t >= 614 && t < 819) { /*Fall back*/ t -= 614; t = t * 5; /*to [0..1024] range*/ - diff = diff / 6; - } else if(t >= 819 && t < 921) { + diff = diff / 20; + } + else if(t >= 819 && t < 921) { /*Second bounce back*/ t -= 819; t = t * 10; /*to [0..1024] range*/ t = 1024 - t; - diff = diff / 16; - } else if(t >= 921 && t <= 1024) { + diff = diff / 40; + } + else if(t >= 921 && t <= 1024) { /*Fall back*/ t -= 921; t = t * 10; /*to [0..1024] range*/ - diff = diff / 16; + diff = diff / 40; } if(t > 1024) t = 1024; + if(t < 0) t = 0; - int32_t step = lv_bezier3(t, 1024, 1024, 800, 0); + int32_t step = _lv_bezier3(t, 1024, 800, 500, 0); int32_t new_value; new_value = (int32_t)step * diff; @@ -359,8 +417,10 @@ lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_step(const lv_anim_t * a) +lv_anim_value_t lv_anim_path_step(const lv_anim_path_t * path, const lv_anim_t * a) { + LV_UNUSED(path); + if(a->act_time >= a->time) return a->end; else @@ -380,14 +440,13 @@ static void anim_task(lv_task_t * param) (void)param; lv_anim_t * a; - LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) - { + _LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) { a->has_run = 0; } uint32_t elaps = lv_tick_elaps(last_task_run); - a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + a = _lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); while(a != NULL) { /*It can be set by `lv_anim_del()` typically in `end_cb`. If set then an animation delete @@ -397,16 +456,26 @@ static void anim_task(lv_task_t * param) anim_list_changed = false; if(!a->has_run) { - a->has_run = 1; /*The list readying might be reseted so need to know which anim has run already*/ + a->has_run = 1; /*The list readying might be reset so need to know which anim has run already*/ + + /*The animation will run now for the first time. Call `start_cb`*/ + int32_t new_act_time = a->act_time + elaps; + if(a->act_time <= 0 && new_act_time >= 0) { + if(a->start_cb) a->start_cb(a); + } a->act_time += elaps; if(a->act_time >= 0) { if(a->act_time > a->time) a->act_time = a->time; int32_t new_value; - new_value = a->path_cb(a); + if(a->path.cb) new_value = a->path.cb(&a->path, a); + else new_value = lv_anim_path_linear(&a->path, a); - /*Apply the calculated value*/ - if(a->exec_cb) a->exec_cb(a->var, new_value); + if(new_value != a->current) { + a->current = new_value; + /*Apply the calculated value*/ + if(a->exec_cb) a->exec_cb(a->var, new_value); + } /*If the time is elapsed the animation is ready*/ if(a->act_time >= a->time) { @@ -418,9 +487,9 @@ static void anim_task(lv_task_t * param) /* If the linked list changed due to anim. delete then it's not safe to continue * the reading of the list from here -> start from the head*/ if(anim_list_changed) - a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); + a = _lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll)); else - a = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); + a = _lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); } last_task_run = lv_tick_get(); @@ -430,34 +499,39 @@ static void anim_task(lv_task_t * param) * Called when an animation is ready to do the necessary thinks * e.g. repeat, play back, delete etc. * @param a pointer to an animation descriptor - * @return true: animation delete occurred nnd the `LV_GC_ROOT(_lv_anim_ll)` has changed + * @return true: animation delete occurred and the `LV_GC_ROOT(_lv_anim_ll)` has changed * */ static bool anim_ready_handler(lv_anim_t * a) { + /*In the end of a forward anim decrement repeat cnt.*/ + if(a->playback_now == 0 && a->repeat_cnt > 0 && a->repeat_cnt != LV_ANIM_REPEAT_INFINITE) { + a->repeat_cnt--; + } /*Delete the animation if - * - no repeat and no play back (simple one shot animation) + * - no repeat left and no play back (simple one shot animation) * - no repeat, play back is enabled and play back is ready */ - if((a->repeat == 0 && a->playback == 0) || (a->repeat == 0 && a->playback == 1 && a->playback_now == 1)) { + if(a->repeat_cnt == 0 && ((a->playback_time == 0) || (a->playback_time && a->playback_now == 1))) { /*Create copy from the animation and delete the animation from the list. * This way the `ready_cb` will see the animations like it's animation is ready deleted*/ lv_anim_t a_tmp; - memcpy(&a_tmp, a, sizeof(lv_anim_t)); - lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); + _lv_memcpy(&a_tmp, a, sizeof(lv_anim_t)); + _lv_ll_remove(&LV_GC_ROOT(_lv_anim_ll), a); lv_mem_free(a); - anim_list_changed = true; + /*Flag that the list has changed */ + anim_mark_list_change(); /* Call the callback function at the end*/ if(a_tmp.ready_cb != NULL) a_tmp.ready_cb(&a_tmp); } /*If the animation is not deleted then restart it*/ else { - a->act_time = -a->repeat_pause; /*Restart the animation*/ + a->act_time = -(int32_t)(a->repeat_delay); /*Restart the animation*/ /*Swap the start and end values in play back mode*/ - if(a->playback != 0) { + if(a->playback_time != 0) { /*If now turning back use the 'playback_pause*/ - if(a->playback_now == 0) a->act_time = -a->playback_pause; + if(a->playback_now == 0) a->act_time = -(int32_t)(a->playback_delay); /*Toggle the play back state*/ a->playback_now = a->playback_now == 0 ? 1 : 0; @@ -466,9 +540,19 @@ static bool anim_ready_handler(lv_anim_t * a) tmp = a->start; a->start = a->end; a->end = tmp; + + a->time = a->playback_now == 0 ? a->time_orig : a->playback_time; } } return anim_list_changed; } +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); + else + lv_task_set_prio(_lv_anim_task, LV_ANIM_TASK_PRIO); +} #endif diff --git a/src/libs/lvgl/src/lv_misc/lv_anim.h b/src/libs/lvgl/src/lv_misc/lv_anim.h index b43035aa..54baf596 100644 --- a/src/libs/lvgl/src/lv_misc/lv_anim.h +++ b/src/libs/lvgl/src/lv_misc/lv_anim.h @@ -13,15 +13,12 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include <stdint.h> #include <stdbool.h> #include <string.h> +#include "lv_mem.h" /********************* * DEFINES @@ -44,7 +41,17 @@ typedef lv_coord_t lv_anim_value_t; #if LV_USE_ANIMATION +#define LV_ANIM_REPEAT_INFINITE 0xFFFF + struct _lv_anim_t; +struct _lv_anim_path_t; +/** Get the current value during an animation*/ +typedef lv_anim_value_t (*lv_anim_path_cb_t)(const struct _lv_anim_path_t *, const struct _lv_anim_t *); + +typedef struct _lv_anim_path_t { + lv_anim_path_cb_t cb; + void * user_data; +} lv_anim_path_t; /** Generic prototype of "animator" functions. * First parameter is the variable to animate. @@ -58,37 +65,39 @@ typedef void (*lv_anim_exec_xcb_t)(void *, lv_anim_value_t); * It's more consistent but less convenient. Might be used by binding generator functions.*/ typedef void (*lv_anim_custom_exec_cb_t)(struct _lv_anim_t *, lv_anim_value_t); -/** Get the current value during an animation*/ -typedef lv_anim_value_t (*lv_anim_path_cb_t)(const struct _lv_anim_t *); - /** Callback to call when the animation is ready*/ typedef void (*lv_anim_ready_cb_t)(struct _lv_anim_t *); +/** Callback to call when the animation really stars (considering `delay`)*/ +typedef void (*lv_anim_start_cb_t)(struct _lv_anim_t *); + /** Describes an animation*/ -typedef struct _lv_anim_t -{ +typedef struct _lv_anim_t { void * var; /**<Variable to animate*/ lv_anim_exec_xcb_t exec_cb; /**< Function to execute to animate*/ - lv_anim_path_cb_t path_cb; /**< Function to get the steps of animations*/ + lv_anim_start_cb_t start_cb; /**< Call it when the animation is starts (considering `delay`)*/ lv_anim_ready_cb_t ready_cb; /**< Call it when the animation is ready*/ + lv_anim_path_t path; /**< Describe the path (curve) of animations*/ int32_t start; /**< Start value*/ + int32_t current; /**< Current value */ int32_t end; /**< End value*/ - uint32_t time; /**< Animation time in ms*/ + int32_t time; /**< Animation time in ms*/ int32_t act_time; /**< Current time in animation. Set to negative to make delay.*/ - uint16_t playback_pause; /**< Wait before play back*/ - uint16_t repeat_pause; /**< Wait before repeat*/ + uint32_t playback_delay; /**< Wait before play back*/ + uint32_t playback_time; /**< Duration of playback animation*/ + uint32_t repeat_delay; /**< Wait before repeat*/ + uint16_t repeat_cnt; /**< Repeat count for the animation*/ + uint8_t early_apply : 1; /**< 1: Apply start value immediately even is there is `delay` */ #if LV_USE_USER_DATA lv_anim_user_data_t user_data; /**< Custom user data*/ #endif - uint8_t playback : 1; /**< When the animation is ready play it back*/ - uint8_t repeat : 1; /**< Repeat the animation infinitely*/ /*Animation system use these - user shouldn't set*/ + uint32_t time_orig; uint8_t playback_now : 1; /**< Play back is in progress*/ uint32_t has_run : 1; /**< Indicates the animation has run in this round*/ } lv_anim_t; - /********************** * GLOBAL PROTOTYPES **********************/ @@ -96,7 +105,7 @@ typedef struct _lv_anim_t /** * Init. the animation module */ -void lv_anim_core_init(void); +void _lv_anim_core_init(void); /** * Initialize an animation variable. @@ -104,35 +113,50 @@ void lv_anim_core_init(void); * lv_anim_t a; * lv_anim_init(&a); * lv_anim_set_...(&a); - * lv_anim_create(&a); * @param a pointer to an `lv_anim_t` variable to initialize */ void lv_anim_init(lv_anim_t * a); /** - * Set a variable to animate function to execute on `var` + * Set a variable to animate * @param a pointer to an initialized `lv_anim_t` variable * @param var pointer to a variable to animate - * @param exec_cb a function to execute. + */ +static inline void lv_anim_set_var(lv_anim_t * a, void * var) +{ + a->var = var; +} + +/** + * Set a function to animate `var` + * @param a pointer to an initialized `lv_anim_t` variable + * @param exec_cb a function to execute during animation * LittelvGL's built-in functions can be used. * E.g. lv_obj_set_x */ -static inline void lv_anim_set_exec_cb(lv_anim_t * a, void * var, lv_anim_exec_xcb_t exec_cb) +static inline void lv_anim_set_exec_cb(lv_anim_t * a, lv_anim_exec_xcb_t exec_cb) { - a->var = var; a->exec_cb = exec_cb; } /** - * Set the duration and delay of an animation + * Set the duration of an animation * @param a pointer to an initialized `lv_anim_t` variable * @param duration duration of the animation in milliseconds - * @param delay delay before the animation in milliseconds */ -static inline void lv_anim_set_time(lv_anim_t * a, uint16_t duration, int16_t delay) +static inline void lv_anim_set_time(lv_anim_t * a, uint32_t duration) { a->time = duration; - a->act_time = (int16_t)(-delay); +} + +/** + * Set a delay before starting the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param delay delay before the animation in milliseconds + */ +static inline void lv_anim_set_delay(lv_anim_t * a, uint32_t delay) +{ + a->act_time = -(int32_t)(delay); } /** @@ -144,14 +168,16 @@ static inline void lv_anim_set_time(lv_anim_t * a, uint16_t duration, int16_t de static inline void lv_anim_set_values(lv_anim_t * a, lv_anim_value_t start, lv_anim_value_t end) { a->start = start; + a->current = start; a->end = end; } /** - * Similar to `lv_anim_set_var_and_cb` but `lv_anim_custom_exec_cb_t` receives + * Similar to `lv_anim_set_exec_cb` but `lv_anim_custom_exec_cb_t` receives * `lv_anim_t * ` as its first parameter instead of `void *`. - * This function might be used when LittlevGL is binded to other languages because + * This function might be used when LVGL is binded to other languages because * it's more consistent to have `lv_anim_t *` as first parameter. + * The variable to animate can be stored in the animation's `user_sata` * @param a pointer to an initialized `lv_anim_t` variable * @param exec_cb a function to execute. */ @@ -167,9 +193,19 @@ static inline void lv_anim_set_custom_exec_cb(lv_anim_t * a, lv_anim_custom_exec * @param path_cb a function the get the current value of the animation. * The built in functions starts with `lv_anim_path_...` */ -static inline void lv_anim_set_path_cb(lv_anim_t * a, lv_anim_path_cb_t path_cb) +static inline void lv_anim_set_path(lv_anim_t * a, const lv_anim_path_t * path) +{ + _lv_memcpy_small(&a->path, path, sizeof(lv_anim_path_t)); +} + +/** + * Set a function call when the animation really starts (considering `delay`) + * @param a pointer to an initialized `lv_anim_t` variable + * @param start_cb a function call when the animation starts + */ +static inline void lv_anim_set_start_cb(lv_anim_t * a, lv_anim_ready_cb_t start_cb) { - a->path_cb = path_cb; + a->start_cb = start_cb; } /** @@ -185,48 +221,87 @@ static inline void lv_anim_set_ready_cb(lv_anim_t * a, lv_anim_ready_cb_t ready_ /** * Make the animation to play back to when the forward direction is ready * @param a pointer to an initialized `lv_anim_t` variable - * @param wait_time time in milliseconds to wait before starting the back direction + * @param time the duration of the playback animation in in milliseconds. 0: disable playback */ -static inline void lv_anim_set_playback(lv_anim_t * a, uint16_t wait_time) +static inline void lv_anim_set_playback_time(lv_anim_t * a, uint16_t time) { - a->playback = 1; - a->playback_pause = wait_time; + a->playback_time = time; } /** - * Disable playback. (Disabled after `lv_anim_init()`) + * Make the animation to play back to when the forward direction is ready * @param a pointer to an initialized `lv_anim_t` variable + * @param delay delay in milliseconds before starting the playback animation. */ -static inline void lv_anim_clear_playback(lv_anim_t * a) +static inline void lv_anim_set_playback_delay(lv_anim_t * a, uint16_t delay) { - a->playback = 0; + a->playback_delay = delay; } /** - * Make the animation to start again when ready. + * Make the animation repeat itself. * @param a pointer to an initialized `lv_anim_t` variable - * @param wait_time time in milliseconds to wait before starting the animation again + * @param cnt repeat count or `LV_ANIM_REPEAT_INFINITE` for infinite repetition. 0: to disable repetition. */ -static inline void lv_anim_set_repeat(lv_anim_t * a, uint16_t wait_time) +static inline void lv_anim_set_repeat_count(lv_anim_t * a, uint16_t cnt) { - a->repeat = 1; - a->repeat_pause = wait_time; + a->repeat_cnt = cnt; } /** - * Disable repeat. (Disabled after `lv_anim_init()`) + * Set a delay before repeating the animation. * @param a pointer to an initialized `lv_anim_t` variable + * @param delay delay in milliseconds before repeating the animation. */ -static inline void lv_anim_clear_repeat(lv_anim_t * a) +static inline void lv_anim_set_repeat_delay(lv_anim_t * a, uint16_t delay) { - a->repeat = 0; + a->repeat_delay = delay; } /** * Create an animation * @param a an initialized 'anim_t' variable. Not required after call. */ -void lv_anim_create(lv_anim_t * a); +void lv_anim_start(lv_anim_t * a); + +/** + * Initialize an animation path + * @param path pointer to path + */ +static inline void lv_anim_path_init(lv_anim_path_t * path) +{ + _lv_memset_00(path, sizeof(lv_anim_path_t)); +} + +/** + * Set a callback for a path + * @param path pointer to an initialized path + * @param cb the callback + */ +static inline void lv_anim_path_set_cb(lv_anim_path_t * path, lv_anim_path_cb_t cb) +{ + path->cb = cb; +} + +/** + * Set a user data for a path + * @param path pointer to an initialized path + * @param user_data pointer to the user data + */ +static inline void lv_anim_path_set_user_data(lv_anim_path_t * path, void * user_data) +{ + path->user_data = user_data; +} + +/** + * Get a delay before starting the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @return delay before the animation in milliseconds + */ +static inline int32_t lv_anim_get_delay(lv_anim_t * a) +{ + return -a->act_time; +} /** * Delete an animation of a variable with a given animator function @@ -238,11 +313,20 @@ void lv_anim_create(lv_anim_t * a); bool lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb); /** - * Delete an aniamation by getting the animated variable from `a`. + * Get the animation of a variable and its `exec_cb`. + * @param var pointer to variable + * @param exec_cb a function pointer which is animating 'var', + * or NULL to delete all the animations of 'var' + * @return pointer to the animation. + */ +lv_anim_t * lv_anim_get(void * var, lv_anim_exec_xcb_t exec_cb); + +/** + * Delete an animation by getting the animated variable from `a`. * Only animations with `exec_cb` will be deleted. - * This function exist becasue it's logical that all anim functions receives an - * `lv_anim_t` as their first parameter. It's not practical in C but might makes - * the API more conequent and makes easier to genrate bindings. + * This function exists because it's logical that all anim. functions receives an + * `lv_anim_t` as their first parameter. It's not practical in C but might make + * the API more consequent and makes easier to generate bindings. * @param a pointer to an animation. * @param exec_cb a function pointer which is animating 'var', * or NULL to ignore it and delete all the animations of 'var @@ -266,49 +350,57 @@ uint16_t lv_anim_count_running(void); * @param end end value of the animation * @return the required time [ms] for the animation with the given parameters */ -uint32_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end); +uint16_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end); + +/** + * Manually refresh the state of the animations. + * Useful to make the animations running in a blocking process where + * `lv_task_handler` can't run for a while. + * Shouldn't be used directly because it is called in `lv_refr_now()`. + */ +void lv_anim_refr_now(void); /** * Calculate the current value of an animation applying linear characteristic * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_linear(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_linear(const lv_anim_path_t * path, const lv_anim_t * a); /** * Calculate the current value of an animation slowing down the start phase * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_ease_in(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_ease_in(const lv_anim_path_t * path, const lv_anim_t * a); /** * Calculate the current value of an animation slowing down the end phase * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_ease_out(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_ease_out(const lv_anim_path_t * path, const lv_anim_t * a); /** * Calculate the current value of an animation applying an "S" characteristic (cosine) * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_path_t * path, const lv_anim_t * a); /** * Calculate the current value of an animation with overshoot at the end * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_overshoot(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_overshoot(const lv_anim_path_t * path, const lv_anim_t * a); /** * Calculate the current value of an animation with 3 bounces * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_bounce(const lv_anim_path_t * path, const lv_anim_t * a); /** * Calculate the current value of an animation applying step characteristic. @@ -316,7 +408,12 @@ lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a); * @param a pointer to an animation * @return the current value to set */ -lv_anim_value_t lv_anim_path_step(const lv_anim_t * a); +lv_anim_value_t lv_anim_path_step(const lv_anim_path_t * path, const lv_anim_t * a); + +/********************** + * GLOBAL VARIABLES + **********************/ +extern const lv_anim_path_t lv_anim_path_def; /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_area.c b/src/libs/lvgl/src/lv_misc/lv_area.c index de649c5b..0fea6832 100644 --- a/src/libs/lvgl/src/lv_misc/lv_area.c +++ b/src/libs/lvgl/src/lv_misc/lv_area.c @@ -6,11 +6,7 @@ /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include "lv_area.h" #include "lv_math.h" @@ -27,6 +23,8 @@ * STATIC PROTOTYPES **********************/ +static bool lv_point_within_circle(const lv_area_t * area, const lv_point_t * p); + /********************** * STATIC VARIABLES **********************/ @@ -81,7 +79,7 @@ void lv_area_set_height(lv_area_t * area_p, lv_coord_t h) * @param x the new x coordinate of the area * @param y the new y coordinate of the area */ -void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y) +void _lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y) { lv_coord_t w = lv_area_get_width(area_p); lv_coord_t h = lv_area_get_height(area_p); @@ -112,7 +110,7 @@ uint32_t lv_area_get_size(const lv_area_t * area_p) * @param a2_p pointer to the second area * @return false: the two area has NO common parts, res_p is invalid */ -bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) +bool _lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) { /* Get the smaller area from 'a1_p' and 'a2_p' */ res_p->x1 = LV_MATH_MAX(a1_p->x1, a2_p->x1); @@ -134,7 +132,7 @@ bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_ * @param a1_p pointer to the first area * @param a2_p pointer to the second area */ -void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) +void _lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p) { a_res_p->x1 = LV_MATH_MIN(a1_p->x1, a2_p->x1); a_res_p->y1 = LV_MATH_MIN(a1_p->y1, a2_p->y1); @@ -146,17 +144,67 @@ void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * * Check if a point is on an area * @param a_p pointer to an area * @param p_p pointer to a point + * @param radius radius of area (e.g. for rounded rectangle) * @return false:the point is out of the area */ -bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p) +bool _lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p, lv_coord_t radius) { - bool is_on = false; - + /*First check the basic area*/ + bool is_on_rect = false; if((p_p->x >= a_p->x1 && p_p->x <= a_p->x2) && ((p_p->y >= a_p->y1 && p_p->y <= a_p->y2))) { - is_on = true; + is_on_rect = true; + } + if(!is_on_rect) + return false; + /*Now handle potential rounded rectangles*/ + if(radius <= 0) { + /*No radius, it is within the rectangle*/ + return true; } + lv_coord_t w = lv_area_get_width(a_p) / 2; + lv_coord_t h = lv_area_get_height(a_p) / 2; + lv_coord_t max_radius = LV_MATH_MIN(w, h); + if(radius > max_radius) + radius = max_radius; - return is_on; + /*Check if it's in one of the corners*/ + lv_area_t corner_area; + /*Top left*/ + corner_area.x1 = a_p->x1; + corner_area.x2 = a_p->x1 + radius; + corner_area.y1 = a_p->y1; + corner_area.y2 = a_p->y1 + radius; + if(_lv_area_is_point_on(&corner_area, p_p, 0)) { + corner_area.x2 += radius; + corner_area.y2 += radius; + return lv_point_within_circle(&corner_area, p_p); + } + /*Bottom left*/ + corner_area.y1 = a_p->y2 - radius; + corner_area.y2 = a_p->y2; + if(_lv_area_is_point_on(&corner_area, p_p, 0)) { + corner_area.x2 += radius; + corner_area.y1 -= radius; + return lv_point_within_circle(&corner_area, p_p); + } + /*Bottom right*/ + corner_area.x1 = a_p->x2 - radius; + corner_area.x2 = a_p->x2; + if(_lv_area_is_point_on(&corner_area, p_p, 0)) { + corner_area.x1 -= radius; + corner_area.y1 -= radius; + return lv_point_within_circle(&corner_area, p_p); + } + /*Top right*/ + corner_area.y1 = a_p->y1; + corner_area.y2 = a_p->y1 + radius; + if(_lv_area_is_point_on(&corner_area, p_p, 0)) { + corner_area.x1 -= radius; + corner_area.y2 += radius; + return lv_point_within_circle(&corner_area, p_p); + } + /*Not within corners*/ + return true; } /** @@ -165,11 +213,12 @@ bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p) * @param a2_p pointer to an other area * @return false: a1_p and a2_p has no common parts */ -bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p) +bool _lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p) { if((a1_p->x1 <= a2_p->x2) && (a1_p->x2 >= a2_p->x1) && (a1_p->y1 <= a2_p->y2) && (a1_p->y2 >= a2_p->y1)) { return true; - } else { + } + else { return false; } } @@ -177,10 +226,11 @@ bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p) /** * Check if an area is fully on an other * @param ain_p pointer to an area which could be in 'aholder_p' - * @param aholder pointer to an area which could involve 'ain_p' - * @return + * @param aholder_p pointer to an area which could involve 'ain_p' + * @param radius radius of `aholder_p` (e.g. for rounded rectangle) + * @return true: `ain_p` is fully inside `aholder_p` */ -bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p) +bool _lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p, lv_coord_t radius) { bool is_in = false; @@ -189,22 +239,171 @@ bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p) is_in = true; } - return is_in; + if(!is_in) return false; + if(radius == 0) return true; + + /*Check if the corner points are inside the radius or not*/ + lv_point_t p; + + p.x = ain_p->x1; + p.y = ain_p->y1; + if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false; + + p.x = ain_p->x2; + p.y = ain_p->y1; + if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false; + + p.x = ain_p->x1; + p.y = ain_p->y2; + if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false; + + p.x = ain_p->x2; + p.y = ain_p->y2; + if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false; + + return true; } /** - * Increment or decrement an area's size by a single amount - * @param a_p pointer to an area to grow - * @param amount amount to increment the area, or negative to decrement + * Align an area to an other + * @param base an are where the other will be aligned + * @param to_align the area to align + * @param align `LV_ALIGN_...` + * @param res x/y coordinates where `to_align` align area should be placed */ -void lv_area_increment(lv_area_t * a_p, const lv_coord_t amount) +void _lv_area_align(const lv_area_t * base, const lv_area_t * to_align, lv_align_t align, lv_point_t * res) { - a_p->x1 -= amount; - a_p->y1 -= amount; - a_p->x2 += amount; - a_p->y2 += amount; + + switch(align) { + case LV_ALIGN_CENTER: + res->x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2; + res->y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2; + break; + + case LV_ALIGN_IN_TOP_LEFT: + res->x = 0; + res->y = 0; + break; + case LV_ALIGN_IN_TOP_MID: + res->x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2; + res->y = 0; + break; + + case LV_ALIGN_IN_TOP_RIGHT: + res->x = lv_area_get_width(base) - lv_area_get_width(to_align); + res->y = 0; + break; + + case LV_ALIGN_IN_BOTTOM_LEFT: + res->x = 0; + res->y = lv_area_get_height(base) - lv_area_get_height(to_align); + break; + case LV_ALIGN_IN_BOTTOM_MID: + res->x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2; + res->y = lv_area_get_height(base) - lv_area_get_height(to_align); + break; + + case LV_ALIGN_IN_BOTTOM_RIGHT: + res->x = lv_area_get_width(base) - lv_area_get_width(to_align); + res->y = lv_area_get_height(base) - lv_area_get_height(to_align); + break; + + case LV_ALIGN_IN_LEFT_MID: + res->x = 0; + res->y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2; + break; + + case LV_ALIGN_IN_RIGHT_MID: + res->x = lv_area_get_width(base) - lv_area_get_width(to_align); + res->y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2; + break; + + case LV_ALIGN_OUT_TOP_LEFT: + res->x = 0; + res->y = -lv_area_get_height(to_align); + break; + + case LV_ALIGN_OUT_TOP_MID: + res->x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2; + res->y = -lv_area_get_height(to_align); + break; + + case LV_ALIGN_OUT_TOP_RIGHT: + res->x = lv_area_get_width(base) - lv_area_get_width(to_align); + res->y = -lv_area_get_height(to_align); + break; + + case LV_ALIGN_OUT_BOTTOM_LEFT: + res->x = 0; + res->y = lv_area_get_height(base); + break; + + case LV_ALIGN_OUT_BOTTOM_MID: + res->x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2; + res->y = lv_area_get_height(base); + break; + + case LV_ALIGN_OUT_BOTTOM_RIGHT: + res->x = lv_area_get_width(base) - lv_area_get_width(to_align); + res->y = lv_area_get_height(base); + break; + + case LV_ALIGN_OUT_LEFT_TOP: + res->x = -lv_area_get_width(to_align); + res->y = 0; + break; + + case LV_ALIGN_OUT_LEFT_MID: + res->x = -lv_area_get_width(to_align); + res->y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2; + break; + + case LV_ALIGN_OUT_LEFT_BOTTOM: + res->x = -lv_area_get_width(to_align); + res->y = lv_area_get_height(base) - lv_area_get_height(to_align); + break; + + case LV_ALIGN_OUT_RIGHT_TOP: + res->x = lv_area_get_width(base); + res->y = 0; + break; + + case LV_ALIGN_OUT_RIGHT_MID: + res->x = lv_area_get_width(base); + res->y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2; + break; + + case LV_ALIGN_OUT_RIGHT_BOTTOM: + res->x = lv_area_get_width(base); + res->y = lv_area_get_height(base) - lv_area_get_height(to_align); + break; + } + + res->x += base->x1; + res->y += base->y1; } /********************** * STATIC FUNCTIONS **********************/ + +static bool lv_point_within_circle(const lv_area_t * area, const lv_point_t * p) +{ + lv_coord_t r = (area->x2 - area->x1) / 2; + + /* Circle center */ + lv_coord_t cx = area->x1 + r; + lv_coord_t cy = area->y1 + r; + + /*Simplify the code by moving everything to (0, 0) */ + lv_coord_t px = p->x - cx; + lv_coord_t py = p->y - cy; + + uint32_t r_sqrd = r * r; + uint32_t dist = (px * px) + (py * py); + + if(dist <= r_sqrd) + return true; + else + return false; +} diff --git a/src/libs/lvgl/src/lv_misc/lv_area.h b/src/libs/lvgl/src/lv_misc/lv_area.h index 211bebd8..6394b73c 100644 --- a/src/libs/lvgl/src/lv_misc/lv_area.h +++ b/src/libs/lvgl/src/lv_misc/lv_area.h @@ -13,14 +13,11 @@ extern "C" { /********************* * INCLUDES *********************/ +#include "../lv_conf_internal.h" #include <string.h> #include <stdbool.h> #include <stdint.h> -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "lv_mem.h" /********************* * DEFINES @@ -39,21 +36,45 @@ LV_EXPORT_CONST_INT(LV_COORD_MIN); /** * Represents a point on the screen. */ -typedef struct -{ +typedef struct { lv_coord_t x; lv_coord_t y; } lv_point_t; /** Represents an area of the screen. */ -typedef struct -{ +typedef struct { lv_coord_t x1; lv_coord_t y1; lv_coord_t x2; lv_coord_t y2; } lv_area_t; +/** Alignments */ +enum { + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +}; +typedef uint8_t lv_align_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -75,7 +96,7 @@ void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2 */ inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src) { - memcpy(dest, src, sizeof(lv_area_t)); + _lv_memcpy_small(dest, src, sizeof(lv_area_t)); } /** @@ -118,7 +139,7 @@ void lv_area_set_height(lv_area_t * area_p, lv_coord_t h); * @param x the new x coordinate of the area * @param y the new y coordinate of the area */ -void lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); +void _lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); /** * Return with area of an area (x * y) @@ -134,7 +155,7 @@ uint32_t lv_area_get_size(const lv_area_t * area_p); * @param a2_p pointer to the second area * @return false: the two area has NO common parts, res_p is invalid */ -bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); +bool _lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); /** * Join two areas into a third which involves the other two @@ -142,15 +163,16 @@ bool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_ * @param a1_p pointer to the first area * @param a2_p pointer to the second area */ -void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); +void _lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); /** * Check if a point is on an area * @param a_p pointer to an area * @param p_p pointer to a point + * @param radius radius of area (e.g. for rounded rectangle) * @return false:the point is out of the area */ -bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p); +bool _lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p, lv_coord_t radius); /** * Check if two area has common parts @@ -158,22 +180,25 @@ bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p); * @param a2_p pointer to an other area * @return false: a1_p and a2_p has no common parts */ -bool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); +bool _lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); /** * Check if an area is fully on an other - * @param ain_p pointer to an area which could be on aholder_p - * @param aholder pointer to an area which could involve ain_p - * @return + * @param ain_p pointer to an area which could be in 'aholder_p' + * @param aholder_p pointer to an area which could involve 'ain_p' + * @param radius radius of `aholder_p` (e.g. for rounded rectangle) + * @return true: `ain_p` is fully inside `aholder_p` */ -bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p); +bool _lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p, lv_coord_t radius); /** - * Increment or decrement an area's size by a single amount - * @param a_p pointer to an area to grow - * @param amount amount to increment the area, or negative to decrement + * Align an area to an other + * @param base an are where the other will be aligned + * @param to_align the area to align + * @param align `LV_ALIGN_...` + * @param res x/y coordinates where `to_align` align area should be placed */ -void lv_area_increment(lv_area_t * a_p, const lv_coord_t amount); +void _lv_area_align(const lv_area_t * base, const lv_area_t * to_align, lv_align_t align, lv_point_t * res); /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_async.c b/src/libs/lvgl/src/lv_misc/lv_async.c index 2a836432..41ec144a 100644 --- a/src/libs/lvgl/src/lv_misc/lv_async.c +++ b/src/libs/lvgl/src/lv_misc/lv_async.c @@ -17,11 +17,16 @@ * TYPEDEFS **********************/ +typedef struct _lv_async_info_t { + lv_async_cb_t cb; + void * user_data; +} lv_async_info_t; + /********************** * STATIC PROTOTYPES **********************/ -static void lv_async_task_cb(lv_task_t *task); +static void lv_async_task_cb(lv_task_t * task); /********************** * STATIC VARIABLES @@ -38,26 +43,24 @@ static void lv_async_task_cb(lv_task_t *task); lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data) { /*Allocate an info structure */ - lv_async_info_t *info = lv_mem_alloc(sizeof(lv_async_info_t)); - + lv_async_info_t * info = lv_mem_alloc(sizeof(lv_async_info_t)); + if(info == NULL) return LV_RES_INV; - + /* 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_task_t * task = lv_task_create(lv_async_task_cb, 0, LV_TASK_PRIO_HIGHEST, info); + if(task == NULL) { lv_mem_free(info); return LV_RES_INV; } - + info->cb = async_xcb; info->user_data = user_data; - /* Set the task's user data */ - task->user_data = info; - lv_task_once(task); + lv_task_set_repeat_count(task, 1); return LV_RES_OK; } @@ -65,11 +68,11 @@ 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_task_t * task) { - lv_async_info_t *info = (lv_async_info_t *)task->user_data; - + lv_async_info_t * info = (lv_async_info_t *)task->user_data; + info->cb(info->user_data); - + lv_mem_free(info); } diff --git a/src/libs/lvgl/src/lv_misc/lv_async.h b/src/libs/lvgl/src/lv_misc/lv_async.h index 9423cd8e..a3a9330b 100644 --- a/src/libs/lvgl/src/lv_misc/lv_async.h +++ b/src/libs/lvgl/src/lv_misc/lv_async.h @@ -30,13 +30,6 @@ extern "C" { */ typedef void (*lv_async_cb_t)(void *); -typedef struct _lv_async_info_t { - lv_async_cb_t cb; - void *user_data; -} lv_async_info_t; - -struct _lv_obj_t; - /********************** * GLOBAL PROTOTYPES **********************/ @@ -44,7 +37,7 @@ struct _lv_obj_t; /** * Call an asynchronous function the next time lv_task_handler() is run. This function is likely to return * **before** the call actually happens! - * @param task_xcb a callback which is the task itself. + * @param async_xcb a callback which is the task itself. * (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 user_data custom parameter @@ -59,4 +52,4 @@ lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data); } /* extern "C" */ #endif -#endif /*LV_TEMPL_H*/ +#endif /*LV_ASYNC_H*/ diff --git a/src/libs/lvgl/src/lv_misc/lv_bidi.c b/src/libs/lvgl/src/lv_misc/lv_bidi.c index 6e50d926..caa463a8 100644 --- a/src/libs/lvgl/src/lv_misc/lv_bidi.c +++ b/src/libs/lvgl/src/lv_misc/lv_bidi.c @@ -9,7 +9,7 @@ #include <stddef.h> #include "lv_bidi.h" #include "lv_txt.h" -#include "../lv_draw/lv_draw.h" +#include "../lv_misc/lv_mem.h" #if LV_USE_BIDI @@ -26,19 +26,28 @@ /********************** * TYPEDEFS **********************/ -typedef struct -{ +typedef struct { uint32_t bracklet_pos; lv_bidi_dir_t dir; -}bracket_stack_t; +} bracket_stack_t; /********************** * STATIC PROTOTYPES **********************/ -static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, uint16_t * pos_conv_len); -static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *pos_conv_out, uint16_t pos_conv_rd_base, uint16_t pos_conv_len); + +static uint32_t lv_bidi_get_next_paragraph(const char * txt); +static lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter); +static bool lv_bidi_letter_is_weak(uint32_t letter); +static bool lv_bidi_letter_is_rtl(uint32_t letter); +static bool lv_bidi_letter_is_neutral(uint32_t letter); + +static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, + uint16_t * pos_conv_len); +static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t * pos_conv_out, uint16_t pos_conv_rd_base, + uint16_t pos_conv_len); static uint32_t char_change_to_pair(uint32_t letter); -static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir); +static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, + lv_bidi_dir_t base_dir); static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index); static uint32_t get_txt_len(const char * txt, uint32_t max_len); @@ -58,9 +67,16 @@ static uint8_t br_stack_p; * GLOBAL FUNCTIONS **********************/ -void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir) +/** + * Convert a text to get the characters in the correct visual order according to + * Unicode Bidirectional Algorithm + * @param str_in the text to process + * @param str_out store the result here. Has the be `strlen(str_in)` length + * @param base_dir `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + */ +void _lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir) { - if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in); + if(base_dir == LV_BIDI_DIR_AUTO) base_dir = _lv_bidi_detect_base_dir(str_in); uint32_t par_start = 0; uint32_t par_len; @@ -72,7 +88,7 @@ void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir while(str_in[par_start] != '\0') { par_len = lv_bidi_get_next_paragraph(&str_in[par_start]); - lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir, NULL, 0); + _lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir, NULL, 0); par_start += par_len; while(str_in[par_start] == '\n' || str_in[par_start] == '\r') { @@ -84,12 +100,17 @@ void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir str_out[par_start] = '\0'; } -lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt) +/** + * Auto-detect the direction of a text based on the first strong character + * @param txt the text to process + * @return `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + */ +lv_bidi_dir_t _lv_bidi_detect_base_dir(const char * txt) { uint32_t i = 0; uint32_t letter; while(txt[i] != '\0') { - letter = lv_txt_encoded_next(txt, &i); + letter = _lv_txt_encoded_next(txt, &i); lv_bidi_dir_t dir; dir = lv_bidi_get_letter_dir(letter); @@ -101,82 +122,99 @@ lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt) else return LV_BIDI_BASE_DIR_DEF; } -lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter) +/** + * Get the logical position of a character in a line + * @param str_in the input string. Can be only one line. + * @param bidi_txt internally the text is bidi processed which buffer can be get here. + * If not required anymore has to freed with `lv_mem_free()` + * Can be `NULL` is unused + * @param len length of the line in character count + * @param base_dir base direction of the text: `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + * @param visual_pos the visual character position which logical position should be get + * @param is_rtl tell the char at `visual_pos` is RTL or LTR context + * @return the logical character position + */ +uint16_t _lv_bidi_get_logical_pos(const char * str_in, char ** bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, + uint32_t visual_pos, bool * is_rtl) { - if(lv_bidi_letter_is_rtl(letter)) return LV_BIDI_DIR_RTL; - if(lv_bidi_letter_is_neutral(letter)) return LV_BIDI_DIR_NEUTRAL; - if(lv_bidi_letter_is_weak(letter)) return LV_BIDI_DIR_WEAK; - - return LV_BIDI_DIR_LTR; -} + uint32_t pos_conv_len = get_txt_len(str_in, len); + char * buf = _lv_mem_buf_get(len + 1); + if(buf == NULL) return (uint16_t) -1; -bool lv_bidi_letter_is_weak(uint32_t letter) -{ - uint32_t i = 0; - static const char weaks[] = "0123456789"; + uint16_t * pos_conv_buf = _lv_mem_buf_get(pos_conv_len * sizeof(uint16_t)); + if(pos_conv_buf == NULL) { + _lv_mem_buf_release(buf); + return (uint16_t) -1; + } - do { - uint32_t x = lv_txt_encoded_next(weaks, &i); - if(letter == x) { - return true; - } - } while(weaks[i] != '\0'); + if(bidi_txt) *bidi_txt = buf; - return false; -} + _lv_bidi_process_paragraph(str_in, bidi_txt ? *bidi_txt : NULL, len, base_dir, pos_conv_buf, pos_conv_len); -bool lv_bidi_letter_is_rtl(uint32_t letter) -{ - if(letter >= 0x5d0 && letter <= 0x5ea) return true; - if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/ -// if(letter >= 'a' && letter <= 'z') return true; + if(is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[visual_pos]); - return false; + if(bidi_txt == NULL) _lv_mem_buf_release(buf); + uint16_t res = GET_POS(pos_conv_buf[visual_pos]); + _lv_mem_buf_release(pos_conv_buf); + return res; } -bool lv_bidi_letter_is_neutral(uint32_t letter) +/** + * Get the visual position of a character in a line + * @param str_in the input string. Can be only one line. + * @param bidi_txt internally the text is bidi processed which buffer can be get here. + * If not required anymore has to freed with `lv_mem_free()` + * Can be `NULL` is unused + * @param len length of the line in character count + * @param base_dir base direction of the text: `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + * @param logical_pos the logical character position which visual position should be get + * @param is_rtl tell the char at `logical_pos` is RTL or LTR context + * @return the visual character position + */ +uint16_t _lv_bidi_get_visual_pos(const char * str_in, char ** bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, + uint32_t logical_pos, bool * is_rtl) { - uint16_t i; - static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\-=()[]{}<>@#&$|"; - for(i = 0; neutrals[i] != '\0'; i++) { - if(letter == (uint32_t)neutrals[i]) return true; + uint32_t pos_conv_len = get_txt_len(str_in, len); + char * buf = _lv_mem_buf_get(len + 1); + if(buf == NULL) return (uint16_t) -1; + + uint16_t * pos_conv_buf = _lv_mem_buf_get(pos_conv_len * sizeof(uint16_t)); + if(pos_conv_buf == NULL) { + _lv_mem_buf_release(buf); + return (uint16_t) -1; } - return false; -} + if(bidi_txt) *bidi_txt = buf; -uint16_t lv_bidi_get_logical_pos(const char * str_in, char **bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos, bool *is_rtl) -{ - uint32_t pos_conv_len = get_txt_len(str_in, len); - uint32_t txt_buf_size = len + 1; - txt_buf_size = (txt_buf_size + 3) & (~0x3); - void *buf = lv_draw_get_buf(txt_buf_size + pos_conv_len * sizeof(uint16_t)); - if (bidi_txt) *bidi_txt = buf; - uint16_t *pos_conv_buf = (uint16_t*) ((char*)buf + txt_buf_size); - lv_bidi_process_paragraph(str_in, bidi_txt? *bidi_txt: NULL, len, base_dir, pos_conv_buf, pos_conv_len); - if (is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[visual_pos]); - return GET_POS(pos_conv_buf[visual_pos]); -} + _lv_bidi_process_paragraph(str_in, bidi_txt ? *bidi_txt : NULL, len, base_dir, pos_conv_buf, pos_conv_len); -uint16_t lv_bidi_get_visual_pos(const char * str_in, char **bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos, bool *is_rtl) -{ - uint32_t pos_conv_len = get_txt_len(str_in, len); - uint32_t txt_buf_size = len + 1; - txt_buf_size = (txt_buf_size + 3) & (~0x3); - void *buf = lv_draw_get_buf(txt_buf_size + pos_conv_len * sizeof(uint16_t)); - if (bidi_txt) *bidi_txt = buf; - uint16_t *pos_conv_buf = (uint16_t*) ((char*)buf + txt_buf_size); - lv_bidi_process_paragraph(str_in, bidi_txt? *bidi_txt: NULL, len, base_dir, pos_conv_buf, pos_conv_len); - for (uint16_t i = 0; i < pos_conv_len; i++){ - if (GET_POS(pos_conv_buf[i]) == logical_pos){ - if (is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[i]); + for(uint16_t i = 0; i < pos_conv_len; i++) { + if(GET_POS(pos_conv_buf[i]) == logical_pos) { + + if(is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[i]); + _lv_mem_buf_release(pos_conv_buf); + + if(bidi_txt == NULL) _lv_mem_buf_release(buf); return i; } } + _lv_mem_buf_release(pos_conv_buf); + if(bidi_txt == NULL) _lv_mem_buf_release(buf); return (uint16_t) -1; } -void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, uint16_t *pos_conv_out, uint16_t pos_conv_len) +/** + * Bidi process a paragraph of text + * @param str_in the string to process + * @param str_out store the result here + * @param len length of the text + * @param base_dir base dir of the text + * @param pos_conv_out an `uint16_t` array to store the related logical position of the character. + * Can be `NULL` is unused + * @param pos_conv_len length of `pos_conv_out` in element count + */ +void _lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, + uint16_t * pos_conv_out, uint16_t pos_conv_len) { uint32_t run_len = 0; lv_bidi_dir_t run_dir; @@ -186,7 +224,7 @@ void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len uint16_t pos_conv_rd = 0; uint16_t pos_conv_wr; - if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in); + if(base_dir == LV_BIDI_DIR_AUTO) base_dir = _lv_bidi_detect_base_dir(str_in); if(base_dir == LV_BIDI_DIR_RTL) { wr = len; pos_conv_wr = pos_conv_len; @@ -196,7 +234,7 @@ void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len pos_conv_wr = 0; } - if (str_out) str_out[len] = '\0'; + if(str_out) str_out[len] = '\0'; lv_bidi_dir_t dir = base_dir; @@ -205,7 +243,7 @@ void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len /*Process neutral chars in the beginning*/ while(rd < len) { - uint32_t letter = lv_txt_encoded_next(str_in, &rd); + uint32_t letter = _lv_txt_encoded_next(str_in, &rd); pos_conv_rd++; dir = lv_bidi_get_letter_dir(letter); if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(str_in, rd, len, letter, base_dir); @@ -213,24 +251,26 @@ void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len } if(rd && str_in[rd] != '\0') { - lv_txt_encoded_prev(str_in, &rd); - pos_conv_rd--; + _lv_txt_encoded_prev(str_in, &rd); + pos_conv_rd--; } if(rd) { if(base_dir == LV_BIDI_DIR_LTR) { - if (str_out) { - memcpy(&str_out[wr], str_in, rd); + if(str_out) { + _lv_memcpy(&str_out[wr], str_in, rd); wr += rd; } - if (pos_conv_out) { + if(pos_conv_out) { fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_rd, 0); pos_conv_wr += pos_conv_rd; } - } else { + } + else { wr -= rd; pos_conv_wr -= pos_conv_rd; - rtl_reverse(str_out? &str_out[wr]: NULL, str_in, rd, pos_conv_out? &pos_conv_out[pos_conv_wr]: NULL, 0, pos_conv_rd); + rtl_reverse(str_out ? &str_out[wr] : NULL, str_in, rd, pos_conv_out ? &pos_conv_out[pos_conv_wr] : NULL, 0, + pos_conv_rd); } } @@ -241,43 +281,117 @@ void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len if(base_dir == LV_BIDI_DIR_LTR) { if(run_dir == LV_BIDI_DIR_LTR) { - if (str_out) memcpy(&str_out[wr], &str_in[rd], run_len); - if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd); + if(str_out) _lv_memcpy(&str_out[wr], &str_in[rd], run_len); + if(pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd); } - else rtl_reverse(str_out? &str_out[wr]: NULL, &str_in[rd], run_len, pos_conv_out? &pos_conv_out[pos_conv_wr] : NULL, pos_conv_rd, pos_conv_run_len); - wr += run_len; - pos_conv_wr += pos_conv_run_len; - } else { - wr -= run_len; - pos_conv_wr -= pos_conv_run_len; - if(run_dir == LV_BIDI_DIR_LTR) { - if (str_out) memcpy(&str_out[wr], &str_in[rd], run_len); - if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd); - } - else rtl_reverse(str_out? &str_out[wr]: NULL, &str_in[rd], run_len, pos_conv_out? &pos_conv_out[pos_conv_wr] : NULL, pos_conv_rd, pos_conv_run_len); - } + else rtl_reverse(str_out ? &str_out[wr] : NULL, &str_in[rd], run_len, pos_conv_out ? &pos_conv_out[pos_conv_wr] : NULL, + pos_conv_rd, pos_conv_run_len); + wr += run_len; + pos_conv_wr += pos_conv_run_len; + } + else { + wr -= run_len; + pos_conv_wr -= pos_conv_run_len; + if(run_dir == LV_BIDI_DIR_LTR) { + if(str_out) _lv_memcpy(&str_out[wr], &str_in[rd], run_len); + if(pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd); + } + else rtl_reverse(str_out ? &str_out[wr] : NULL, &str_in[rd], run_len, pos_conv_out ? &pos_conv_out[pos_conv_wr] : NULL, + pos_conv_rd, pos_conv_run_len); + } rd += run_len; pos_conv_rd += pos_conv_run_len; } } -uint32_t lv_bidi_get_next_paragraph(const char * txt) +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Get the next paragraph from a text + * @param txt the text to process + * @return the length of the current paragraph in byte count + */ +static uint32_t lv_bidi_get_next_paragraph(const char * txt) { uint32_t i = 0; - lv_txt_encoded_next(txt, &i); + _lv_txt_encoded_next(txt, &i); while(txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') { - lv_txt_encoded_next(txt, &i); + _lv_txt_encoded_next(txt, &i); } return i; } -/********************** - * STATIC FUNCTIONS - **********************/ +/** + * Get the direction of a character + * @param letter an Unicode character + * @return `LV_BIDI_DIR_RTL/LTR/WEAK/NEUTRAL` + */ +static lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter) +{ + if(lv_bidi_letter_is_rtl(letter)) return LV_BIDI_DIR_RTL; + if(lv_bidi_letter_is_neutral(letter)) return LV_BIDI_DIR_NEUTRAL; + if(lv_bidi_letter_is_weak(letter)) return LV_BIDI_DIR_WEAK; + + return LV_BIDI_DIR_LTR; +} +/** + * Tell whether a character is weak or not + * @param letter an Unicode character + * @return true/false + */ +static bool lv_bidi_letter_is_weak(uint32_t letter) +{ + uint32_t i = 0; + static const char weaks[] = "0123456789"; + + do { + uint32_t x = _lv_txt_encoded_next(weaks, &i); + if(letter == x) { + return true; + } + } while(weaks[i] != '\0'); + + return false; +} +/** + * Tell whether a character is RTL or not + * @param letter an Unicode character + * @return true/false + */ +static bool lv_bidi_letter_is_rtl(uint32_t letter) +{ + if(letter >= 0x5d0 && letter <= 0x5ea) return true; + if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/ + + /* Check for Persian and Arabic characters [https://en.wikipedia.org/wiki/Arabic_script_in_Unicode]*/ + if(letter >= 0x600 && letter <= 0x6FF) return true; + if(letter >= 0xFB50 && letter <= 0xFDFF) return true; + if(letter >= 0xFE70 && letter <= 0xFEFF) return true; + + return false; +} + +/** + * Tell whether a character is neutral or not + * @param letter an Unicode character + * @return true/false + */ +static bool lv_bidi_letter_is_neutral(uint32_t letter) +{ + uint16_t i; + static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\-=()[]{}<>@#&$|"; + for(i = 0; neutrals[i] != '\0'; i++) { + if(letter == (uint32_t)neutrals[i]) return true; + } + + return false; +} static uint32_t get_txt_len(const char * txt, uint32_t max_len) { @@ -285,7 +399,7 @@ static uint32_t get_txt_len(const char * txt, uint32_t max_len) uint32_t i = 0; while(i < max_len && txt[i] != '\0') { - lv_txt_encoded_next(txt, &i); + _lv_txt_encoded_next(txt, &i); len++; } @@ -294,27 +408,28 @@ static uint32_t get_txt_len(const char * txt, uint32_t max_len) static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index) { - for (uint16_t i = 0; i < len; i++) - { + uint16_t i; + for(i = 0; i < len; i++) { out[i] = SET_RTL_POS(index, false); index++; } -} +} -static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, uint16_t * pos_conv_len) +static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, + uint16_t * pos_conv_len) { uint32_t i = 0; uint32_t letter; uint16_t pos_conv_i = 0; - letter = lv_txt_encoded_next(txt, NULL); + letter = _lv_txt_encoded_next(txt, NULL); lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter); if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, 0, max_len, letter, base_dir); /*Find the first strong char. Skip the neutrals*/ while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) { - letter = lv_txt_encoded_next(txt, &i); + letter = _lv_txt_encoded_next(txt, &i); pos_conv_i++; dir = lv_bidi_get_letter_dir(letter); if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, i, max_len, letter, base_dir); @@ -336,7 +451,7 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint /*Find the next char which has different direction*/ lv_bidi_dir_t next_dir = base_dir; while(i_prev < max_len && txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') { - letter = lv_txt_encoded_next(txt, &i); + letter = _lv_txt_encoded_next(txt, &i); pos_conv_i++; next_dir = lv_bidi_get_letter_dir(letter); if(next_dir == LV_BIDI_DIR_NEUTRAL) next_dir = bracket_process(txt, i, max_len, letter, base_dir); @@ -382,7 +497,8 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint return run_dir; } -static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *pos_conv_out, uint16_t pos_conv_rd_base, uint16_t pos_conv_len) +static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t * pos_conv_out, uint16_t pos_conv_rd_base, + uint16_t pos_conv_len) { uint32_t i = len; uint32_t wr = 0; @@ -390,7 +506,7 @@ static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *p uint16_t pos_conv_wr = 0; while(i) { - uint32_t letter = lv_txt_encoded_prev(src, &i); + uint32_t letter = _lv_txt_encoded_prev(src, &i); uint16_t pos_conv_letter = --pos_conv_i; /*Keep weak letters (numbers) as LTR*/ @@ -400,15 +516,15 @@ static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *p uint16_t pos_conv_last_weak = pos_conv_i; uint16_t pos_conv_first_weak = pos_conv_i; while(i) { - letter = lv_txt_encoded_prev(src, &i); + letter = _lv_txt_encoded_prev(src, &i); pos_conv_letter = --pos_conv_i; /*No need to call `char_change_to_pair` because there not such chars here*/ /*Finish on non-weak char */ /*but treat number and currency related chars as weak*/ - if (lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') { - lv_txt_encoded_next(src, &i); /*Rewind one letter*/ + if(lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') { + _lv_txt_encoded_next(src, &i); /*Rewind one letter*/ pos_conv_i++; first_weak = i; pos_conv_first_weak = pos_conv_i; @@ -420,27 +536,28 @@ static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *p pos_conv_first_weak = 0; } - if (dest) memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1); - if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_last_weak - pos_conv_first_weak + 1, pos_conv_rd_base + pos_conv_first_weak); + if(dest) _lv_memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1); + if(pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_last_weak - pos_conv_first_weak + 1, + pos_conv_rd_base + pos_conv_first_weak); wr += last_weak - first_weak + 1; pos_conv_wr += pos_conv_last_weak - pos_conv_first_weak + 1; } /*Simply store in reversed order*/ else { - uint32_t letter_size = lv_txt_encoded_size((const char *)&src[i]); + uint32_t letter_size = _lv_txt_encoded_size((const char *)&src[i]); /*Swap arithmetical symbols*/ if(letter_size == 1) { uint32_t new_letter = letter = char_change_to_pair(letter); - if (dest) dest[wr] = (uint8_t)new_letter; - if (pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_letter, true); + if(dest) dest[wr] = (uint8_t)new_letter; + if(pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_letter, true); wr++; pos_conv_wr++; } /*Just store the letter*/ else { - if (dest) memcpy(&dest[wr], &src[i], letter_size); - if (pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_i, true); + if(dest) _lv_memcpy(&dest[wr], &src[i], letter_size); + if(pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_i, true); wr += letter_size; pos_conv_wr++; } @@ -463,7 +580,8 @@ static uint32_t char_change_to_pair(uint32_t letter) return letter; } -static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir) +static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, + lv_bidi_dir_t base_dir) { lv_bidi_dir_t bracket_dir = LV_BIDI_DIR_NEUTRAL; @@ -475,11 +593,12 @@ static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32 * If a char with base dir. direction is found then the brackets will have `base_dir` direction*/ uint32_t txt_i = next_pos; while(txt_i < len) { - uint32_t letter_next = lv_txt_encoded_next(txt, &txt_i); + uint32_t letter_next = _lv_txt_encoded_next(txt, &txt_i); if(letter_next == bracket_right[i]) { /*Closing bracket found*/ break; - } else { + } + else { /*Save the dir*/ lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next); if(letter_dir == base_dir) { @@ -496,9 +615,9 @@ static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32 /*If there were no matching strong chars in the brackets then check the previous chars*/ txt_i = next_pos; - if(txt_i) lv_txt_encoded_prev(txt, &txt_i); + if(txt_i) _lv_txt_encoded_prev(txt, &txt_i); while(txt_i > 0) { - uint32_t letter_next = lv_txt_encoded_prev(txt, &txt_i); + uint32_t letter_next = _lv_txt_encoded_prev(txt, &txt_i); lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next); if(letter_dir == LV_BIDI_DIR_LTR || letter_dir == LV_BIDI_DIR_RTL) { bracket_dir = letter_dir; @@ -506,7 +625,6 @@ static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32 } } - /*There where a previous strong char which can be used*/ if(bracket_dir != LV_BIDI_DIR_NEUTRAL) break; @@ -517,7 +635,6 @@ static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32 } } - /*The letter was an opening bracket*/ if(bracket_left[i] != '\0') { @@ -528,7 +645,8 @@ static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32 br_stack_p++; return bracket_dir; - } else if(br_stack_p > 0) { + } + else if(br_stack_p > 0) { /*Is the letter a closing bracket of the last opening?*/ if(letter == bracket_right[br_stack[br_stack_p - 1].bracklet_pos]) { bracket_dir = br_stack[br_stack_p - 1].dir; @@ -540,5 +658,4 @@ static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32 return LV_BIDI_DIR_NEUTRAL; } - #endif /*LV_USE_BIDI*/ diff --git a/src/libs/lvgl/src/lv_misc/lv_bidi.h b/src/libs/lvgl/src/lv_misc/lv_bidi.h index 215727aa..8b2f765d 100644 --- a/src/libs/lvgl/src/lv_misc/lv_bidi.h +++ b/src/libs/lvgl/src/lv_misc/lv_bidi.h @@ -1,5 +1,5 @@ /** - * @file lv_bifi.h + * @file lv_bidi.h * */ @@ -13,11 +13,7 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include <stdbool.h> #include <stdint.h> @@ -25,7 +21,7 @@ extern "C" { /********************* * DEFINES *********************/ -/* Special non printable strong characters. +/* Special non printable strong characters. * They can be inserted to texts to affect the run's direction*/ #define LV_BIDI_LRO "\xE2\x80\xAD" /*U+202D*/ #define LV_BIDI_RLO "\xE2\x80\xAE" /*U+202E*/ @@ -33,8 +29,7 @@ extern "C" { /********************** * TYPEDEFS **********************/ -enum -{ +enum { /*The first 4 values are stored in `lv_obj_t` on 2 bits*/ LV_BIDI_DIR_LTR = 0x00, LV_BIDI_DIR_RTL = 0x01, @@ -52,16 +47,64 @@ typedef uint8_t lv_bidi_dir_t; **********************/ #if LV_USE_BIDI -void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir); -void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, uint16_t *pos_conv_out, uint16_t pos_conv_len); -uint32_t lv_bidi_get_next_paragraph(const char * txt); -lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt); -lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter); -bool lv_bidi_letter_is_weak(uint32_t letter); -bool lv_bidi_letter_is_rtl(uint32_t letter); -bool lv_bidi_letter_is_neutral(uint32_t letter); -uint16_t lv_bidi_get_logical_pos(const char * str_in, char **bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos, bool *is_rtl); -uint16_t lv_bidi_get_visual_pos(const char * str_in, char **bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos, bool *is_rtl); +/** + * Convert a text to get the characters in the correct visual order according to + * Unicode Bidirectional Algorithm + * @param str_in the text to process + * @param str_out store the result here. Has the be `strlen(str_in)` length + * @param base_dir `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + */ +void _lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir); + +/** + * Auto-detect the direction of a text based on the first strong character + * @param txt the text to process + * @return `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + */ +lv_bidi_dir_t _lv_bidi_detect_base_dir(const char * txt); + +/** + * Get the logical position of a character in a line + * @param str_in the input string. Can be only one line. + * @param bidi_txt internally the text is bidi processed which buffer can be get here. + * If not required anymore has to freed with `lv_mem_free()` + * Can be `NULL` is unused + * @param len length of the line in character count + * @param base_dir base direction of the text: `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + * @param visual_pos the visual character position which logical position should be get + * @param is_rtl tell the char at `visual_pos` is RTL or LTR context + * @return the logical character position + */ +uint16_t _lv_bidi_get_logical_pos(const char * str_in, char ** bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, + uint32_t visual_pos, bool * is_rtl); + +/** + * Get the visual position of a character in a line + * @param str_in the input string. Can be only one line. + * @param bidi_txt internally the text is bidi processed which buffer can be get here. + * If not required anymore has to freed with `lv_mem_free()` + * Can be `NULL` is unused + * @param len length of the line in character count + * @param base_dir base direction of the text: `LV_BIDI_DIR_LTR` or `LV_BIDI_DIR_RTL` + * @param logical_pos the logical character position which visual position should be get + * @param is_rtl tell the char at `logical_pos` is RTL or LTR context + * @return the visual character position + */ +uint16_t _lv_bidi_get_visual_pos(const char * str_in, char ** bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, + uint32_t logical_pos, bool * is_rtl); + +/** + * Bidi process a paragraph of text + * @param str_in the string to process + * @param str_out store the result here + * @param len length of the text + * @param base_dir base dir of the text + * @param pos_conv_out an `uint16_t` array to store the related logical position of the character. + * Can be `NULL` is unused + * @param pos_conv_len length of `pos_conv_out` in element count + */ +void _lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, + uint16_t * pos_conv_out, uint16_t pos_conv_len); /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_circ.c b/src/libs/lvgl/src/lv_misc/lv_circ.c deleted file mode 100644 index fc0e3e20..00000000 --- a/src/libs/lvgl/src/lv_misc/lv_circ.c +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file lv_circ.c - * Circle drawing algorithm (with Bresenham) - * Only a 1/8 circle is calculated. Use CIRC_OCT1_X, CIRC_OCT1_Y macros to get - * the other octets. - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_circ.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the circle drawing - * @param c pointer to a point. The coordinates will be calculated here - * @param tmp point to a variable. It will store temporary data - * @param radius radius of the circle - */ -void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius) -{ - c->x = radius; - c->y = 0; - *tmp = 1 - radius; -} - -/** - * Test the circle drawing is ready or not - * @param c same as in circ_init - * @return true if the circle is not ready yet - */ -bool lv_circ_cont(lv_point_t * c) -{ - return c->y <= c->x ? true : false; -} - -/** - * Get the next point from the circle - * @param c same as in circ_init. The next point stored here. - * @param tmp same as in circ_init. - */ -void lv_circ_next(lv_point_t * c, lv_coord_t * tmp) -{ - c->y++; - - if(*tmp <= 0) { - (*tmp) += 2 * c->y + 1; /*Change in decision criterion for y -> y+1*/ - } else { - c->x--; - (*tmp) += 2 * (c->y - c->x) + 1; /*Change for y -> y+1, x -> x-1*/ - } -} - -/********************** - * STATIC FUNCTIONS - **********************/ diff --git a/src/libs/lvgl/src/lv_misc/lv_circ.h b/src/libs/lvgl/src/lv_misc/lv_circ.h deleted file mode 100644 index 405a4b6c..00000000 --- a/src/libs/lvgl/src/lv_misc/lv_circ.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file lv_circ.h - * - */ - -#ifndef LV_CIRC_H -#define LV_CIRC_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include <stddef.h> -#include "lv_area.h" - -/********************* - * DEFINES - *********************/ -#define LV_CIRC_OCT1_X(p) (p.x) -#define LV_CIRC_OCT1_Y(p) (p.y) -#define LV_CIRC_OCT2_X(p) (p.y) -#define LV_CIRC_OCT2_Y(p) (p.x) -#define LV_CIRC_OCT3_X(p) (-p.y) -#define LV_CIRC_OCT3_Y(p) (p.x) -#define LV_CIRC_OCT4_X(p) (-p.x) -#define LV_CIRC_OCT4_Y(p) (p.y) -#define LV_CIRC_OCT5_X(p) (-p.x) -#define LV_CIRC_OCT5_Y(p) (-p.y) -#define LV_CIRC_OCT6_X(p) (-p.y) -#define LV_CIRC_OCT6_Y(p) (-p.x) -#define LV_CIRC_OCT7_X(p) (p.y) -#define LV_CIRC_OCT7_Y(p) (-p.x) -#define LV_CIRC_OCT8_X(p) (p.x) -#define LV_CIRC_OCT8_Y(p) (-p.y) - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the circle drawing - * @param c pointer to a point. The coordinates will be calculated here - * @param tmp point to a variable. It will store temporary data - * @param radius radius of the circle - */ -void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius); - -/** - * Test the circle drawing is ready or not - * @param c same as in circ_init - * @return true if the circle is not ready yet - */ -bool lv_circ_cont(lv_point_t * c); - -/** - * Get the next point from the circle - * @param c same as in circ_init. The next point stored here. - * @param tmp same as in circ_init. - */ -void lv_circ_next(lv_point_t * c, lv_coord_t * tmp); - -/********************** - * MACROS - **********************/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/libs/lvgl/src/lv_misc/lv_color.c b/src/libs/lvgl/src/lv_misc/lv_color.c index cd4825df..11f33618 100644 --- a/src/libs/lvgl/src/lv_misc/lv_color.c +++ b/src/libs/lvgl/src/lv_misc/lv_color.c @@ -7,7 +7,6 @@ * INCLUDES *********************/ #include "lv_color.h" -#include "lv_math.h" /********************* * DEFINES @@ -33,9 +32,105 @@ * GLOBAL FUNCTIONS **********************/ -/********************** - * STATIC FUNCTIONS - **********************/ +LV_ATTRIBUTE_FAST_MEM void lv_color_fill(lv_color_t * buf, lv_color_t color, uint32_t px_num) +{ +#if LV_COLOR_DEPTH == 16 + uintptr_t buf_int = (uintptr_t) buf; + if(buf_int & 0x3) { + *buf = color; + buf++; + px_num--; + } + + uint32_t c32 = color.full + (color.full << 16); + uint32_t * buf32 = (uint32_t *)buf; + + while(px_num > 16) { + *buf32 = c32; + buf32++; + *buf32 = c32; + buf32++; + *buf32 = c32; + buf32++; + *buf32 = c32; + buf32++; + + *buf32 = c32; + buf32++; + *buf32 = c32; + buf32++; + *buf32 = c32; + buf32++; + *buf32 = c32; + buf32++; + + px_num -= 16; + } + + buf = (lv_color_t *)buf32; + + while(px_num) { + *buf = color; + buf++; + px_num --; + } +#else + while(px_num > 16) { + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + *buf = color; + buf++; + + px_num -= 16; + } + while(px_num) { + *buf = color; + buf++; + px_num --; + } +#endif +} + +lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl) +{ + return lv_color_mix(LV_COLOR_WHITE, c, lvl); +} + +lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl) +{ + return lv_color_mix(LV_COLOR_BLACK, c, lvl); +} /** * Convert a HSV color to RGB @@ -55,9 +150,6 @@ lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v) uint8_t region, remainder, p, q, t; if(s == 0) { - r = v; - g = v; - b = v; return lv_color_make(v, v, v); } @@ -127,7 +219,7 @@ lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8) hsv.v = (100 * rgbMax) >> 10; int32_t delta = rgbMax - rgbMin; - if (LV_MATH_ABS(delta) < 3) { + if(delta < 3) { hsv.h = 0; hsv.s = 0; return hsv; @@ -152,7 +244,7 @@ lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8) h = 0; h *= 60; h >>= 10; - if (h < 0) h += 360; + if(h < 0) h += 360; hsv.h = h; return hsv; diff --git a/src/libs/lvgl/src/lv_misc/lv_color.h b/src/libs/lvgl/src/lv_misc/lv_color.h index 1febbdce..75205edb 100644 --- a/src/libs/lvgl/src/lv_misc/lv_color.h +++ b/src/libs/lvgl/src/lv_misc/lv_color.h @@ -13,15 +13,13 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" +#include "lv_math.h" +#include "lv_types.h" /*Error checking*/ #if LV_COLOR_DEPTH == 24 -#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" +#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" #endif #if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0 @@ -37,24 +35,24 @@ extern "C" { /********************* * DEFINES *********************/ -#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF, 0xFF, 0xFF) -#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0, 0xC0, 0xC0) -#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80, 0x80, 0x80) -#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00, 0x00, 0x00) -#define LV_COLOR_RED LV_COLOR_MAKE(0xFF, 0x00, 0x00) -#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80, 0x00, 0x00) -#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF, 0xFF, 0x00) -#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80, 0x80, 0x00) -#define LV_COLOR_LIME LV_COLOR_MAKE(0x00, 0xFF, 0x00) -#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00, 0x80, 0x00) -#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00, 0xFF, 0xFF) -#define LV_COLOR_AQUA LV_COLOR_CYAN -#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00, 0x80, 0x80) -#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00, 0x00, 0xFF) -#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00, 0x00, 0x80) +#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF, 0xFF, 0xFF) +#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0, 0xC0, 0xC0) +#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80, 0x80, 0x80) +#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00, 0x00, 0x00) +#define LV_COLOR_RED LV_COLOR_MAKE(0xFF, 0x00, 0x00) +#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80, 0x00, 0x00) +#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF, 0xFF, 0x00) +#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80, 0x80, 0x00) +#define LV_COLOR_LIME LV_COLOR_MAKE(0x00, 0xFF, 0x00) +#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00, 0x80, 0x00) +#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00, 0xFF, 0xFF) +#define LV_COLOR_AQUA LV_COLOR_CYAN +#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00, 0x80, 0x80) +#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00, 0x00, 0xFF) +#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00, 0x00, 0x80) #define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF, 0x00, 0xFF) -#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80, 0x00, 0x80) -#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF, 0xA5, 0x00) +#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80, 0x00, 0x80) +#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF, 0xA5, 0x00) /** * Opacity percentages. @@ -75,8 +73,8 @@ enum { LV_OPA_COVER = 255, }; -#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/ -#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/ +#define LV_OPA_MIN 2 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 253 /*Opacities above this will fully cover*/ #if LV_COLOR_DEPTH == 1 #define LV_COLOR_SIZE 8 @@ -90,23 +88,70 @@ enum { #error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" #endif +/* Adjust color mix functions rounding. + * GPUs might calculate color mix (blending) differently. + * Should be in range of 0..254 + * 0: no adjustment, get the integer part of the result (round down) + * 64: round up from x.75 + * 128: round up from half + * 192: round up from x.25 + * 254: round up */ +#ifndef LV_COLOR_MIX_ROUND_OFS +#if LV_COLOR_DEPTH == 32 +#define LV_COLOR_MIX_ROUND_OFS 0 +#else +#define LV_COLOR_MIX_ROUND_OFS 128 +#endif +#endif + +#if defined(__cplusplus) && !defined(_LV_COLOR_HAS_MODERN_CPP) +/** +* MSVC compiler's definition of the __cplusplus indicating 199711L regardless to C++ standard version +* see https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-cplusplus +* so we use _MSC_VER macro instead of __cplusplus +*/ +#ifdef _MSC_VER +#if _MSC_VER >= 1900 /* Visual Studio 2015 */ +#define _LV_COLOR_HAS_MODERN_CPP 1 +#endif +#else +#if __cplusplus >= 201103L +#define _LV_COLOR_HAS_MODERN_CPP 1 +#endif +#endif +#endif /* __cplusplus */ + +#ifndef _LV_COLOR_HAS_MODERN_CPP +#define _LV_COLOR_HAS_MODERN_CPP 0 +#endif + +#if _LV_COLOR_HAS_MODERN_CPP +/* Fix msvc compiler error C4576 inside C++ code */ +#define _LV_COLOR_MAKE_TYPE_HELPER lv_color_t +#else +#define _LV_COLOR_MAKE_TYPE_HELPER (lv_color_t) +#endif + /*--------------------------------------- - * Macros for all existing color depths + * Macros for all existing color depths * to set/get values of the color channels *------------------------------------------*/ -# define LV_COLOR_SET_R1(c, v) (c).ch.red = (uint8_t)((v) & 0x1); -# define LV_COLOR_SET_G1(c, v) (c).ch.green = (uint8_t)((v) & 0x1); -# define LV_COLOR_SET_B1(c, v) (c).ch.blue = (uint8_t)((v) & 0x1); -# define LV_COLOR_SET_A1(c, v) +# define LV_COLOR_SET_R1(c, v) (c).ch.red = (uint8_t)((v) & 0x1) +# define LV_COLOR_SET_G1(c, v) (c).ch.green = (uint8_t)((v) & 0x1) +# define LV_COLOR_SET_B1(c, v) (c).ch.blue = (uint8_t)((v) & 0x1) +# define LV_COLOR_SET_A1(c, v) do {} while(0) # define LV_COLOR_GET_R1(c) (c).ch.red # define LV_COLOR_GET_G1(c) (c).ch.green # define LV_COLOR_GET_B1(c) (c).ch.blue -# define LV_COLOR_GET_A1(c) 1 +# define LV_COLOR_GET_A1(c) 0xFF -# define LV_COLOR_SET_R8(c, v) (c).ch.red = (uint8_t)(v) & 0x7U; -# define LV_COLOR_SET_G8(c, v) (c).ch.green = (uint8_t)(v) & 0x7U; -# define LV_COLOR_SET_B8(c, v) (c).ch.blue = (uint8_t)(v) & 0x3U; +# define _LV_COLOR_ZERO_INITIALIZER1 {0x00} +# define LV_COLOR_MAKE1(r8, g8, b8) (_LV_COLOR_MAKE_TYPE_HELPER{(uint8_t)((b8 >> 7) | (g8 >> 7) | (r8 >> 7))}) + +# define LV_COLOR_SET_R8(c, v) (c).ch.red = (uint8_t)((v) & 0x7U) +# define LV_COLOR_SET_G8(c, v) (c).ch.green = (uint8_t)((v) & 0x7U) +# define LV_COLOR_SET_B8(c, v) (c).ch.blue = (uint8_t)((v) & 0x3U) # define LV_COLOR_SET_A8(c, v) do {} while(0) # define LV_COLOR_GET_R8(c) (c).ch.red @@ -114,105 +159,80 @@ enum { # define LV_COLOR_GET_B8(c) (c).ch.blue # define LV_COLOR_GET_A8(c) 0xFF -# define LV_COLOR_SET_R16(c, v) (c).ch.red = (uint8_t)(v) & 0x1FU; -# define LV_COLOR_SET_G16(c, v) (c).ch.green = (uint8_t)(v) & 0x3FU; -# define LV_COLOR_SET_G16_SWAP(c, v) {(c).ch.green_h = (uint8_t)(((v) >> 3) & 0x7); (c).ch.green_l = (uint8_t)((v) & 0x7);} -# define LV_COLOR_SET_B16(c, v) (c).ch.blue = (uint8_t)(v) & 0x1FU; +# define _LV_COLOR_ZERO_INITIALIZER8 {{0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE8(r8, g8, b8) (_LV_COLOR_MAKE_TYPE_HELPER{{(uint8_t)((b8 >> 6) & 0x3U), (uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 5) & 0x7U)}}) + +# define LV_COLOR_SET_R16(c, v) (c).ch.red = (uint8_t)((v) & 0x1FU) +#if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_SET_G16(c, v) (c).ch.green = (uint8_t)((v) & 0x3FU) +#else +# define LV_COLOR_SET_G16(c, v) {(c).ch.green_h = (uint8_t)(((v) >> 3) & 0x7); (c).ch.green_l = (uint8_t)((v) & 0x7);} +#endif +# define LV_COLOR_SET_B16(c, v) (c).ch.blue = (uint8_t)((v) & 0x1FU) # define LV_COLOR_SET_A16(c, v) do {} while(0) # define LV_COLOR_GET_R16(c) (c).ch.red +#if LV_COLOR_16_SWAP == 0 # define LV_COLOR_GET_G16(c) (c).ch.green -# define LV_COLOR_GET_G16_SWAP(c) (((c).ch.green_h << 3) + (c).ch.green_l) +#else +# define LV_COLOR_GET_G16(c) (((c).ch.green_h << 3) + (c).ch.green_l) +#endif # define LV_COLOR_GET_B16(c) (c).ch.blue # define LV_COLOR_GET_A16(c) 0xFF -# define LV_COLOR_SET_R32(c, v) (c).ch.red = (uint32_t)((v) & 0xFF); -# define LV_COLOR_SET_G32(c, v) (c).ch.green = (uint32_t)((v) & 0xFF); -# define LV_COLOR_SET_B32(c, v) (c).ch.blue = (uint32_t)((v) & 0xFF); -# define LV_COLOR_SET_A32(c, v) (c).ch.alpha = (uint32_t)((v) & 0xFF); +#if LV_COLOR_16_SWAP == 0 +# define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE16(r8, g8, b8) (_LV_COLOR_MAKE_TYPE_HELPER{{(uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x3FU), (uint8_t)((r8 >> 3) & 0x1FU)}}) +#else +# define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE16(r8, g8, b8) (_LV_COLOR_MAKE_TYPE_HELPER{{(uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 3) & 0x1FU), (uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x7U)}}) +#endif + +# define LV_COLOR_SET_R32(c, v) (c).ch.red = (uint8_t)((v) & 0xFF) +# define LV_COLOR_SET_G32(c, v) (c).ch.green = (uint8_t)((v) & 0xFF) +# define LV_COLOR_SET_B32(c, v) (c).ch.blue = (uint8_t)((v) & 0xFF) +# define LV_COLOR_SET_A32(c, v) (c).ch.alpha = (uint8_t)((v) & 0xFF) # define LV_COLOR_GET_R32(c) (c).ch.red # define LV_COLOR_GET_G32(c) (c).ch.green # define LV_COLOR_GET_B32(c) (c).ch.blue # define LV_COLOR_GET_A32(c) (c).ch.alpha +# define _LV_COLOR_ZERO_INITIALIZER32 {{0x00, 0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE32(r8, g8, b8) (_LV_COLOR_MAKE_TYPE_HELPER{{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ /*--------------------------------------- * Macros for the current color depth * to set/get values of the color channels *------------------------------------------*/ -#if LV_COLOR_DEPTH == 1 -# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R1(c,v) -# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G1(c,v) -# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B1(c,v) -# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A1(c,v) - -# define LV_COLOR_GET_R(c) LV_COLOR_GET_R1(c) -# define LV_COLOR_GET_G(c) LV_COLOR_GET_G1(c) -# define LV_COLOR_GET_B(c) LV_COLOR_GET_B1(c) -# define LV_COLOR_GET_A(c) LV_COLOR_GET_A1(c) - -#elif LV_COLOR_DEPTH == 8 -# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R8(c,v) -# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G8(c,v) -# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B8(c,v) -# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A8(c,v) +#define LV_COLOR_SET_R(c, v) LV_CONCAT(LV_COLOR_SET_R, LV_COLOR_DEPTH)(c, v) +#define LV_COLOR_SET_G(c, v) LV_CONCAT(LV_COLOR_SET_G, LV_COLOR_DEPTH)(c, v) +#define LV_COLOR_SET_B(c, v) LV_CONCAT(LV_COLOR_SET_B, LV_COLOR_DEPTH)(c, v) +#define LV_COLOR_SET_A(c, v) LV_CONCAT(LV_COLOR_SET_A, LV_COLOR_DEPTH)(c, v) -# define LV_COLOR_GET_R(c) LV_COLOR_GET_R8(c) -# define LV_COLOR_GET_G(c) LV_COLOR_GET_G8(c) -# define LV_COLOR_GET_B(c) LV_COLOR_GET_B8(c) -# define LV_COLOR_GET_A(c) LV_COLOR_GET_A8(c) +#define LV_COLOR_GET_R(c) LV_CONCAT(LV_COLOR_GET_R, LV_COLOR_DEPTH)(c) +#define LV_COLOR_GET_G(c) LV_CONCAT(LV_COLOR_GET_G, LV_COLOR_DEPTH)(c) +#define LV_COLOR_GET_B(c) LV_CONCAT(LV_COLOR_GET_B, LV_COLOR_DEPTH)(c) +#define LV_COLOR_GET_A(c) LV_CONCAT(LV_COLOR_GET_A, LV_COLOR_DEPTH)(c) -#elif LV_COLOR_DEPTH == 16 -# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R16(c,v) -# if LV_COLOR_16_SWAP == 0 -# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G16(c,v) -# else -# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G16_SWAP(c,v) -# endif -# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B16(c,v) -# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A16(c,v) - -# define LV_COLOR_GET_R(c) LV_COLOR_GET_R16(c) -# if LV_COLOR_16_SWAP == 0 -# define LV_COLOR_GET_G(c) LV_COLOR_GET_G16(c) -# else -# define LV_COLOR_GET_G(c) LV_COLOR_GET_G16_SWAP(c) -# endif -# define LV_COLOR_GET_B(c) LV_COLOR_GET_B16(c) -# define LV_COLOR_GET_A(c) LV_COLOR_GET_A16(c) - -#elif LV_COLOR_DEPTH == 32 -# define LV_COLOR_SET_R(c, v) LV_COLOR_SET_R32(c,v) -# define LV_COLOR_SET_G(c, v) LV_COLOR_SET_G32(c,v) -# define LV_COLOR_SET_B(c, v) LV_COLOR_SET_B32(c,v) -# define LV_COLOR_SET_A(c, v) LV_COLOR_SET_A32(c,v) - -# define LV_COLOR_GET_R(c) LV_COLOR_GET_R32(c) -# define LV_COLOR_GET_G(c) LV_COLOR_GET_G32(c) -# define LV_COLOR_GET_B(c) LV_COLOR_GET_B32(c) -# define LV_COLOR_GET_A(c) LV_COLOR_GET_A32(c) -#endif +#define _LV_COLOR_ZERO_INITIALIZER LV_CONCAT(_LV_COLOR_ZERO_INITIALIZER, LV_COLOR_DEPTH) +#define LV_COLOR_MAKE(r8, g8, b8) LV_CONCAT(LV_COLOR_MAKE, LV_COLOR_DEPTH)(r8, g8, b8) /********************** * TYPEDEFS **********************/ -typedef union -{ - struct - { +typedef union { + uint8_t full; /*must be declared first to set all bits of byte via initializer list */ + union { uint8_t blue : 1; uint8_t green : 1; uint8_t red : 1; } ch; - uint8_t full; } lv_color1_t; -typedef union -{ - struct - { +typedef union { + struct { uint8_t blue : 2; uint8_t green : 3; uint8_t red : 3; @@ -220,10 +240,8 @@ typedef union uint8_t full; } lv_color8_t; -typedef union -{ - struct - { +typedef union { + struct { #if LV_COLOR_16_SWAP == 0 uint16_t blue : 5; uint16_t green : 6; @@ -238,10 +256,8 @@ typedef union uint16_t full; } lv_color16_t; -typedef union -{ - struct - { +typedef union { + struct { uint8_t blue; uint8_t green; uint8_t red; @@ -250,31 +266,20 @@ typedef union uint32_t full; } lv_color32_t; -#if LV_COLOR_DEPTH == 1 -typedef uint8_t lv_color_int_t; -typedef lv_color1_t lv_color_t; -#elif LV_COLOR_DEPTH == 8 -typedef uint8_t lv_color_int_t; -typedef lv_color8_t lv_color_t; -#elif LV_COLOR_DEPTH == 16 -typedef uint16_t lv_color_int_t; -typedef lv_color16_t lv_color_t; -#elif LV_COLOR_DEPTH == 32 -typedef uint32_t lv_color_int_t; -typedef lv_color32_t lv_color_t; -#else -#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" -#endif - -typedef uint8_t lv_opa_t; +typedef LV_CONCAT3(uint, LV_COLOR_SIZE, _t) lv_color_int_t; +typedef LV_CONCAT3(lv_color, LV_COLOR_DEPTH, _t) lv_color_t; -typedef struct -{ +typedef struct { uint16_t h; uint8_t s; uint8_t v; } lv_color_hsv_t; +//! @cond Doxygen_Suppress +/*No idea where the guard is required but else throws warnings in the docs*/ +typedef uint8_t lv_opa_t; +//! @endcond + /********************** * GLOBAL PROTOTYPES **********************/ @@ -282,17 +287,16 @@ typedef struct /*In color conversations: * - When converting to bigger color type the LSB weight of 1 LSB is calculated * E.g. 16 bit Red has 5 bits - * 8 bit Red has 2 bits + * 8 bit Red has 3 bits * ---------------------- - * 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10 + * 8 bit red LSB = (2^5 - 1) / (2^3 - 1) = 31 / 7 = 4 * * - When calculating to smaller color type simply shift out the LSBs - * E.g. 8 bit Red has 2 bits + * E.g. 8 bit Red has 3 bits * 16 bit Red has 5 bits * ---------------------- * Shift right with 5 - 3 = 2 */ - static inline uint8_t lv_color_to1(lv_color_t color) { #if LV_COLOR_DEPTH == 1 @@ -300,19 +304,22 @@ static inline uint8_t lv_color_to1(lv_color_t color) #elif LV_COLOR_DEPTH == 8 if((LV_COLOR_GET_R(color) & 0x4) || (LV_COLOR_GET_G(color) & 0x4) || (LV_COLOR_GET_B(color) & 0x2)) { return 1; - } else { + } + else { return 0; } #elif LV_COLOR_DEPTH == 16 if((LV_COLOR_GET_R(color) & 0x10) || (LV_COLOR_GET_G(color) & 0x20) || (LV_COLOR_GET_B(color) & 0x10)) { return 1; - } else { + } + else { return 0; } #elif LV_COLOR_DEPTH == 32 if((LV_COLOR_GET_R(color) & 0x80) || (LV_COLOR_GET_G(color) & 0x80) || (LV_COLOR_GET_B(color) & 0x80)) { return 1; - } else { + } + else { return 0; } #endif @@ -329,15 +336,15 @@ static inline uint8_t lv_color_to8(lv_color_t color) return color.full; #elif LV_COLOR_DEPTH == 16 lv_color8_t ret; - LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 2); /* 5 - 3 = 2*/ + LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 2); /* 5 - 3 = 2*/ LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 3); /* 6 - 3 = 3*/ - LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 3); /* 5 - 2 = 3*/ + LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 3); /* 5 - 2 = 3*/ return ret.full; #elif LV_COLOR_DEPTH == 32 lv_color8_t ret; - LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 5); /* 8 - 3 = 5*/ + LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 5); /* 8 - 3 = 5*/ LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 5); /* 8 - 3 = 5*/ - LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 6); /* 8 - 2 = 6*/ + LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 6); /* 8 - 2 = 6*/ return ret.full; #endif } @@ -351,42 +358,33 @@ static inline uint16_t lv_color_to16(lv_color_t color) return 0xFFFF; #elif LV_COLOR_DEPTH == 8 lv_color16_t ret; - LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) * 4); /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ -#if LV_COLOR_16_SWAP == 0 - LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) * 9); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ -#else - LV_COLOR_SET_G16_SWAP(ret, (LV_COLOR_GET_G(color) * 9)); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ -#endif - LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) * 10); /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ + LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) * 4); /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) * 9); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) * 10); /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ return ret.full; #elif LV_COLOR_DEPTH == 16 return color.full; #elif LV_COLOR_DEPTH == 32 lv_color16_t ret; - LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) >> 3); /* 8 - 5 = 3*/ - -#if LV_COLOR_16_SWAP == 0 + LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) >> 3); /* 8 - 5 = 3*/ LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) >> 2); /* 8 - 6 = 2*/ -#else - LV_COLOR_SET_G16_SWAP(ret, ret.ch.green_h = (LV_COLOR_GET_G(color) >> 2); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ -#endif - LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) >> 3); /* 8 - 5 = 3*/ + LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) >> 3); /* 8 - 5 = 3*/ return ret.full; -#endif +#endif } static inline uint32_t lv_color_to32(lv_color_t color) { #if LV_COLOR_DEPTH == 1 if(color.full == 0) - return 0; + return 0xFF000000; else return 0xFFFFFFFF; #elif LV_COLOR_DEPTH == 8 lv_color32_t ret; - LV_COLOR_SET_R32(ret, LV_COLOR_GET_R(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + LV_COLOR_SET_R32(ret, LV_COLOR_GET_R(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ LV_COLOR_SET_G32(ret, LV_COLOR_GET_G(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ - LV_COLOR_SET_B32(ret, LV_COLOR_GET_B(color) * 85); /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + LV_COLOR_SET_B32(ret, LV_COLOR_GET_B(color) * 85); /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ LV_COLOR_SET_A32(ret, 0xFF); return ret.full; #elif LV_COLOR_DEPTH == 16 @@ -396,9 +394,9 @@ static inline uint32_t lv_color_to32(lv_color_t color) * The faster integer math for conversion is: * valueto = ( valuefrom * multiplier + adder ) >> divisor * multiplier = FLOOR( ( (2^bitsto - 1) << divisor ) / (float)(2^bitsfrom - 1) ) - * + * * Find the first divisor where ( adder >> divisor ) <= 0 - * + * * 5-bit to 8-bit: ( 31 * multiplier + adder ) >> divisor = 255 * divisor multiplier adder min (0) max (31) * 0 8 7 7 255 @@ -407,7 +405,7 @@ static inline uint32_t lv_color_to32(lv_color_t color) * 3 65 25 3 255 * 4 131 19 1 255 * 5 263 7 0 255 - * + * * 6-bit to 8-bit: 255 = ( 63 * multiplier + adder ) >> divisor * divisor multiplier adder min (0) max (63) * 0 4 3 3 255 @@ -418,10 +416,11 @@ static inline uint32_t lv_color_to32(lv_color_t color) * 5 129 33 1 255 * 6 259 3 0 255 */ + lv_color32_t ret; - LV_COLOR_SET_R32(ret, (LV_COLOR_GET_R(color) * 263 + 7 ) >> 5); - LV_COLOR_SET_G32(ret, (LV_COLOR_GET_G(color) * 259 + 3 ) >> 6); - LV_COLOR_SET_B32(ret, (LV_COLOR_GET_B(color) * 263 + 7 ) >> 5); + LV_COLOR_SET_R32(ret, (LV_COLOR_GET_R(color) * 263 + 7) >> 5); + LV_COLOR_SET_G32(ret, (LV_COLOR_GET_G(color) * 259 + 3) >> 6); + LV_COLOR_SET_B32(ret, (LV_COLOR_GET_B(color) * 263 + 7) >> 5); LV_COLOR_SET_A32(ret, 0xFF); return ret.full; #elif LV_COLOR_DEPTH == 32 @@ -429,14 +428,26 @@ static inline uint32_t lv_color_to32(lv_color_t color) #endif } -static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix) +//! @cond Doxygen_Suppress + +/** + * Mix two colors with a given ratio. + * @param c1 the first color to mix (usually the foreground) + * @param c2 the second color to mix (usually the background) + * @param mix The ratio of the colors. 0: full `c2`, 255: full `c1`, 127: half `c1` and half`c2` + * @return the mixed color + */ +LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix) { lv_color_t ret; #if LV_COLOR_DEPTH != 1 /*LV_COLOR_DEPTH == 8, 16 or 32*/ - LV_COLOR_SET_R(ret, (uint16_t)((uint16_t) LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) * (255 - mix)) >> 8); - LV_COLOR_SET_G(ret, (uint16_t)((uint16_t) LV_COLOR_GET_G(c1) * mix + LV_COLOR_GET_G(c2) * (255 - mix)) >> 8); - LV_COLOR_SET_B(ret, (uint16_t)((uint16_t) LV_COLOR_GET_B(c1) * mix + LV_COLOR_GET_B(c2) * (255 - mix)) >> 8); + LV_COLOR_SET_R(ret, LV_MATH_UDIV255((uint16_t) LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) * + (255 - mix) + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_G(ret, LV_MATH_UDIV255((uint16_t) LV_COLOR_GET_G(c1) * mix + LV_COLOR_GET_G(c2) * + (255 - mix) + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_B(ret, LV_MATH_UDIV255((uint16_t) LV_COLOR_GET_B(c1) * mix + LV_COLOR_GET_B(c2) * + (255 - mix) + LV_COLOR_MIX_ROUND_OFS)); LV_COLOR_SET_A(ret, 0xFF); #else /*LV_COLOR_DEPTH == 1*/ @@ -446,6 +457,116 @@ static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix) return ret; } +LV_ATTRIBUTE_FAST_MEM static inline void lv_color_premult(lv_color_t c, uint8_t mix, uint16_t * out) +{ +#if LV_COLOR_DEPTH != 1 + out[0] = (uint16_t) LV_COLOR_GET_R(c) * mix; + out[1] = (uint16_t) LV_COLOR_GET_G(c) * mix; + out[2] = (uint16_t) LV_COLOR_GET_B(c) * mix; +#else + (void) mix; + /*Pre-multiplication can't be used with 1 bpp*/ + out[0] = LV_COLOR_GET_R(c); + out[1] = LV_COLOR_GET_G(c); + out[2] = LV_COLOR_GET_B(c); +#endif + +} + +/** + * Mix two colors with a given ratio. It runs faster then `lv_color_mix` but requires some pre computation. + * @param premult_c1 The first color. Should be preprocessed with `lv_color_premult(c1)` + * @param c2 The second color. As it is no pre computation required on it + * @param mix The ratio of the colors. 0: full `c1`, 255: full `c2`, 127: half `c1` and half `c2`. + * Should be modified like mix = `255 - mix` + * @return the mixed color + * @note 255 won't give clearly `c1`. + */ +LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix_premult(uint16_t * premult_c1, lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; +#if LV_COLOR_DEPTH != 1 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + LV_COLOR_SET_R(ret, LV_MATH_UDIV255(premult_c1[0] + LV_COLOR_GET_R(c2) * mix + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_G(ret, LV_MATH_UDIV255(premult_c1[1] + LV_COLOR_GET_G(c2) * mix + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_B(ret, LV_MATH_UDIV255(premult_c1[2] + LV_COLOR_GET_B(c2) * mix + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_A(ret, 0xFF); +#else + /*LV_COLOR_DEPTH == 1*/ + /*Restore color1*/ + lv_color_t c1; + LV_COLOR_SET_R(c1, premult_c1[0]); + LV_COLOR_SET_G(c1, premult_c1[1]); + LV_COLOR_SET_B(c1, premult_c1[2]); + ret.full = mix > LV_OPA_50 ? c2.full : c1.full; +#endif + + return ret; +} + +/** + * Mix two colors. Both color can have alpha value. + * @param bg_color background color + * @param bg_opa alpha of the background color + * @param fg_color foreground color + * @param fg_opa alpha of the foreground color + * @param res_color the result color + * @param res_opa the result opacity + */ +LV_ATTRIBUTE_FAST_MEM static inline void lv_color_mix_with_alpha(lv_color_t bg_color, lv_opa_t bg_opa, + lv_color_t fg_color, lv_opa_t fg_opa, + lv_color_t * res_color, lv_opa_t * res_opa) +{ + /* Pick the foreground if it's fully opaque or the Background is fully transparent*/ + if(fg_opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) { + res_color->full = fg_color.full; + *res_opa = fg_opa; + } + /*Transparent foreground: use the Background*/ + else if(fg_opa <= LV_OPA_MIN) { + res_color->full = bg_color.full; + *res_opa = bg_opa; + } + /*Opaque background: use simple mix*/ + else if(bg_opa >= LV_OPA_MAX) { + *res_color = lv_color_mix(fg_color, bg_color, fg_opa); + *res_opa = LV_OPA_COVER; + } + /*Both colors have alpha. Expensive calculation need to be applied*/ + else { + /*Save the parameters and the result. If they will be asked again don't compute again*/ + static lv_opa_t fg_opa_save = 0; + static lv_opa_t bg_opa_save = 0; + static lv_color_t fg_color_save = _LV_COLOR_ZERO_INITIALIZER; + static lv_color_t bg_color_save = _LV_COLOR_ZERO_INITIALIZER; + static lv_color_t res_color_saved = _LV_COLOR_ZERO_INITIALIZER; + static lv_opa_t res_opa_saved = 0; + + if(fg_opa != fg_opa_save || bg_opa != bg_opa_save || fg_color.full != fg_color_save.full || + bg_color.full != bg_color_save.full) { + fg_opa_save = fg_opa; + bg_opa_save = bg_opa; + fg_color_save.full = fg_color.full; + bg_color_save.full = bg_color.full; + /*Info: + * https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/ + res_opa_saved = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8); + if(res_opa_saved == 0) { + while(1) + ; + } + lv_opa_t ratio = (uint16_t)((uint16_t)fg_opa * 255) / res_opa_saved; + res_color_saved = lv_color_mix(fg_color, bg_color, ratio); + + } + + res_color->full = res_color_saved.full; + *res_opa = res_opa_saved; + } +} + +//! @endcond + /** * Get the brightness of a color * @param color a color @@ -459,21 +580,6 @@ static inline uint8_t lv_color_brightness(lv_color_t color) return (uint8_t)(bright >> 3); } -/* The most simple macro to create a color from R,G and B values */ -#if LV_COLOR_DEPTH == 1 -#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){.full = (uint8_t)((b8 >> 7) | (g8 >> 7) | (r8 >> 7))}) -#elif LV_COLOR_DEPTH == 8 -#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint8_t)((b8 >> 6) & 0x3U), (uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 5) & 0x7U)}}) -#elif LV_COLOR_DEPTH == 16 -#if LV_COLOR_16_SWAP == 0 -#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint16_t)((b8 >> 3) & 0x1FU), (uint16_t)((g8 >> 2) & 0x3FU), (uint16_t)((r8 >> 3) & 0x1FU)}}) -#else -#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{(uint16_t)((g8 >> 5) & 0x7U), (uint16_t)((r8 >> 3) & 0x1FU), (uint16_t)((b8 >> 3) & 0x1FU), (uint16_t)((g8 >> 2) & 0x7U)}}) -#endif -#elif LV_COLOR_DEPTH == 32 -#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ -#endif - static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b) { return LV_COLOR_MAKE(r, g, b); @@ -490,6 +596,15 @@ static inline lv_color_t lv_color_hex3(uint32_t c) (uint8_t)((c & 0xF) | ((c & 0xF) << 4))); } +//! @cond Doxygen_Suppress +//! +LV_ATTRIBUTE_FAST_MEM void lv_color_fill(lv_color_t * buf, lv_color_t color, uint32_t px_num); + +//! @endcond +lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl); + +lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl); + /** * Convert a HSV color to RGB * @param h hue [0..359] @@ -523,4 +638,4 @@ lv_color_hsv_t lv_color_to_hsv(lv_color_t color); } /* extern "C" */ #endif -#endif /*USE_COLOR*/ +#endif /*LV_COLOR_H*/ diff --git a/src/libs/lvgl/src/lv_misc/lv_debug.c b/src/libs/lvgl/src/lv_misc/lv_debug.c new file mode 100644 index 00000000..24fc78ff --- /dev/null +++ b/src/libs/lvgl/src/lv_misc/lv_debug.c @@ -0,0 +1,138 @@ +/** + * @file lv_debug.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_debug.h" + +#if LV_USE_DEBUG + +#include "lv_mem.h" +#include <string.h> + +/********************* + * DEFINES + *********************/ +#ifndef LV_DEBUG_STR_MAX_LENGTH + #define LV_DEBUG_STR_MAX_LENGTH (1024 * 8) +#endif + +#ifndef LV_DEBUG_STR_MAX_REPEAT + #define LV_DEBUG_STR_MAX_REPEAT 8 +#endif +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +bool lv_debug_check_null(const void * p) +{ + if(p) return true; + + return false; +} + +bool lv_debug_check_mem_integrity(void) +{ + return lv_mem_test() == LV_RES_OK ? true : false; +} + +bool lv_debug_check_str(const void * str) +{ + const uint8_t * s = (const uint8_t *)str; + uint8_t last_byte = 0; + uint32_t rep = 0; + uint32_t i; + + for(i = 0; i < LV_DEBUG_STR_MAX_LENGTH && s[i] != '\0'; i++) { + if(s[i] != last_byte) { + last_byte = s[i]; + rep = 1; + } + else if(s[i] > 0x7F) { + rep++; + if(rep > LV_DEBUG_STR_MAX_REPEAT) { + LV_LOG_WARN("lv_debug_check_str: a non-ASCII char has repeated more than LV_DEBUG_STR_MAX_REPEAT times)"); + return false; + } + } + + if(s[i] < 10) { + LV_LOG_WARN("lv_debug_check_str: invalid char in the string (< 10 value)"); + return false; /*Shouldn't occur in strings*/ + } + } + + if(s[i] == '\0') return true; + + LV_LOG_WARN("lv_debug_check_str: string is longer than LV_DEBUG_STR_MAX_LENGTH"); + return false; +} + +void lv_debug_log_error(const char * msg, uint64_t value) +{ + static const char hex[] = "0123456789ABCDEF"; + + size_t msg_len = strlen(msg); + uint32_t value_len = sizeof(unsigned long int); + + if(msg_len < 230) { + char buf[255]; + char * bufp = buf; + + /*Add the function name*/ + _lv_memcpy(bufp, msg, msg_len); + bufp += msg_len; + + /*Add value in hey*/ + *bufp = ' '; + bufp ++; + *bufp = '('; + bufp ++; + *bufp = '0'; + bufp ++; + *bufp = 'x'; + bufp ++; + + int8_t i; + for(i = value_len * 2 - 1; i >= 0; i--) { + uint8_t x = (unsigned long int)((unsigned long int)value >> (i * 4)) & 0xF; + + *bufp = hex[x]; + bufp++; + } + + *bufp = ')'; + bufp ++; + + *bufp = '\0'; + LV_LOG_ERROR(buf); + } + else { + LV_LOG_ERROR(msg); + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*LV_USE_DEBUG*/ diff --git a/src/libs/lvgl/src/lv_misc/lv_debug.h b/src/libs/lvgl/src/lv_misc/lv_debug.h new file mode 100644 index 00000000..82c92fe0 --- /dev/null +++ b/src/libs/lvgl/src/lv_misc/lv_debug.h @@ -0,0 +1,131 @@ +/** + * @file lv_debug.h + * + */ + +#ifndef LV_DEBUG_H +#define LV_DEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_conf_internal.h" + +#if LV_USE_DEBUG +#include <stdbool.h> + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +bool lv_debug_check_null(const void * p); + +bool lv_debug_check_mem_integrity(void); + +bool lv_debug_check_str(const void * str); + +void lv_debug_log_error(const char * msg, uint64_t value); + +/********************** + * MACROS + **********************/ + +#ifndef LV_DEBUG_ASSERT +#define LV_DEBUG_ASSERT(expr, msg, value) \ + do { \ + if(!(expr)) { \ + LV_LOG_ERROR(__func__); \ + lv_debug_log_error(msg, (uint64_t)((uintptr_t)value)); \ + while(1); \ + } \ + } while(0) +#endif + +/*---------------- + * CHECKS + *----------------*/ + +#ifndef LV_DEBUG_IS_NULL +#define LV_DEBUG_IS_NULL(p) (lv_debug_check_null(p)) +#endif + +#ifndef LV_DEBUG_CHECK_MEM_INTEGRITY +#define LV_DEBUG_CHECK_MEM_INTEGRITY() (lv_debug_check_mem_integrity()) +#endif + +#ifndef LV_DEBUG_IS_STR +#define LV_DEBUG_IS_STR(str) (lv_debug_check_null(str) && \ + lv_debug_check_str(str)) +#endif + +/*----------------- + * ASSERTS + *-----------------*/ + +/*clang-format off*/ + +#if LV_USE_ASSERT_NULL +# ifndef LV_ASSERT_NULL +# define LV_ASSERT_NULL(p) LV_DEBUG_ASSERT(LV_DEBUG_IS_NULL(p), "NULL pointer", p); +# endif +#else +# define LV_ASSERT_NULL(p) +#endif + +#if LV_USE_ASSERT_MEM +# ifndef LV_ASSERT_MEM +# define LV_ASSERT_MEM(p) LV_DEBUG_ASSERT(LV_DEBUG_IS_NULL(p), "Out of memory", p); +# endif +#else +# define LV_ASSERT_MEM(p) +#endif + +#if LV_USE_ASSERT_MEM_INTEGRITY +# ifndef LV_ASSERT_MEM_INTEGRITY +# define LV_ASSERT_MEM_INTEGRITY() LV_DEBUG_ASSERT(LV_DEBUG_CHECK_MEM_INTEGRITY(), "Memory integrity error", 0); +# endif +#else +# define LV_ASSERT_MEM_INTEGRITY() +#endif + +#if LV_USE_ASSERT_STR +# ifndef LV_ASSERT_STR +# define LV_ASSERT_STR(str) LV_DEBUG_ASSERT(LV_DEBUG_IS_STR(str), "Strange or invalid string", str); +# endif +#else /* LV_USE_ASSERT_OBJ == 0 */ +# if LV_USE_ASSERT_NULL /*Use at least LV_ASSERT_NULL if enabled*/ +# define LV_ASSERT_STR(str) LV_ASSERT_NULL(str) +# else +# define LV_ASSERT_STR(str) +# endif +#endif + +#else /* LV_USE_DEBUG == 0 */ + +#define LV_DEBUG_ASSERT(expr, msg, value) do{}while(0) + +#define LV_ASSERT_NULL(p) +#define LV_ASSERT_MEM(p) +#define LV_ASSERT_MEM_INTEGRITY() +#define LV_ASSERT_STR(p) +#define LV_ASSERT_OBJ(obj, obj_type) + +#endif /* LV_USE_DEBUG */ +/*clang-format on*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DEBUG_H*/ diff --git a/src/libs/lvgl/src/lv_misc/lv_fs.c b/src/libs/lvgl/src/lv_misc/lv_fs.c index a23081ce..6f66c765 100644 --- a/src/libs/lvgl/src/lv_misc/lv_fs.c +++ b/src/libs/lvgl/src/lv_misc/lv_fs.c @@ -9,15 +9,11 @@ #include "lv_fs.h" #if LV_USE_FILESYSTEM -#include "../lv_core/lv_debug.h" +#include "../lv_misc/lv_debug.h" #include "lv_ll.h" #include <string.h> #include "lv_gc.h" -#if defined(LV_GC_INCLUDE) -#include LV_GC_INCLUDE -#endif /* LV_ENABLE_GC */ - /********************* * DEFINES *********************/ @@ -27,7 +23,7 @@ * free function, otherwise compilation would fail. */ #ifdef free -#undef free + #undef free #endif /********************** @@ -54,13 +50,13 @@ static const char * lv_fs_get_real_path(const char * path); /** * Initialize the File system interface */ -void lv_fs_init(void) +void _lv_fs_init(void) { - lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t)); + _lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t)); } /** - * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be + * Test if a drive is ready or not. If the `ready` function was not initialized `true` will be * returned. * @param letter letter of the drive * @return true: drive is ready; false: drive is not ready @@ -95,18 +91,28 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo file_p->drv = lv_fs_get_drv(letter); if(file_p->drv == NULL) { - file_p->file_d = NULL; return LV_FS_RES_NOT_EX; } if(file_p->drv->ready_cb != NULL) { if(file_p->drv->ready_cb(file_p->drv) == false) { - file_p->drv = NULL; - file_p->file_d = NULL; + file_p->drv = NULL; return LV_FS_RES_HW_ERR; } } + if(file_p->drv->open_cb == NULL) { + file_p->drv = NULL; + return LV_FS_RES_NOT_IMP; + } + + const char * real_path = lv_fs_get_real_path(path); + + if(file_p->drv->file_size == 0) { /*Is file_d zero size?*/ + /*Pass file_d's address to open_cb, so the implementor can allocate memory byself*/ + return file_p->drv->open_cb(file_p->drv, &file_p->file_d, real_path, mode); + } + file_p->file_d = lv_mem_alloc(file_p->drv->file_size); LV_ASSERT_MEM(file_p->file_d); if(file_p->file_d == NULL) { @@ -114,12 +120,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ } - if(file_p->drv->open_cb == NULL) { - return LV_FS_RES_NOT_IMP; - } - - const char * real_path = lv_fs_get_real_path(path); - lv_fs_res_t res = file_p->drv->open_cb(file_p->drv, file_p->file_d, real_path, mode); + lv_fs_res_t res = file_p->drv->open_cb(file_p->drv, file_p->file_d, real_path, mode); if(res != LV_FS_RES_OK) { lv_mem_free(file_p->file_d); @@ -133,7 +134,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo /** * Close an already opened file * @param file_p pointer to a lv_fs_file_t variable - * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p) { @@ -150,7 +151,6 @@ lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p) lv_mem_free(file_p->file_d); /*Clean up*/ file_p->file_d = NULL; file_p->drv = NULL; - file_p->file_d = NULL; return res; } @@ -158,16 +158,15 @@ lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p) /** * Delete a file * @param path path of the file to delete - * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ lv_fs_res_t lv_fs_remove(const char * path) { if(path == NULL) return LV_FS_RES_INV_PARAM; - lv_fs_drv_t * drv = NULL; char letter = path[0]; - drv = lv_fs_get_drv(letter); + lv_fs_drv_t * drv = lv_fs_get_drv(letter); if(drv == NULL) return LV_FS_RES_NOT_EX; if(drv->ready_cb != NULL) { if(drv->ready_cb(drv) == false) return LV_FS_RES_HW_ERR; @@ -259,12 +258,12 @@ lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos) lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos) { if(file_p->drv == NULL) { - pos = 0; + *pos = 0; return LV_FS_RES_INV_PARAM; } if(file_p->drv->tell_cb == NULL) { - pos = 0; + *pos = 0; return LV_FS_RES_NOT_IMP; } @@ -285,7 +284,7 @@ lv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p) return LV_FS_RES_INV_PARAM; } - if(file_p->drv->tell_cb == NULL) { + if(file_p->drv->trunc_cb == NULL) { return LV_FS_RES_NOT_IMP; } @@ -349,13 +348,16 @@ lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname) } /** - * Initialize a 'fs_read_dir_t' variable for directory reading - * @param rddir_p pointer to a 'fs_read_dir_t' variable + * Initialize a 'lv_fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'lv_fs_dir_t' variable * @param path path to a directory * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path) { + rddir_p->drv = NULL; + rddir_p->dir_d = NULL; + if(path == NULL) return LV_FS_RES_INV_PARAM; char letter = path[0]; @@ -363,32 +365,50 @@ lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path) rddir_p->drv = lv_fs_get_drv(letter); if(rddir_p->drv == NULL) { - rddir_p->dir_d = NULL; return LV_FS_RES_NOT_EX; } - rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size); - LV_ASSERT_MEM(rddir_p->dir_d); - if(rddir_p->dir_d == NULL) { - rddir_p->dir_d = NULL; - return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ + if(rddir_p->drv->ready_cb != NULL) { + if(rddir_p->drv->ready_cb(rddir_p->drv) == false) { + rddir_p->drv = NULL; + return LV_FS_RES_HW_ERR; + } } if(rddir_p->drv->dir_open_cb == NULL) { + rddir_p->drv = NULL; return LV_FS_RES_NOT_IMP; } const char * real_path = lv_fs_get_real_path(path); + if(rddir_p->drv->rddir_size == 0) { /*Is dir_d zero size?*/ + /*Pass dir_d's address to dir_open_cb, so the implementor can allocate memory byself*/ + return rddir_p->drv->dir_open_cb(rddir_p->drv, &rddir_p->dir_d, real_path); + } + + rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size); + LV_ASSERT_MEM(rddir_p->dir_d); + if(rddir_p->dir_d == NULL) { + rddir_p->drv = NULL; + return LV_FS_RES_OUT_OF_MEM; /* Out of memory */ + } + lv_fs_res_t res = rddir_p->drv->dir_open_cb(rddir_p->drv, rddir_p->dir_d, real_path); + if(res != LV_FS_RES_OK) { + lv_mem_free(rddir_p->dir_d); + rddir_p->dir_d = NULL; + rddir_p->drv = NULL; + } + return res; } /** * Read the next filename form a directory. * The name of the directories will begin with '/' - * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable + * @param rddir_p pointer to an initialized 'lv_fs_dir_t' variable * @param fn pointer to a buffer to store the filename * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ @@ -400,6 +420,7 @@ lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn) } if(rddir_p->drv->dir_read_cb == NULL) { + fn[0] = '\0'; return LV_FS_RES_NOT_IMP; } @@ -410,7 +431,7 @@ lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn) /** * Close the directory reading - * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable + * @param rddir_p pointer to an initialized 'lv_fs_dir_t' variable * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p) @@ -419,18 +440,15 @@ lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p) return LV_FS_RES_INV_PARAM; } - lv_fs_res_t res; - if(rddir_p->drv->dir_close_cb == NULL) { - res = LV_FS_RES_NOT_IMP; - } else { - res = rddir_p->drv->dir_close_cb(rddir_p->drv, rddir_p->dir_d); + return LV_FS_RES_NOT_IMP; } + lv_fs_res_t res = rddir_p->drv->dir_close_cb(rddir_p->drv, rddir_p->dir_d); + lv_mem_free(rddir_p->dir_d); /*Clean up*/ rddir_p->dir_d = NULL; rddir_p->drv = NULL; - rddir_p->dir_d = NULL; return res; } @@ -450,19 +468,23 @@ lv_fs_res_t lv_fs_free_space(char letter, uint32_t * total_p, uint32_t * free_p) return LV_FS_RES_INV_PARAM; } - lv_fs_res_t res; + if(drv->ready_cb != NULL) { + if(drv->ready_cb(drv) == false) { + return LV_FS_RES_HW_ERR; + } + } if(drv->free_space_cb == NULL) { - res = LV_FS_RES_NOT_IMP; - } else { - uint32_t total_tmp = 0; - uint32_t free_tmp = 0; - res = drv->free_space_cb(drv, &total_tmp, &free_tmp); - - if(total_p != NULL) *total_p = total_tmp; - if(free_p != NULL) *free_p = free_tmp; + return LV_FS_RES_NOT_IMP; } + uint32_t total_tmp = 0; + uint32_t free_tmp = 0; + lv_fs_res_t res = drv->free_space_cb(drv, &total_tmp, &free_tmp); + + if(total_p != NULL) *total_p = total_tmp; + if(free_p != NULL) *free_p = free_tmp; + return res; } @@ -474,7 +496,7 @@ lv_fs_res_t lv_fs_free_space(char letter, uint32_t * total_p, uint32_t * free_p) */ void lv_fs_drv_init(lv_fs_drv_t * drv) { - memset(drv, 0, sizeof(lv_fs_drv_t)); + _lv_memset_00(drv, sizeof(lv_fs_drv_t)); } /** @@ -486,11 +508,11 @@ void lv_fs_drv_register(lv_fs_drv_t * drv_p) { /*Save the new driver*/ lv_fs_drv_t * new_drv; - new_drv = lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll)); + new_drv = _lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll)); LV_ASSERT_MEM(new_drv); if(new_drv == NULL) return; - memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t)); + _lv_memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t)); } /** @@ -502,8 +524,7 @@ lv_fs_drv_t * lv_fs_get_drv(char letter) { lv_fs_drv_t * drv; - LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) - { + _LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) { if(drv->letter == letter) { return drv; } @@ -521,8 +542,7 @@ char * lv_fs_get_letters(char * buf) lv_fs_drv_t * drv; uint8_t i = 0; - LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) - { + _LV_LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) { buf[i] = drv->letter; i++; } @@ -543,7 +563,8 @@ const char * lv_fs_get_ext(const char * fn) for(i = strlen(fn); i > 0; i--) { if(fn[i] == '.') { return &fn[i + 1]; - } else if(fn[i] == '/' || fn[i] == '\\') { + } + else if(fn[i] == '/' || fn[i] == '\\') { return ""; /*No extension if a '\' or '/' found*/ } } @@ -631,7 +652,8 @@ static const char * lv_fs_get_real_path(const char * path) while(*path != '\0') { if(*path == ':' || *path == '\\' || *path == '/') { path++; - } else { + } + else { break; } } diff --git a/src/libs/lvgl/src/lv_misc/lv_fs.h b/src/libs/lvgl/src/lv_misc/lv_fs.h index f1824282..acaa895d 100644 --- a/src/libs/lvgl/src/lv_misc/lv_fs.h +++ b/src/libs/lvgl/src/lv_misc/lv_fs.h @@ -13,11 +13,7 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #if LV_USE_FILESYSTEM @@ -34,8 +30,9 @@ extern "C" { /********************** * TYPEDEFS **********************/ + /** - * Errors in the filesystem module. + * Errors in the file system module. */ enum { LV_FS_RES_OK = 0, @@ -63,8 +60,7 @@ enum { }; typedef uint8_t lv_fs_mode_t; -typedef struct _lv_fs_drv_t -{ +typedef struct _lv_fs_drv_t { char letter; uint16_t file_size; uint16_t rddir_size; @@ -91,14 +87,12 @@ typedef struct _lv_fs_drv_t #endif } lv_fs_drv_t; -typedef struct -{ +typedef struct { void * file_d; lv_fs_drv_t * drv; } lv_fs_file_t; -typedef struct -{ +typedef struct { void * dir_d; lv_fs_drv_t * drv; } lv_fs_dir_t; @@ -110,7 +104,7 @@ typedef struct /** * Initialize the File system interface */ -void lv_fs_init(void); +void _lv_fs_init(void); /** * Initialize a file system driver with default values. @@ -135,7 +129,7 @@ void lv_fs_drv_register(lv_fs_drv_t * drv_p); lv_fs_drv_t * lv_fs_get_drv(char letter); /** - * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be + * Test if a drive is ready or not. If the `ready` function was not initialized `true` will be * returned. * @param letter letter of the drive * @return true: drive is ready; false: drive is not ready @@ -154,14 +148,14 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo /** * Close an already opened file * @param file_p pointer to a lv_fs_file_t variable - * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p); /** * Delete a file * @param path path of the file to delete - * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ lv_fs_res_t lv_fs_remove(const char * path); @@ -227,7 +221,7 @@ lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname); /** * Initialize a 'fs_dir_t' variable for directory reading - * @param rddir_p pointer to a 'fs_read_dir_t' variable + * @param rddir_p pointer to a 'lv_fs_dir_t' variable * @param path path to a directory * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ @@ -236,7 +230,7 @@ lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path); /** * Read the next filename form a directory. * The name of the directories will begin with '/' - * @param rddir_p pointer to an initialized 'fs_rdir_t' variable + * @param rddir_p pointer to an initialized 'fs_dir_t' variable * @param fn pointer to a buffer to store the filename * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ @@ -281,7 +275,7 @@ char * lv_fs_up(char * path); /** * Get the last element of a path (e.g. U:/folder/file -> file) - * @param buf buffer to store the letters ('\0' added after the last letter) + * @param path pointer to a file name * @return pointer to the beginning of the last element in the path */ const char * lv_fs_get_last(const char * path); diff --git a/src/libs/lvgl/src/lv_misc/lv_gc.c b/src/libs/lvgl/src/lv_misc/lv_gc.c index 94bf532a..3a37a48c 100644 --- a/src/libs/lvgl/src/lv_misc/lv_gc.c +++ b/src/libs/lvgl/src/lv_misc/lv_gc.c @@ -10,10 +10,6 @@ #include "lv_gc.h" #include "string.h" -#if defined(LV_GC_INCLUDE) -#include LV_GC_INCLUDE -#endif /* LV_ENABLE_GC */ - /********************* * DEFINES *********************/ @@ -29,9 +25,11 @@ /********************** * STATIC VARIABLES **********************/ + #if(!defined(LV_ENABLE_GC)) || LV_ENABLE_GC == 0 -LV_ROOTS + LV_ROOTS #endif /* LV_ENABLE_GC */ + /********************** * MACROS **********************/ @@ -40,9 +38,9 @@ LV_ROOTS * GLOBAL FUNCTIONS **********************/ -void lv_gc_clear_roots(void) +void _lv_gc_clear_roots(void) { -#define LV_CLEAR_ROOT(root_type, root_name) memset(&LV_GC_ROOT(root_name), 0, sizeof(LV_GC_ROOT(root_name))); +#define LV_CLEAR_ROOT(root_type, root_name) _lv_memset_00(&LV_GC_ROOT(root_name), sizeof(LV_GC_ROOT(root_name))); LV_ITERATE_ROOTS(LV_CLEAR_ROOT) } diff --git a/src/libs/lvgl/src/lv_misc/lv_gc.h b/src/libs/lvgl/src/lv_misc/lv_gc.h index afd4d600..915bf39a 100644 --- a/src/libs/lvgl/src/lv_misc/lv_gc.h +++ b/src/libs/lvgl/src/lv_misc/lv_gc.h @@ -13,18 +13,13 @@ extern "C" { /********************* * INCLUDES *********************/ - -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif - #include <stdint.h> #include <stdbool.h> #include "lv_mem.h" #include "lv_ll.h" +#include "lv_task.h" #include "../lv_draw/lv_img_cache.h" +#include "../lv_draw/lv_draw_mask.h" /********************* * DEFINES @@ -33,15 +28,22 @@ 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_disp_ll) /*Linked list of screens*/ \ - f(lv_ll_t, _lv_indev_ll) /*Linked list of screens*/ \ + f(lv_ll_t, _lv_indev_ll) /*Linked list of input device*/ \ f(lv_ll_t, _lv_drv_ll) \ f(lv_ll_t, _lv_file_ll) \ f(lv_ll_t, _lv_anim_ll) \ f(lv_ll_t, _lv_group_ll) \ 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(void*, _lv_task_act) \ - f(void*, _lv_draw_buf) + f(lv_task_t*, _lv_task_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) \ #define LV_DEFINE_ROOT(root_type, root_name) root_type root_name; #define LV_ROOTS LV_ITERATE_ROOTS(LV_DEFINE_ROOT) @@ -50,6 +52,7 @@ extern "C" { #if LV_MEM_CUSTOM != 1 #error "GC requires CUSTOM_MEM" #endif /* LV_MEM_CUSTOM */ +#include LV_GC_INCLUDE #else /* LV_ENABLE_GC */ #define LV_GC_ROOT(x) x #define LV_EXTERN_ROOT(root_type, root_name) extern root_type root_name; @@ -64,7 +67,7 @@ LV_ITERATE_ROOTS(LV_EXTERN_ROOT) * GLOBAL PROTOTYPES **********************/ -void lv_gc_clear_roots(void); +void _lv_gc_clear_roots(void); /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_ll.c b/src/libs/lvgl/src/lv_misc/lv_ll.c index 99526659..56013682 100644 --- a/src/libs/lvgl/src/lv_misc/lv_ll.c +++ b/src/libs/lvgl/src/lv_misc/lv_ll.c @@ -47,22 +47,16 @@ static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * nex * @param ll_dsc pointer to ll_dsc variable * @param node_size the size of 1 node in bytes */ -void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size) +void _lv_ll_init(lv_ll_t * ll_p, uint32_t node_size) { ll_p->head = NULL; ll_p->tail = NULL; -#ifdef LV_MEM_ENV64 +#ifdef LV_ARCH_64 /*Round the size up to 8*/ - if(node_size & 0x7) { - node_size = node_size & (~0x7); - node_size += 8; - } + node_size = (node_size + 7) & (~0x7); #else /*Round the size up to 4*/ - if(node_size & 0x3) { - node_size = node_size & (~0x3); - node_size += 4; - } + node_size = (node_size + 3) & (~0x3); #endif ll_p->n_size = node_size; @@ -73,7 +67,7 @@ void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size) * @param ll_p pointer to linked list * @return pointer to the new head */ -void * lv_ll_ins_head(lv_ll_t * ll_p) +void * _lv_ll_ins_head(lv_ll_t * ll_p) { lv_ll_node_t * n_new; @@ -102,21 +96,22 @@ void * lv_ll_ins_head(lv_ll_t * ll_p) * @param n_act pointer a node * @return pointer to the new head */ -void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act) +void * _lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act) { lv_ll_node_t * n_new; - lv_ll_node_t * n_prev; if(NULL == ll_p || NULL == n_act) return NULL; - if(lv_ll_get_head(ll_p) == n_act) { - n_new = lv_ll_ins_head(ll_p); + if(_lv_ll_get_head(ll_p) == n_act) { + n_new = _lv_ll_ins_head(ll_p); if(n_new == NULL) return NULL; - } else { + } + else { n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); if(n_new == NULL) return NULL; - n_prev = lv_ll_get_prev(ll_p, n_act); + lv_ll_node_t * n_prev; + n_prev = _lv_ll_get_prev(ll_p, n_act); node_set_next(ll_p, n_prev, n_new); node_set_prev(ll_p, n_new, n_prev); node_set_prev(ll_p, n_act, n_new); @@ -131,16 +126,15 @@ void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act) * @param ll_p pointer to linked list * @return pointer to the new tail */ -void * lv_ll_ins_tail(lv_ll_t * ll_p) +void * _lv_ll_ins_tail(lv_ll_t * ll_p) { lv_ll_node_t * n_new; n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE); - if(n_new == NULL) return NULL; if(n_new != NULL) { node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/ - node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/ + node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is the old tail*/ if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/ node_set_next(ll_p, ll_p->tail, n_new); } @@ -156,31 +150,35 @@ void * lv_ll_ins_tail(lv_ll_t * ll_p) /** * Remove the node 'node_p' from 'll_p' linked list. - * It does not free the the memory of node. + * It does not free the memory of node. * @param ll_p pointer to the linked list of 'node_p' * @param node_p pointer to node in 'll_p' linked list */ -void lv_ll_rem(lv_ll_t * ll_p, void * node_p) +void _lv_ll_remove(lv_ll_t * ll_p, void * node_p) { - if(lv_ll_get_head(ll_p) == node_p) { + if(_lv_ll_get_head(ll_p) == node_p) { /*The new head will be the node after 'n_act'*/ - ll_p->head = lv_ll_get_next(ll_p, node_p); + ll_p->head = _lv_ll_get_next(ll_p, node_p); if(ll_p->head == NULL) { ll_p->tail = NULL; - } else { + } + else { node_set_prev(ll_p, ll_p->head, NULL); } - } else if(lv_ll_get_tail(ll_p) == node_p) { - /*The new tail will be the node before 'n_act'*/ - ll_p->tail = lv_ll_get_prev(ll_p, node_p); + } + else if(_lv_ll_get_tail(ll_p) == node_p) { + /*The new tail will be the node before 'n_act'*/ + ll_p->tail = _lv_ll_get_prev(ll_p, node_p); if(ll_p->tail == NULL) { ll_p->head = NULL; - } else { + } + else { node_set_next(ll_p, ll_p->tail, NULL); } - } else { - lv_ll_node_t * n_prev = lv_ll_get_prev(ll_p, node_p); - lv_ll_node_t * n_next = lv_ll_get_next(ll_p, node_p); + } + else { + lv_ll_node_t * n_prev = _lv_ll_get_prev(ll_p, node_p); + lv_ll_node_t * n_next = _lv_ll_get_next(ll_p, node_p); node_set_next(ll_p, n_prev, n_next); node_set_prev(ll_p, n_next, n_prev); @@ -191,18 +189,18 @@ void lv_ll_rem(lv_ll_t * ll_p, void * node_p) * Remove and free all elements from a linked list. The list remain valid but become empty. * @param ll_p pointer to linked list */ -void lv_ll_clear(lv_ll_t * ll_p) +void _lv_ll_clear(lv_ll_t * ll_p) { void * i; void * i_next; - i = lv_ll_get_head(ll_p); + i = _lv_ll_get_head(ll_p); i_next = NULL; while(i != NULL) { - i_next = lv_ll_get_next(ll_p, i); + i_next = _lv_ll_get_next(ll_p, i); - lv_ll_rem(ll_p, i); + _lv_ll_remove(ll_p, i); lv_mem_free(i); i = i_next; @@ -217,9 +215,9 @@ void lv_ll_clear(lv_ll_t * ll_p) * @param head true: be the head in the new list * false be the head in the new list */ -void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head) +void _lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head) { - lv_ll_rem(ll_ori_p, node); + _lv_ll_remove(ll_ori_p, node); if(head) { /*Set node as head*/ @@ -234,7 +232,8 @@ void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool he if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/ ll_new_p->tail = node; } - } else { + } + else { /*Set node as tail*/ node_set_prev(ll_new_p, node, ll_new_p->tail); node_set_next(ll_new_p, node, NULL); @@ -255,7 +254,7 @@ void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool he * @param ll_p pointer to linked list * @return pointer to the head of 'll_p' */ -void * lv_ll_get_head(const lv_ll_t * ll_p) +void * _lv_ll_get_head(const lv_ll_t * ll_p) { void * head = NULL; @@ -271,7 +270,7 @@ void * lv_ll_get_head(const lv_ll_t * ll_p) * @param ll_p pointer to linked list * @return pointer to the head of 'll_p' */ -void * lv_ll_get_tail(const lv_ll_t * ll_p) +void * _lv_ll_get_tail(const lv_ll_t * ll_p) { void * tail = NULL; @@ -288,16 +287,15 @@ void * lv_ll_get_tail(const lv_ll_t * ll_p) * @param n_act pointer a node * @return pointer to the next node */ -void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act) +void * _lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act) { - void * next = NULL; - - if(ll_p != NULL) { - const lv_ll_node_t * n_act_d = n_act; - memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *)); - } + if(ll_p == NULL) return NULL; - return next; + /* Pointer to the next node is stored in the end of this node. + * Go there and return the address found there */ + const lv_ll_node_t * n_act_d = n_act; + n_act_d += LL_NEXT_P_OFFSET(ll_p); + return *((lv_ll_node_t **)n_act_d); } /** @@ -306,16 +304,15 @@ void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act) * @param n_act pointer a node * @return pointer to the previous node */ -void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act) +void * _lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act) { - void * prev = NULL; + if(ll_p == NULL) return NULL; - if(ll_p != NULL) { - const lv_ll_node_t * n_act_d = n_act; - memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *)); - } - - return prev; + /* Pointer to the prev. node is stored in the end of this node. + * Go there and return the address found there */ + const lv_ll_node_t * n_act_d = n_act; + n_act_d += LL_PREV_P_OFFSET(ll_p); + return *((lv_ll_node_t **)n_act_d); } /** @@ -323,12 +320,12 @@ void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act) * @param ll_p pointer to linked list * @return length of the linked list */ -uint32_t lv_ll_get_len(const lv_ll_t * ll_p) +uint32_t _lv_ll_get_len(const lv_ll_t * ll_p) { uint32_t len = 0; void * node; - for(node = lv_ll_get_head(ll_p); node != NULL; node = lv_ll_get_next(ll_p, node)) { + for(node = _lv_ll_get_head(ll_p); node != NULL; node = _lv_ll_get_next(ll_p, node)) { len++; } @@ -336,25 +333,25 @@ uint32_t lv_ll_get_len(const lv_ll_t * ll_p) } /** - * Move a nodw before an other node in the same linked list + * Move a node before an other node in the same linked list * @param ll_p pointer to a linked list * @param n_act pointer to node to move * @param n_after pointer to a node which should be after `n_act` */ -void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after) +void _lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after) { if(n_act == n_after) return; /*Can't move before itself*/ void * n_before; if(n_after != NULL) - n_before = lv_ll_get_prev(ll_p, n_after); + n_before = _lv_ll_get_prev(ll_p, n_after); else - n_before = lv_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/ + n_before = _lv_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/ if(n_act == n_before) return; /*Already before `n_after`*/ /*It's much easier to remove from the list and add again*/ - lv_ll_rem(ll_p, n_act); + _lv_ll_remove(ll_p, n_act); /*Add again by setting the prev. and next nodes*/ node_set_next(ll_p, n_before, n_act); @@ -374,7 +371,7 @@ void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after) * @param ll_p pointer to a linked list * @return true: the linked list is empty; false: not empty */ -bool lv_ll_is_empty(lv_ll_t * ll_p) +bool _lv_ll_is_empty(lv_ll_t * ll_p) { if(ll_p == NULL) return true; @@ -388,7 +385,7 @@ bool lv_ll_is_empty(lv_ll_t * ll_p) **********************/ /** - * Set the 'pervious node pointer' of a node + * Set the previous node pointer of a node * @param ll_p pointer to linked list * @param act pointer to a node which prev. node pointer should be set * @param prev pointer to a node which should be the previous node before 'act' @@ -397,11 +394,14 @@ static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * pre { if(act == NULL) return; /*Can't set the prev node of `NULL`*/ - uint32_t node_p_size = sizeof(lv_ll_node_t *); - if(prev) - memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, node_p_size); - else - memset(act + LL_PREV_P_OFFSET(ll_p), 0, node_p_size); + uint8_t * act8 = (uint8_t *) act; + + act8 += LL_PREV_P_OFFSET(ll_p); + + lv_ll_node_t ** act_node_p = (lv_ll_node_t **) act8; + lv_ll_node_t ** prev_node_p = (lv_ll_node_t **) &prev; + + *act_node_p = *prev_node_p; } /** @@ -413,10 +413,11 @@ static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * pre static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next) { if(act == NULL) return; /*Can't set the next node of `NULL`*/ + uint8_t * act8 = (uint8_t *) act; - uint32_t node_p_size = sizeof(lv_ll_node_t *); - if(next) - memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, node_p_size); - else - memset(act + LL_NEXT_P_OFFSET(ll_p), 0, node_p_size); + act8 += LL_NEXT_P_OFFSET(ll_p); + lv_ll_node_t ** act_node_p = (lv_ll_node_t **) act8; + lv_ll_node_t ** next_node_p = (lv_ll_node_t **) &next; + + *act_node_p = *next_node_p; } diff --git a/src/libs/lvgl/src/lv_misc/lv_ll.h b/src/libs/lvgl/src/lv_misc/lv_ll.h index 2c02eb48..9ccc1100 100644 --- a/src/libs/lvgl/src/lv_misc/lv_ll.h +++ b/src/libs/lvgl/src/lv_misc/lv_ll.h @@ -1,5 +1,5 @@ /** - * @file lv_ll.c + * @file lv_ll.h * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module. */ @@ -30,8 +30,7 @@ extern "C" { typedef uint8_t lv_ll_node_t; /** Description of a linked list*/ -typedef struct -{ +typedef struct { uint32_t n_size; lv_ll_node_t * head; lv_ll_node_t * tail; @@ -46,14 +45,14 @@ typedef struct * @param ll_dsc pointer to ll_dsc variable * @param node_size the size of 1 node in bytes */ -void lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); +void _lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); /** * Add a new head to a linked list * @param ll_p pointer to linked list * @return pointer to the new head */ -void * lv_ll_ins_head(lv_ll_t * ll_p); +void * _lv_ll_ins_head(lv_ll_t * ll_p); /** * Insert a new node in front of the n_act node @@ -61,28 +60,28 @@ void * lv_ll_ins_head(lv_ll_t * ll_p); * @param n_act pointer a node * @return pointer to the new head */ -void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); +void * _lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); /** * Add a new tail to a linked list * @param ll_p pointer to linked list * @return pointer to the new tail */ -void * lv_ll_ins_tail(lv_ll_t * ll_p); +void * _lv_ll_ins_tail(lv_ll_t * ll_p); /** * Remove the node 'node_p' from 'll_p' linked list. - * It does not free the the memory of node. + * It does not free the memory of node. * @param ll_p pointer to the linked list of 'node_p' * @param node_p pointer to node in 'll_p' linked list */ -void lv_ll_rem(lv_ll_t * ll_p, void * node_p); +void _lv_ll_remove(lv_ll_t * ll_p, void * node_p); /** * Remove and free all elements from a linked list. The list remain valid but become empty. * @param ll_p pointer to linked list */ -void lv_ll_clear(lv_ll_t * ll_p); +void _lv_ll_clear(lv_ll_t * ll_p); /** * Move a node to a new linked list @@ -92,21 +91,21 @@ void lv_ll_clear(lv_ll_t * ll_p); * @param head true: be the head in the new list * false be the head in the new list */ -void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head); +void _lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head); /** * Return with head node of the linked list * @param ll_p pointer to linked list * @return pointer to the head of 'll_p' */ -void * lv_ll_get_head(const lv_ll_t * ll_p); +void * _lv_ll_get_head(const lv_ll_t * ll_p); /** * Return with tail node of the linked list * @param ll_p pointer to linked list * @return pointer to the head of 'll_p' */ -void * lv_ll_get_tail(const lv_ll_t * ll_p); +void * _lv_ll_get_tail(const lv_ll_t * ll_p); /** * Return with the pointer of the next node after 'n_act' @@ -114,7 +113,7 @@ void * lv_ll_get_tail(const lv_ll_t * ll_p); * @param n_act pointer a node * @return pointer to the next node */ -void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); +void * _lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); /** * Return with the pointer of the previous node after 'n_act' @@ -122,36 +121,45 @@ void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); * @param n_act pointer a node * @return pointer to the previous node */ -void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); +void * _lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); /** * Return the length of the linked list. * @param ll_p pointer to linked list * @return length of the linked list */ -uint32_t lv_ll_get_len(const lv_ll_t * ll_p); +uint32_t _lv_ll_get_len(const lv_ll_t * ll_p); /** - * Move a nodw before an other node in the same linked list + * TODO + * @param ll_p + * @param n1_p + * @param n2_p +void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p); + */ + +/** + * Move a node before an other node in the same linked list * @param ll_p pointer to a linked list * @param n_act pointer to node to move * @param n_after pointer to a node which should be after `n_act` */ -void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); +void _lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); /** * Check if a linked list is empty * @param ll_p pointer to a linked list * @return true: the linked list is empty; false: not empty */ -bool lv_ll_is_empty(lv_ll_t * ll_p); +bool _lv_ll_is_empty(lv_ll_t * ll_p); + /********************** * MACROS **********************/ -#define LV_LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i)) +#define _LV_LL_READ(list, i) for(i = _lv_ll_get_head(&list); i != NULL; i = _lv_ll_get_next(&list, i)) -#define LV_LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i)) +#define _LV_LL_READ_BACK(list, i) for(i = _lv_ll_get_tail(&list); i != NULL; i = _lv_ll_get_prev(&list, i)) #ifdef __cplusplus } /* extern "C" */ diff --git a/src/libs/lvgl/src/lv_misc/lv_log.c b/src/libs/lvgl/src/lv_misc/lv_log.c index acbdfb73..42b3b025 100644 --- a/src/libs/lvgl/src/lv_misc/lv_log.c +++ b/src/libs/lvgl/src/lv_misc/lv_log.c @@ -9,8 +9,12 @@ #include "lv_log.h" #if LV_USE_LOG +#include <stdarg.h> +#include <string.h> +#include "lv_printf.h" + #if LV_LOG_PRINTF -#include <stdio.h> + #include <stdio.h> #endif /********************* @@ -41,7 +45,7 @@ static lv_log_print_g_cb_t custom_print_cb; /** * Register custom print/write function to call when a log is added. * It can format its "File path", "Line number" and "Description" as required - * and send the formatted log message to a consol or serial port. + * and send the formatted log message to a console or serial port. * @param print_cb a function pointer to print a log */ void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb) @@ -54,19 +58,35 @@ void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb) * @param level the level of log. (From `lv_log_level_t` enum) * @param file name of the file when the log added * @param line line number in the source code where the log added - * @param dsc description of the log + * @param func name of the function when the log added + * @param format printf-like format string + * @param ... parameters for `format` */ -void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc) +void _lv_log_add(lv_log_level_t level, const char * file, int line, const char * func, const char * format, ...) { if(level >= _LV_LOG_LEVEL_NUM) return; /*Invalid level*/ if(level >= LV_LOG_LEVEL) { + va_list args; + va_start(args, format); + char buf[256]; + lv_vsnprintf(buf, sizeof(buf), format, args); + va_end(args); #if LV_LOG_PRINTF - static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"}; - printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line); + /*Use only the file name not the path*/ + size_t p; + for(p = strlen(file); p > 0; p--) { + if(file[p] == '/' || file[p] == '\\') { + p++; /*Skip the slash*/ + break; + } + } + + static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error", "User"}; + printf("%s: %s \t(%s #%d %s())\n", lvl_prefix[level], buf, &file[p], line, func); #else - if(custom_print_cb) custom_print_cb(level, file, line, dsc); + if(custom_print_cb) custom_print_cb(level, file, line, func, buf); #endif } } diff --git a/src/libs/lvgl/src/lv_misc/lv_log.h b/src/libs/lvgl/src/lv_misc/lv_log.h index 62c613b4..fe46cf44 100644 --- a/src/libs/lvgl/src/lv_misc/lv_log.h +++ b/src/libs/lvgl/src/lv_misc/lv_log.h @@ -13,11 +13,7 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include <stdint.h> /********************* @@ -27,16 +23,18 @@ extern "C" { /*Possible log level. For compatibility declare it independently from `LV_USE_LOG`*/ #define LV_LOG_LEVEL_TRACE 0 /**< A lot of logs to give detailed information*/ -#define LV_LOG_LEVEL_INFO 1 /**< Log important events*/ -#define LV_LOG_LEVEL_WARN 2 /**< Log if something unwanted happened but didn't caused problem*/ +#define LV_LOG_LEVEL_INFO 1 /**< Log important events*/ +#define LV_LOG_LEVEL_WARN 2 /**< Log if something unwanted happened but didn't caused problem*/ #define LV_LOG_LEVEL_ERROR 3 /**< Only critical issue, when the system may fail*/ -#define LV_LOG_LEVEL_NONE 4 /**< Do not log anything*/ -#define _LV_LOG_LEVEL_NUM 5 /**< Number of log levels */ +#define LV_LOG_LEVEL_USER 4 /**< Custom logs from the user*/ +#define LV_LOG_LEVEL_NONE 5 /**< Do not log anything*/ +#define _LV_LOG_LEVEL_NUM 6 /**< Number of log levels */ LV_EXPORT_CONST_INT(LV_LOG_LEVEL_TRACE); LV_EXPORT_CONST_INT(LV_LOG_LEVEL_INFO); LV_EXPORT_CONST_INT(LV_LOG_LEVEL_WARN); LV_EXPORT_CONST_INT(LV_LOG_LEVEL_ERROR); +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_USER); LV_EXPORT_CONST_INT(LV_LOG_LEVEL_NONE); typedef int8_t lv_log_level_t; @@ -47,9 +45,9 @@ typedef int8_t lv_log_level_t; **********************/ /** - * Log print function. Receives "Log Level", "File path", "Line number" and "Description". + * Log print function. Receives "Log Level", "File path", "Line number", "Function name" and "Description". */ -typedef void (*lv_log_print_g_cb_t)(lv_log_level_t level, const char *, uint32_t, const char *); +typedef void (*lv_log_print_g_cb_t)(lv_log_level_t level, const char *, uint32_t, const char *, const char *); /********************** * GLOBAL PROTOTYPES @@ -58,7 +56,7 @@ typedef void (*lv_log_print_g_cb_t)(lv_log_level_t level, const char *, uint32_t /** * Register custom print/write function to call when a log is added. * It can format its "File path", "Line number" and "Description" as required - * and send the formatted log message to a consol or serial port. + * and send the formatted log message to a console or serial port. * @param print_cb a function pointer to print a log */ void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb); @@ -68,73 +66,55 @@ void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb); * @param level the level of log. (From `lv_log_level_t` enum) * @param file name of the file when the log added * @param line line number in the source code where the log added - * @param dsc description of the log + * @param func name of the function when the log added + * @param format printf-like format string + * @param ... parameters for `format` */ -void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc); +void _lv_log_add(lv_log_level_t level, const char * file, int line, const char * func, const char * format, ...); /********************** * MACROS **********************/ #if LV_LOG_LEVEL <= LV_LOG_LEVEL_TRACE -#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc); +#define LV_LOG_TRACE(...) _lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_TRACE(dsc) \ - { \ - ; \ - } +#define LV_LOG_TRACE(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO -#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc); +#define LV_LOG_INFO(...) _lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_INFO(dsc) \ - { \ - ; \ - } +#define LV_LOG_INFO(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_WARN -#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc); +#define LV_LOG_WARN(...) _lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_WARN(dsc) \ - { \ - ; \ - } +#define LV_LOG_WARN(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_ERROR -#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc); +#define LV_LOG_ERROR(...) _lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__); +#else +#define LV_LOG_ERROR(...) +#endif + +#if LV_LOG_LEVEL <= LV_LOG_LEVEL_USER +#define LV_LOG_USER(...) _lv_log_add(LV_LOG_LEVEL_USER, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_ERROR(dsc) \ - { \ - ; \ - } +#define LV_LOG_USER(...) #endif #else /*LV_USE_LOG*/ -/*Do nothing if `LV_USE_LOG 0`*/ -#define lv_log_add(level, file, line, dsc) \ - { \ - ; \ - } -#define LV_LOG_TRACE(dsc) \ - { \ - ; \ - } -#define LV_LOG_INFO(dsc) \ - { \ - ; \ - } -#define LV_LOG_WARN(dsc) \ - { \ - ; \ - } -#define LV_LOG_ERROR(dsc) \ - { \ - ; \ - } +/*Do nothing if `LV_USE_LOG 0`*/ +#define _lv_log_add(level, file, line, ...) +#define LV_LOG_TRACE(...) +#define LV_LOG_INFO(...) +#define LV_LOG_WARN(...) +#define LV_LOG_ERROR(...) +#define LV_LOG_USER(...) #endif /*LV_USE_LOG*/ #ifdef __cplusplus diff --git a/src/libs/lvgl/src/lv_misc/lv_math.c b/src/libs/lvgl/src/lv_misc/lv_math.c index f015456e..45b82cd5 100644 --- a/src/libs/lvgl/src/lv_misc/lv_math.c +++ b/src/libs/lvgl/src/lv_misc/lv_math.c @@ -9,6 +9,7 @@ #include "lv_math.h" #include <stdbool.h> #include <stdlib.h> +#include <string.h> /********************* * DEFINES @@ -31,7 +32,8 @@ static const int16_t sin0_90_table[] = { 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621, 21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, 24351, 24730, 25101, 25465, 25821, 26169, 26509, 26841, 27165, 27481, 27788, 28087, 28377, 28659, 28932, 29196, 29451, 29697, 29934, 30162, 30381, 30591, 30791, 30982, 31163, 31335, 31498, 31650, 31794, 31927, 32051, 32165, - 32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762, 32767}; + 32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762, 32767 +}; /********************** * MACROS @@ -46,7 +48,7 @@ static const int16_t sin0_90_table[] = { * @param angle * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 */ -int16_t lv_trigo_sin(int16_t angle) +LV_ATTRIBUTE_FAST_MEM int16_t _lv_trigo_sin(int16_t angle) { int16_t ret = 0; angle = angle % 360; @@ -55,13 +57,16 @@ int16_t lv_trigo_sin(int16_t angle) if(angle < 90) { ret = sin0_90_table[angle]; - } else if(angle >= 90 && angle < 180) { + } + else if(angle >= 90 && angle < 180) { angle = 180 - angle; ret = sin0_90_table[angle]; - } else if(angle >= 180 && angle < 270) { + } + else if(angle >= 180 && angle < 270) { angle = angle - 180; ret = -sin0_90_table[angle]; - } else { /*angle >=270*/ + } + else { /*angle >=270*/ angle = 360 - angle; ret = -sin0_90_table[angle]; } @@ -78,7 +83,7 @@ int16_t lv_trigo_sin(int16_t angle) * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] */ -int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3) +uint32_t _lv_bezier3(uint32_t t, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) { uint32_t t_rem = 1024 - t; uint32_t t_rem2 = (t_rem * t_rem) >> 10; @@ -86,21 +91,48 @@ int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3) uint32_t t2 = (t * t) >> 10; uint32_t t3 = (t2 * t) >> 10; - uint32_t v1 = ((uint32_t)t_rem3 * u0) >> 10; - uint32_t v2 = ((uint32_t)3 * t_rem2 * t * u1) >> 20; - uint32_t v3 = ((uint32_t)3 * t_rem * t2 * u2) >> 20; - uint32_t v4 = ((uint32_t)t3 * u3) >> 10; + uint32_t v1 = (t_rem3 * u0) >> 10; + uint32_t v2 = (3 * t_rem2 * t * u1) >> 20; + uint32_t v3 = (3 * t_rem * t2 * u2) >> 20; + uint32_t v4 = (t3 * u3) >> 10; return v1 + v2 + v3 + v4; } /** + * Get the square root of a number + * @param x integer which square root should be calculated + * @param q store the result here. q->i: integer part, q->f: fractional part in 1/256 unit + * @param mask: optional to skip some iterations if the magnitude of the root is known. + * Set to 0x8000 by default. + * If root < 16: mask = 0x80 + * If root < 256: mask = 0x800 + * Else: mask = 0x8000 + */ +LV_ATTRIBUTE_FAST_MEM void _lv_sqrt(uint32_t x, lv_sqrt_res_t * q, uint32_t mask) +{ + x = x << 8; /*To get 4 bit precision. (sqrt(256) = 16 = 4 bit)*/ + + uint32_t root = 0; + uint32_t trial; + // http://ww1.microchip.com/...en/AppNotes/91040a.pdf + do { + trial = root + mask; + if(trial * trial <= x) root = trial; + mask = mask >> 1; + } while(mask); + + q->i = root >> 4; + q->f = (root & 0xf) << 4; +} + +/** * Calculate the atan2 of a vector. * @param x * @param y * @return the angle in degree calculated from the given parameters in range of [0..360] */ -uint16_t lv_atan2(int x, int y) +uint16_t _lv_atan2(int x, int y) { // Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com // Converts any XY values including 0 to a degree value that should be @@ -138,7 +170,8 @@ uint16_t lv_atan2(int x, int y) if(ux > uy) { degree = (uy * 45) / ux; // degree result will be 0-45 range negflag += 0x10; // octant flag bit - } else { + } + else { degree = (ux * 45) / uy; // degree result will be 0-45 range } @@ -150,7 +183,8 @@ uint16_t lv_atan2(int x, int y) if(tempdegree <= 41) comp++; if(tempdegree <= 37) comp++; if(tempdegree <= 32) comp++; // max is 4 degrees compensated - } else { // else is lower half of range + } + else { // else is lower half of range if(tempdegree >= 2) comp++; if(tempdegree >= 6) comp++; if(tempdegree >= 10) comp++; @@ -168,7 +202,8 @@ uint16_t lv_atan2(int x, int y) degree = (180 + degree); else // else is -Y +X degree = (180 - degree); - } else { // else is +Y + } + else { // else is +Y if(negflag & 0x01) // if +Y -X degree = (360 - degree); } @@ -176,26 +211,48 @@ uint16_t lv_atan2(int x, int y) } /** - * Calculate the integer square root of a number. - * @param num - * @return square root of 'num' + * Calculate the integer exponents. + * @param base + * @param power + * @return base raised to the power exponent */ -uint32_t lv_sqrt(uint32_t num) +int64_t _lv_pow(int64_t base, int8_t exp) { - // http://www.codecodex.com/wiki/Calculate_an_integer_square_root#C - uint32_t root = 0; - uint32_t place = 0x40000000; - - while(place > num) place >>= 2; - while(place) { - if(num >= root + place) { - num -= root + place; - root += (place << 1); - } - root >>= 1; - place >>= 2; + int64_t result = 1; + while(exp) { + if(exp & 1) + result *= base; + exp >>= 1; + base *= base; } - return root; + + return result; +} + +/** + * Get the mapped of a number given an input and output range + * @param x integer which mapped value should be calculated + * @param min_in min input range + * @param max_in max input range + * @param min_out max output range + * @param max_out max output range + * @return the mapped number + */ +int32_t _lv_map(int32_t x, int32_t min_in, int32_t max_in, int32_t min_out, int32_t max_out) +{ + if(x <= min_in) return min_out; + if(x >= max_in) return max_out; + + /* The equation should be: + * ((x - min_in) / delta in) * delta_out + min_out + * To avoid rounding error reorder the operations: + * (((x - min_in) * delta_out) / delta in) + min_out + */ + + int32_t delta_in = max_in - min_in; + int32_t delta_out = max_out - min_out; + + return ((x - min_in) * delta_out) / delta_in + min_out; } /********************** diff --git a/src/libs/lvgl/src/lv_misc/lv_math.h b/src/libs/lvgl/src/lv_misc/lv_math.h index 0f93a7c6..1730b431 100644 --- a/src/libs/lvgl/src/lv_misc/lv_math.h +++ b/src/libs/lvgl/src/lv_misc/lv_math.h @@ -1,5 +1,5 @@ /** - * @file math_base.h + * @file lv_math.h * */ @@ -13,15 +13,24 @@ extern "C" { /********************* * INCLUDES *********************/ +#include "../lv_conf_internal.h" #include <stdint.h> /********************* * DEFINES *********************/ #define LV_MATH_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define LV_MATH_MIN3(a, b, c) (LV_MATH_MIN(LV_MATH_MIN(a,b), c)) +#define LV_MATH_MIN4(a, b, c, d) (LV_MATH_MIN(LV_MATH_MIN(a,b), LV_MATH_MIN(c,d))) + #define LV_MATH_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define LV_MATH_MAX3(a, b, c) (LV_MATH_MAX(LV_MATH_MAX(a,b), c)) +#define LV_MATH_MAX4(a, b, c, d) (LV_MATH_MAX(LV_MATH_MAX(a,b), LV_MATH_MAX(c,d))) + #define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x))) +#define LV_MATH_UDIV255(x) ((uint32_t)((uint32_t) (x) * 0x8081) >> 0x17) + #define LV_IS_SIGNED(t) (((t)(-1)) < ((t) 0)) #define LV_UMAX_OF(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | (0xFULL << ((sizeof(t) * 8ULL) - 4ULL))) #define LV_SMAX_OF(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | (0x7ULL << ((sizeof(t) * 8ULL) - 4ULL))) @@ -37,16 +46,24 @@ extern "C" { * TYPEDEFS **********************/ +typedef struct { + uint16_t i; + uint16_t f; +} lv_sqrt_res_t; + /********************** * GLOBAL PROTOTYPES **********************/ +//! @cond Doxygen_Suppress /** * Return with sinus of an angle * @param angle * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 */ -int16_t lv_trigo_sin(int16_t angle); +LV_ATTRIBUTE_FAST_MEM int16_t _lv_trigo_sin(int16_t angle); + +//! @endcond /** * Calculate a value of a Cubic Bezier function. @@ -57,7 +74,7 @@ int16_t lv_trigo_sin(int16_t angle); * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] */ -int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); +uint32_t _lv_bezier3(uint32_t t, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3); /** * Calculate the atan2 of a vector. @@ -65,14 +82,42 @@ int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); * @param y * @return the angle in degree calculated from the given parameters in range of [0..360] */ -uint16_t lv_atan2(int x, int y); +uint16_t _lv_atan2(int x, int y); + +//! @cond Doxygen_Suppress + +/** + * Get the square root of a number + * @param x integer which square root should be calculated + * @param q store the result here. q->i: integer part, q->f: fractional part in 1/256 unit + * @param mask: optional to skip some iterations if the magnitude of the root is known. + * Set to 0x8000 by default. + * If root < 16: mask = 0x80 + * If root < 256: mask = 0x800 + * Else: mask = 0x8000 + */ +LV_ATTRIBUTE_FAST_MEM void _lv_sqrt(uint32_t x, lv_sqrt_res_t * q, uint32_t mask); + +//! @endcond + +/** + * Calculate the integer exponents. + * @param base + * @param power + * @return base raised to the power exponent + */ +int64_t _lv_pow(int64_t base, int8_t exp); /** - * Calculate the integer square root of a number. - * @param num - * @return square root of 'num' + * Get the mapped of a number given an input and output range + * @param x integer which mapped value should be calculated + * @param min_in min input range + * @param max_in max input range + * @param min_out max output range + * @param max_out max output range + * @return the mapped number */ -uint32_t lv_sqrt(uint32_t num); +int32_t _lv_map(int32_t x, int32_t min_in, int32_t max_in, int32_t min, int32_t max); /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_mem.c b/src/libs/lvgl/src/lv_misc/lv_mem.c index 9e18310f..7a7f9e8c 100644 --- a/src/libs/lvgl/src/lv_misc/lv_mem.c +++ b/src/libs/lvgl/src/lv_misc/lv_mem.c @@ -9,10 +9,11 @@ *********************/ #include "lv_mem.h" #include "lv_math.h" +#include "lv_gc.h" #include <string.h> #if LV_MEM_CUSTOM != 0 -#include LV_MEM_CUSTOM_INCLUDE + #include LV_MEM_CUSTOM_INCLUDE #endif /********************* @@ -20,13 +21,17 @@ *********************/ /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/ #ifndef LV_MEM_ADD_JUNK -#define LV_MEM_ADD_JUNK 0 + #define LV_MEM_ADD_JUNK 0 +#endif + +#ifndef LV_MEM_FULL_DEFRAG_CNT + #define LV_MEM_FULL_DEFRAG_CNT 16 #endif #ifdef LV_ARCH_64 -#define MEM_UNIT uint64_t + #define MEM_UNIT uint64_t #else -#define MEM_UNIT uint32_t + #define MEM_UNIT uint32_t #endif /********************** @@ -35,55 +40,77 @@ #if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/ -/*The size of this union must be 4 bytes (uint32_t)*/ -typedef union -{ - struct - { +/*The size of this union must be 4/8 bytes (uint32_t/uint64_t)*/ +typedef union { + struct { MEM_UNIT used : 1; /* 1: if the entry is used*/ - MEM_UNIT d_size : 31; /* Size off the data (1 means 4 bytes)*/ + MEM_UNIT d_size : 31; /* Size of the data*/ } s; MEM_UNIT header; /* The header (used + d_size)*/ } lv_mem_header_t; -typedef struct -{ +typedef struct { lv_mem_header_t header; uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/ } lv_mem_ent_t; #endif /* LV_ENABLE_GC */ +#ifdef LV_ARCH_64 + #define ALIGN_MASK 0x7 +#else + #define ALIGN_MASK 0x3 +#endif + +#define MEM_BUF_SMALL_SIZE 16 + /********************** * STATIC PROTOTYPES **********************/ #if LV_MEM_CUSTOM == 0 -static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e); -static void * ent_alloc(lv_mem_ent_t * e, size_t size); -static void ent_trunc(lv_mem_ent_t * e, size_t size); + static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e); + static void * ent_alloc(lv_mem_ent_t * e, size_t size); + static void ent_trunc(lv_mem_ent_t * e, size_t size); #endif /********************** * STATIC VARIABLES **********************/ #if LV_MEM_CUSTOM == 0 -static uint8_t * work_mem; + static uint8_t * work_mem; #endif static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/ +#if LV_MEM_CUSTOM == 0 + static uint32_t mem_max_size; /*Tracks the maximum total size of memory ever used from the internal heap*/ +#endif + +static uint8_t mem_buf1_32[MEM_BUF_SMALL_SIZE]; +static uint8_t mem_buf2_32[MEM_BUF_SMALL_SIZE]; + +static lv_mem_buf_t mem_buf_small[] = {{.p = mem_buf1_32, .size = MEM_BUF_SMALL_SIZE, .used = 0}, + {.p = mem_buf2_32, .size = MEM_BUF_SMALL_SIZE, .used = 0} +}; + /********************** * MACROS **********************/ +#define COPY32 *d32 = *s32; d32++; s32++; +#define COPY8 *d8 = *s8; d8++; s8++; +#define SET32(x) *d32 = x; d32++; +#define SET8(x) *d8 = x; d8++; +#define REPEAT8(expr) expr expr expr expr expr expr expr expr + /********************** * GLOBAL FUNCTIONS **********************/ /** - * Initiaiize the dyn_mem module (work memory and other variables) + * Initialize the dyn_mem module (work memory and other variables) */ -void lv_mem_init(void) +void _lv_mem_init(void) { #if LV_MEM_CUSTOM == 0 @@ -97,7 +124,7 @@ void lv_mem_init(void) lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem; full->header.s.used = 0; - /*The total mem size id reduced by the first header and the close patterns */ + /*The total mem size reduced by the first header and the close patterns */ full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t); #endif } @@ -106,13 +133,12 @@ void lv_mem_init(void) * Clean up the memory buffer which frees all the allocated memories. * @note It work only if `LV_MEM_CUSTOM == 0` */ -void lv_mem_deinit(void) +void _lv_mem_deinit(void) { #if LV_MEM_CUSTOM == 0 - memset(work_mem, 0x00, (LV_MEM_SIZE / sizeof(MEM_UNIT)) * sizeof(MEM_UNIT)); lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem; full->header.s.used = 0; - /*The total mem size id reduced by the first header and the close patterns */ + /*The total mem size reduced by the first header and the close patterns */ full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t); #endif } @@ -128,19 +154,8 @@ void * lv_mem_alloc(size_t size) return &zero_mem; } -#ifdef LV_ARCH_64 - /*Round the size up to 8*/ - if(size & 0x7) { - size = size & (~0x7); - size += 8; - } -#else - /*Round the size up to 4*/ - if(size & 0x3) { - size = size & (~0x3); - size += 4; - } -#endif + /*Round the size up to ALIGN_MASK*/ + size = (size + ALIGN_MASK) & (~ALIGN_MASK); void * alloc = NULL; #if LV_MEM_CUSTOM == 0 @@ -160,7 +175,7 @@ void * lv_mem_alloc(size_t size) } while(e != NULL && alloc == NULL); #else -/*Use custom, user defined malloc function*/ + /*Use custom, user defined malloc function*/ #if LV_ENABLE_GC == 1 /*gc must not include header*/ alloc = LV_MEM_CUSTOM_ALLOC(size); #else /* LV_ENABLE_GC */ @@ -176,10 +191,22 @@ void * lv_mem_alloc(size_t size) #endif /* LV_MEM_CUSTOM */ #if LV_MEM_ADD_JUNK - if(alloc != NULL) memset(alloc, 0xaa, size); + if(alloc != NULL) _lv_memset(alloc, 0xaa, size); #endif - if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory"); + if(alloc == NULL) { + LV_LOG_WARN("Couldn't allocate memory"); + } + else { +#if LV_MEM_CUSTOM == 0 + /* just a safety check, should always be true */ + if((uintptr_t) alloc > (uintptr_t) work_mem) { + if((((uintptr_t) alloc - (uintptr_t) work_mem) + size) > mem_max_size) { + mem_max_size = ((uintptr_t) alloc - (uintptr_t) work_mem) + size; + } + } +#endif + } return alloc; } @@ -194,7 +221,7 @@ void lv_mem_free(const void * data) if(data == NULL) return; #if LV_MEM_ADD_JUNK - memset((void *)data, 0xbb, lv_mem_get_size(data)); + _lv_memset((void *)data, 0xbb, _lv_mem_get_size(data)); #endif #if LV_ENABLE_GC == 0 @@ -205,19 +232,29 @@ void lv_mem_free(const void * data) #if LV_MEM_CUSTOM == 0 #if LV_MEM_AUTO_DEFRAG - /* Make a simple defrag. - * Join the following free entries after this*/ - lv_mem_ent_t * e_next; - e_next = ent_get_next(e); - while(e_next != NULL) { - if(e_next->header.s.used == 0) { - e->header.s.d_size += e_next->header.s.d_size + sizeof(e->header); - } else { - break; + static uint16_t full_defrag_cnt = 0; + full_defrag_cnt++; + if(full_defrag_cnt < LV_MEM_FULL_DEFRAG_CNT) { + /* Make a simple defrag. + * Join the following free entries after this*/ + lv_mem_ent_t * e_next; + e_next = ent_get_next(e); + while(e_next != NULL) { + if(e_next->header.s.used == 0) { + e->header.s.d_size += e_next->header.s.d_size + sizeof(e->header); + } + else { + break; + } + e_next = ent_get_next(e_next); } - e_next = ent_get_next(e_next); } -#endif + else { + full_defrag_cnt = 0; + lv_mem_defrag(); + + } +#endif /*LV_MEM_AUTO_DEFRAG*/ #else /*Use custom, user defined free function*/ #if LV_ENABLE_GC == 0 LV_MEM_CUSTOM_FREE(e); @@ -239,6 +276,9 @@ void lv_mem_free(const void * data) void * lv_mem_realloc(void * data_p, size_t new_size) { + /*Round the size up to ALIGN_MASK*/ + new_size = (new_size + ALIGN_MASK) & (~ALIGN_MASK); + /*data_p could be previously freed pointer (in this case it is invalid)*/ if(data_p != NULL) { lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data_p - sizeof(lv_mem_header_t)); @@ -247,7 +287,7 @@ void * lv_mem_realloc(void * data_p, size_t new_size) } } - uint32_t old_size = lv_mem_get_size(data_p); + uint32_t old_size = _lv_mem_get_size(data_p); if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/ #if LV_MEM_CUSTOM == 0 @@ -261,17 +301,19 @@ void * lv_mem_realloc(void * data_p, size_t new_size) void * new_p; new_p = lv_mem_alloc(new_size); + if(new_p == NULL) { + LV_LOG_WARN("Couldn't allocate memory"); + return NULL; + } - if(new_p != NULL && data_p != NULL) { + if(data_p != NULL) { /*Copy the old data to the new. Use the smaller size*/ - if(old_size != 0) { - memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size)); - lv_mem_free(data_p); + if(old_size != 0 && new_size != 0) { + _lv_memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size)); } + lv_mem_free(data_p); } - if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory"); - return new_p; } @@ -301,7 +343,8 @@ void lv_mem_defrag(void) while(e_free != NULL) { if(e_free->header.s.used != 0) { e_free = ent_get_next(e_free); - } else { + } + else { break; } } @@ -313,7 +356,8 @@ void lv_mem_defrag(void) while(e_next != NULL) { if(e_next->header.s.used == 0) { e_free->header.s.d_size += e_next->header.s.d_size + sizeof(e_next->header); - } else { + } + else { break; } @@ -328,6 +372,25 @@ void lv_mem_defrag(void) #endif } +lv_res_t lv_mem_test(void) +{ +#if LV_MEM_CUSTOM == 0 + lv_mem_ent_t * e; + e = ent_get_next(NULL); + while(e) { + if(e->header.s.d_size > LV_MEM_SIZE) { + return LV_RES_INV; + } + uint8_t * e8 = (uint8_t *) e; + if(e8 + e->header.s.d_size > work_mem + LV_MEM_SIZE) { + return LV_RES_INV; + } + e = ent_get_next(e); + } +#endif + return LV_RES_OK; +} + /** * Give information about the work memory of dynamic allocation * @param mon_p pointer to a dm_mon_p variable, @@ -336,12 +399,11 @@ void lv_mem_defrag(void) void lv_mem_monitor(lv_mem_monitor_t * mon_p) { /*Init the data*/ - memset(mon_p, 0, sizeof(lv_mem_monitor_t)); + _lv_memset(mon_p, 0, sizeof(lv_mem_monitor_t)); #if LV_MEM_CUSTOM == 0 lv_mem_ent_t * e; - e = NULL; - e = ent_get_next(e); + e = ent_get_next(NULL); while(e != NULL) { if(e->header.s.used == 0) { @@ -350,16 +412,23 @@ void lv_mem_monitor(lv_mem_monitor_t * mon_p) if(e->header.s.d_size > mon_p->free_biggest_size) { mon_p->free_biggest_size = e->header.s.d_size; } - } else { + } + else { mon_p->used_cnt++; } e = ent_get_next(e); } mon_p->total_size = LV_MEM_SIZE; - mon_p->used_pct = 100 - (100U * mon_p->free_size) / mon_p->total_size; - mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size; - mon_p->frag_pct = 100 - mon_p->frag_pct; + mon_p->max_used = mem_max_size; + mon_p->used_pct = 100 - (100U * mon_p->free_size) / mon_p->total_size; + if(mon_p->free_size > 0) { + mon_p->frag_pct = mon_p->free_biggest_size * 100U / mon_p->free_size; + mon_p->frag_pct = 100 - mon_p->frag_pct; + } + else { + mon_p->frag_pct = 0; /*no fragmentation if all the RAM is used*/ + } #endif } @@ -371,7 +440,7 @@ void lv_mem_monitor(lv_mem_monitor_t * mon_p) #if LV_ENABLE_GC == 0 -uint32_t lv_mem_get_size(const void * data) +uint32_t _lv_mem_get_size(const void * data) { if(data == NULL) return 0; if(data == &zero_mem) return 0; @@ -383,13 +452,306 @@ uint32_t lv_mem_get_size(const void * data) #else /* LV_ENABLE_GC */ -uint32_t lv_mem_get_size(const void * data) +uint32_t _lv_mem_get_size(const void * data) { return LV_MEM_CUSTOM_GET_SIZE(data); } #endif /*LV_ENABLE_GC*/ +/** + * Get a temporal buffer with the given size. + * @param size the required size + */ +void * _lv_mem_buf_get(uint32_t size) +{ + if(size == 0) return NULL; + + /*Try small static buffers first*/ + uint8_t i; + if(size <= MEM_BUF_SMALL_SIZE) { + for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) { + if(mem_buf_small[i].used == 0) { + mem_buf_small[i].used = 1; + return mem_buf_small[i].p; + } + } + } + + /*Try to find a free buffer with suitable size */ + int8_t i_guess = -1; + for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) { + if(LV_GC_ROOT(_lv_mem_buf[i]).used == 0 && LV_GC_ROOT(_lv_mem_buf[i]).size >= size) { + if(LV_GC_ROOT(_lv_mem_buf[i]).size == size) { + LV_GC_ROOT(_lv_mem_buf[i]).used = 1; + return LV_GC_ROOT(_lv_mem_buf[i]).p; + } + else if(i_guess < 0) { + i_guess = i; + } + /*If size of `i` is closer to `size` prefer it*/ + else if(LV_GC_ROOT(_lv_mem_buf[i]).size < LV_GC_ROOT(_lv_mem_buf[i_guess]).size) { + i_guess = i; + } + } + } + + if(i_guess >= 0) { + LV_GC_ROOT(_lv_mem_buf[i_guess]).used = 1; + return LV_GC_ROOT(_lv_mem_buf[i_guess]).p; + } + + /*Reallocate a free buffer*/ + for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) { + if(LV_GC_ROOT(_lv_mem_buf[i]).used == 0) { + /*if this fails you probably need to increase your LV_MEM_SIZE/heap size*/ + void * buf = lv_mem_realloc(LV_GC_ROOT(_lv_mem_buf[i]).p, size); + if(buf == NULL) { + LV_DEBUG_ASSERT(false, "Out of memory, can't allocate a new buffer (increase your LV_MEM_SIZE/heap size)", 0x00); + return NULL; + } + LV_GC_ROOT(_lv_mem_buf[i]).used = 1; + LV_GC_ROOT(_lv_mem_buf[i]).size = size; + LV_GC_ROOT(_lv_mem_buf[i]).p = buf; + return LV_GC_ROOT(_lv_mem_buf[i]).p; + } + } + + LV_DEBUG_ASSERT(false, "No free buffer. Increase LV_MEM_BUF_MAX_NUM.", 0x00); + return NULL; +} + +/** + * Release a memory buffer + * @param p buffer to release + */ +void _lv_mem_buf_release(void * p) +{ + uint8_t i; + + /*Try small static buffers first*/ + for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) { + if(mem_buf_small[i].p == p) { + mem_buf_small[i].used = 0; + return; + } + } + + for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) { + if(LV_GC_ROOT(_lv_mem_buf[i]).p == p) { + LV_GC_ROOT(_lv_mem_buf[i]).used = 0; + return; + } + } + + LV_LOG_ERROR("lv_mem_buf_release: p is not a known buffer") +} + +/** + * Free all memory buffers + */ +void _lv_mem_buf_free_all(void) +{ + uint8_t i; + for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) { + mem_buf_small[i].used = 0; + } + + for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) { + if(LV_GC_ROOT(_lv_mem_buf[i]).p) { + lv_mem_free(LV_GC_ROOT(_lv_mem_buf[i]).p); + LV_GC_ROOT(_lv_mem_buf[i]).p = NULL; + LV_GC_ROOT(_lv_mem_buf[i]).used = 0; + LV_GC_ROOT(_lv_mem_buf[i]).size = 0; + } + } +} + +#if LV_MEMCPY_MEMSET_STD == 0 +/** + * Same as `memcpy` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +LV_ATTRIBUTE_FAST_MEM void * _lv_memcpy(void * dst, const void * src, size_t len) +{ + uint8_t * d8 = dst; + const uint8_t * s8 = src; + + lv_uintptr_t d_align = (lv_uintptr_t)d8 & ALIGN_MASK; + lv_uintptr_t s_align = (lv_uintptr_t)s8 & ALIGN_MASK; + + /*Byte copy for unaligned memories*/ + if(s_align != d_align) { + while(len > 32) { + REPEAT8(COPY8); + REPEAT8(COPY8); + REPEAT8(COPY8); + REPEAT8(COPY8); + len -= 32; + } + while(len) { + COPY8 + len--; + } + return dst; + } + + /*Make the memories aligned*/ + if(d_align) { + d_align = ALIGN_MASK + 1 - d_align; + while(d_align && len) { + COPY8; + d_align--; + len--; + } + } + + uint32_t * d32 = (uint32_t *)d8; + const uint32_t * s32 = (uint32_t *)s8; + while(len > 32) { + REPEAT8(COPY32) + len -= 32; + } + + while(len > 4) { + COPY32; + len -= 4; + } + + d8 = (uint8_t *)d32; + s8 = (const uint8_t *)s32; + while(len) { + COPY8 + len--; + } + + return dst; +} + +/** + * Same as `memset` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param v value to set [0..255] + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void _lv_memset(void * dst, uint8_t v, size_t len) +{ + + uint8_t * d8 = (uint8_t *) dst; + + uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK; + + /*Make the address aligned*/ + if(d_align) { + d_align = ALIGN_MASK + 1 - d_align; + while(d_align && len) { + SET8(v); + len--; + d_align--; + } + } + + uint32_t v32 = v + (v << 8) + (v << 16) + (v << 24); + + uint32_t * d32 = (uint32_t *)d8; + + while(len > 32) { + REPEAT8(SET32(v32)); + len -= 32; + } + + while(len > 4) { + SET32(v32); + len -= 4; + } + + d8 = (uint8_t *)d32; + while(len) { + SET8(v); + len--; + } +} + +/** + * Same as `memset(dst, 0x00, len)` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void _lv_memset_00(void * dst, size_t len) +{ + uint8_t * d8 = (uint8_t *) dst; + uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK; + + /*Make the address aligned*/ + if(d_align) { + d_align = ALIGN_MASK + 1 - d_align; + while(d_align && len) { + SET8(0); + len--; + d_align--; + } + } + + uint32_t * d32 = (uint32_t *)d8; + while(len > 32) { + REPEAT8(SET32(0)); + len -= 32; + } + + while(len > 4) { + SET32(0); + len -= 4; + } + + d8 = (uint8_t *)d32; + while(len) { + SET8(0); + len--; + } +} + +/** + * Same as `memset(dst, 0xFF, len)` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void _lv_memset_ff(void * dst, size_t len) +{ + uint8_t * d8 = (uint8_t *) dst; + uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK; + + /*Make the address aligned*/ + if(d_align) { + d_align = ALIGN_MASK + 1 - d_align; + while(d_align && len) { + SET8(0xFF); + len--; + d_align--; + } + } + + uint32_t * d32 = (uint32_t *)d8; + while(len > 32) { + REPEAT8(SET32(0xFFFFFFFF)); + len -= 32; + } + + while(len > 4) { + SET32(0xFFFFFFFF); + len -= 4; + } + + d8 = (uint8_t *)d32; + while(len) { + SET8(0xFF); + len--; + } +} + +#endif /*LV_MEMCPY_MEMSET_STD*/ + /********************** * STATIC FUNCTIONS **********************/ @@ -406,7 +768,8 @@ static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e) if(act_e == NULL) { /*NULL means: get the first entry*/ next_e = (lv_mem_ent_t *)work_mem; - } else { /*Get the next entry */ + } + else { /*Get the next entry */ uint8_t * data = &act_e->first_data; next_e = (lv_mem_ent_t *)&data[act_e->header.s.d_size]; @@ -425,13 +788,11 @@ static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e) static void * ent_alloc(lv_mem_ent_t * e, size_t size) { void * alloc = NULL; - /*If the memory is free and big enough then use it */ if(e->header.s.used == 0 && e->header.s.d_size >= size) { /*Truncate the entry to the desired size */ - ent_trunc(e, size), - - e->header.s.used = 1; + ent_trunc(e, size); + e->header.s.used = 1; /*Save the allocated data*/ alloc = &e->first_data; @@ -447,19 +808,8 @@ static void * ent_alloc(lv_mem_ent_t * e, size_t size) */ static void ent_trunc(lv_mem_ent_t * e, size_t size) { -#ifdef LV_ARCH_64 - /*Round the size up to 8*/ - if(size & 0x7) { - size = size & (~0x7); - size += 8; - } -#else - /*Round the size up to 4*/ - if(size & 0x3) { - size = size & (~0x3); - size += 4; - } -#endif + /*Round the size up to ALIGN_MASK*/ + size = (size + ALIGN_MASK) & (~ALIGN_MASK); /*Don't let empty space only for a header without data*/ if(e->header.s.d_size == size + sizeof(lv_mem_header_t)) { @@ -472,10 +822,10 @@ static void ent_trunc(lv_mem_ent_t * e, size_t size) lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size]; after_new_e->header.s.used = 0; after_new_e->header.s.d_size = (uint32_t)e->header.s.d_size - size - sizeof(lv_mem_header_t); - } - /* Set the new size for the original entry */ - e->header.s.d_size = (uint32_t)size; + /* Set the new size for the original entry */ + e->header.s.d_size = (uint32_t)size; + } } #endif diff --git a/src/libs/lvgl/src/lv_misc/lv_mem.h b/src/libs/lvgl/src/lv_misc/lv_mem.h index f7240742..9c20a23f 100644 --- a/src/libs/lvgl/src/lv_misc/lv_mem.h +++ b/src/libs/lvgl/src/lv_misc/lv_mem.h @@ -13,21 +13,25 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include <stdint.h> #include <stddef.h> #include "lv_log.h" #include "lv_types.h" +#if LV_MEMCPY_MEMSET_STD +#include <string.h> +#endif + /********************* * DEFINES *********************/ +#ifndef LV_MEM_BUF_MAX_NUM +#define LV_MEM_BUF_MAX_NUM 16 +#endif + /********************** * TYPEDEFS **********************/ @@ -35,31 +39,40 @@ extern "C" { /** * Heap information structure. */ -typedef struct -{ +typedef struct { uint32_t total_size; /**< Total heap size */ uint32_t free_cnt; uint32_t free_size; /**< Size of available memory */ uint32_t free_biggest_size; uint32_t used_cnt; + uint32_t max_used; /**< Max size of Heap memory used */ uint8_t used_pct; /**< Percentage used */ uint8_t frag_pct; /**< Amount of fragmentation */ } lv_mem_monitor_t; +typedef struct { + void * p; + uint16_t size; + uint8_t used : 1; +} lv_mem_buf_t; + +typedef lv_mem_buf_t lv_mem_buf_arr_t[LV_MEM_BUF_MAX_NUM]; +extern lv_mem_buf_arr_t _lv_mem_buf; + /********************** * GLOBAL PROTOTYPES **********************/ /** - * Initiaize the dyn_mem module (work memory and other variables) + * Initialize the dyn_mem module (work memory and other variables) */ -void lv_mem_init(void); +void _lv_mem_init(void); /** * Clean up the memory buffer which frees all the allocated memories. * @note It work only if `LV_MEM_CUSTOM == 0` */ -void lv_mem_deinit(void); +void _lv_mem_deinit(void); /** * Allocate a memory dynamically @@ -89,6 +102,12 @@ void * lv_mem_realloc(void * data_p, size_t new_size); void lv_mem_defrag(void); /** + * + * @return + */ +lv_res_t lv_mem_test(void); + +/** * Give information about the work memory of dynamic allocation * @param mon_p pointer to a dm_mon_p variable, * the result of the analysis will be stored here @@ -100,7 +119,137 @@ void lv_mem_monitor(lv_mem_monitor_t * mon_p); * @param data pointer to an allocated memory * @return the size of data memory in bytes */ -uint32_t lv_mem_get_size(const void * data); +uint32_t _lv_mem_get_size(const void * data); + +/** + * Get a temporal buffer with the given size. + * @param size the required size + */ +void * _lv_mem_buf_get(uint32_t size); + +/** + * Release a memory buffer + * @param p buffer to release + */ +void _lv_mem_buf_release(void * p); + +/** + * Free all memory buffers + */ +void _lv_mem_buf_free_all(void); + +//! @cond Doxygen_Suppress + +#if LV_MEMCPY_MEMSET_STD + +/** + * Wrapper for the standard memcpy + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +static inline void * _lv_memcpy(void * dst, const void * src, size_t len) +{ + return memcpy(dst, src, len); +} + +/** + * Wrapper for the standard memcpy + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +static inline void * _lv_memcpy_small(void * dst, const void * src, size_t len) +{ + return memcpy(dst, src, len); +} + +/** + * Wrapper for the standard memset + * @param dst pointer to the destination buffer + * @param v value to set [0..255] + * @param len number of byte to set + */ +static inline void _lv_memset(void * dst, uint8_t v, size_t len) +{ + memset(dst, v, len); +} + +/** + * Wrapper for the standard memset with fixed 0x00 value + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +static inline void _lv_memset_00(void * dst, size_t len) +{ + memset(dst, 0x00, len); +} + +/** + * Wrapper for the standard memset with fixed 0xFF value + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +static inline void _lv_memset_ff(void * dst, size_t len) +{ + memset(dst, 0xFF, len); +} + +#else +/** + * Same as `memcpy` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +LV_ATTRIBUTE_FAST_MEM void * _lv_memcpy(void * dst, const void * src, size_t len); + +/** + * Same as `memcpy` but optimized to copy only a few bytes. + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +LV_ATTRIBUTE_FAST_MEM static inline void * _lv_memcpy_small(void * dst, const void * src, size_t len) +{ + uint8_t * d8 = (uint8_t *)dst; + const uint8_t * s8 = (const uint8_t *)src; + + while(len) { + *d8 = *s8; + d8++; + s8++; + len--; + } + + return dst; +} + +/** + * Same as `memset` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param v value to set [0..255] + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void _lv_memset(void * dst, uint8_t v, size_t len); + +/** + * Same as `memset(dst, 0x00, len)` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void _lv_memset_00(void * dst, size_t len); + +/** + * Same as `memset(dst, 0xFF, len)` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void _lv_memset_ff(void * dst, size_t len); + +//! @endcond + +#endif /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_misc.mk b/src/libs/lvgl/src/lv_misc/lv_misc.mk index 67f496ba..898a248d 100644 --- a/src/libs/lvgl/src/lv_misc/lv_misc.mk +++ b/src/libs/lvgl/src/lv_misc/lv_misc.mk @@ -1,4 +1,3 @@ -CSRCS += lv_circ.c CSRCS += lv_area.c CSRCS += lv_task.c CSRCS += lv_fs.c @@ -7,6 +6,7 @@ CSRCS += lv_mem.c CSRCS += lv_ll.c CSRCS += lv_color.c CSRCS += lv_txt.c +CSRCS += lv_txt_ap.c CSRCS += lv_math.c CSRCS += lv_log.c CSRCS += lv_gc.c @@ -14,9 +14,9 @@ CSRCS += lv_utils.c CSRCS += lv_async.c CSRCS += lv_printf.c CSRCS += lv_bidi.c +CSRCS += lv_debug.c +DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc +VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc -DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_misc -VPATH += :$(LVGL_DIR)/lvgl/src/lv_misc - -CFLAGS += "-I$(LVGL_DIR)/lvgl/src/lv_misc" +CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc" diff --git a/src/libs/lvgl/src/lv_misc/lv_printf.c b/src/libs/lvgl/src/lv_misc/lv_printf.c index e05f35be..bb6f3430 100644 --- a/src/libs/lvgl/src/lv_misc/lv_printf.c +++ b/src/libs/lvgl/src/lv_misc/lv_printf.c @@ -37,56 +37,57 @@ #include <stdbool.h> #include <stdint.h> +#define PRINTF_DISABLE_SUPPORT_FLOAT LV_SPRINTF_DISABLE_FLOAT // 'ntoa' conversion buffer size, this must be big enough to hold one converted // numeric number including padded zeros (dynamically created on stack) // default: 32 byte #ifndef PRINTF_NTOA_BUFFER_SIZE -#define PRINTF_NTOA_BUFFER_SIZE 32U + #define PRINTF_NTOA_BUFFER_SIZE 32U #endif // 'ftoa' conversion buffer size, this must be big enough to hold one converted // float number including padded zeros (dynamically created on stack) // default: 32 byte #ifndef PRINTF_FTOA_BUFFER_SIZE -#define PRINTF_FTOA_BUFFER_SIZE 32U + #define PRINTF_FTOA_BUFFER_SIZE 32U #endif // support for the floating point type (%f) // default: activated -#ifndef PRINTF_DISABLE_SUPPORT_FLOAT -#define PRINTF_SUPPORT_FLOAT +#if !PRINTF_DISABLE_SUPPORT_FLOAT + #define PRINTF_SUPPORT_FLOAT #endif // support for exponential floating point notation (%e/%g) // default: activated #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL -#define PRINTF_SUPPORT_EXPONENTIAL + #define PRINTF_SUPPORT_EXPONENTIAL #endif // define the default floating point precision // default: 6 digits #ifndef PRINTF_DEFAULT_FLOAT_PRECISION -#define PRINTF_DEFAULT_FLOAT_PRECISION 6U + #define PRINTF_DEFAULT_FLOAT_PRECISION 6U #endif // define the largest float suitable to print with %f // default: 1e9 #ifndef PRINTF_MAX_FLOAT -#define PRINTF_MAX_FLOAT 1e9 + #define PRINTF_MAX_FLOAT 1e9 #endif // support for the long long types (%llu or %p) // default: activated #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG -#define PRINTF_SUPPORT_LONG_LONG + #define PRINTF_SUPPORT_LONG_LONG #endif // support for the ptrdiff_t type (%t) // ptrdiff_t is normally defined in <stddef.h> as long or long long type // default: activated #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T -#define PRINTF_SUPPORT_PTRDIFF_T + #define PRINTF_SUPPORT_PTRDIFF_T #endif /////////////////////////////////////////////////////////////////////////////// @@ -105,748 +106,769 @@ #define FLAGS_PRECISION (1U << 10U) #define FLAGS_ADAPT_EXP (1U << 11U) - // import float.h for DBL_MAX #if defined(PRINTF_SUPPORT_FLOAT) -#include <float.h> + #include <float.h> #endif - // output function type -typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); - +typedef void (*out_fct_type)(char character, void * buffer, size_t idx, size_t maxlen); // wrapper (used as buffer) for output function type typedef struct { - void (*fct)(char character, void* arg); - void* arg; + void (*fct)(char character, void * arg); + void * arg; } out_fct_wrap_type; - // internal buffer output -static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +static inline void _out_buffer(char character, void * buffer, size_t idx, size_t maxlen) { - if (idx < maxlen) { - ((char*)buffer)[idx] = character; - } + if(idx < maxlen) { + ((char *)buffer)[idx] = character; + } } - // internal null output -static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +static inline void _out_null(char character, void * buffer, size_t idx, size_t maxlen) { - (void)character; (void)buffer; (void)idx; (void)maxlen; + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; } - - // internal secure strlen // \return The length of the string (excluding the terminating 0) limited by 'maxsize' -static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +static inline unsigned int _strnlen_s(const char * str, size_t maxsize) { - const char* s; - for (s = str; *s && maxsize--; ++s); - return (unsigned int)(s - str); + const char * s; + for(s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); } - // internal test if char is a digit (0-9) // \return true if char is a digit static inline bool _is_digit(char ch) { - return (ch >= '0') && (ch <= '9'); + return (ch >= '0') && (ch <= '9'); } - // internal ASCII string to unsigned int conversion -static unsigned int _atoi(const char** str) +static unsigned int _atoi(const char ** str) { - unsigned int i = 0U; - while (_is_digit(**str)) { - i = i * 10U + (unsigned int)(*((*str)++) - '0'); - } - return i; + unsigned int i = 0U; + while(_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; } - // output the specified string in reverse, taking care of any zero-padding -static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +static size_t _out_rev(out_fct_type out, char * buffer, size_t idx, size_t maxlen, const char * buf, size_t len, + unsigned int width, unsigned int flags) { - const size_t start_idx = idx; + const size_t start_idx = idx; - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - size_t i; - for (i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); + // pad spaces up to given width + if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + size_t i; + for(i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } } - } - // reverse string - while (len) { - out(buf[--len], buffer, idx++, maxlen); - } + // reverse string + while(len) { + out(buf[--len], buffer, idx++, maxlen); + } - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) { - out(' ', buffer, idx++, maxlen); + // append pad spaces up to given width + if(flags & FLAGS_LEFT) { + while(idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } } - } - return idx; + return idx; } - // internal itoa format -static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +static size_t _ntoa_format(out_fct_type out, char * buffer, size_t idx, size_t maxlen, char * buf, size_t len, + bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) { - // pad leading zeros - if (!(flags & FLAGS_LEFT)) { - if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; - } - while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; + // pad leading zeros + if(!(flags & FLAGS_LEFT)) { + if(width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } } - } - // handle hash - if (flags & FLAGS_HASH) { - if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { - len--; - if (len && (base == 16U)) { - len--; - } - } - if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'x'; - } - else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'X'; - } - else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'b'; - } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - buf[len++] = '0'; + // handle hash + if(flags & FLAGS_HASH) { + if(!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if(len && (base == 16U)) { + len--; + } + } + if((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if(len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } } - } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; + if(len < PRINTF_NTOA_BUFFER_SIZE) { + if(negative) { + buf[len++] = '-'; + } + else if(flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if(flags & FLAGS_SPACE) { + buf[len++] = ' '; + } } - } - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); } - // internal itoa for 'long' type -static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +static size_t _ntoa_long(out_fct_type out, char * buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, + unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) { - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; - - // no hash for 0 values - if (!value) { - flags &= ~FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } - - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if(!value) { + flags &= ~FLAGS_HASH; + } + // write if precision != 0 and value is != 0 + if(!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while(value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} // internal itoa for 'long long' type #if defined(PRINTF_SUPPORT_LONG_LONG) -static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +static size_t _ntoa_long_long(out_fct_type out, char * buffer, size_t idx, size_t maxlen, unsigned long long value, + bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) { - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; - - // no hash for 0 values - if (!value) { - flags &= ~FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } - - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if(!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if(!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while(value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); } #endif // PRINTF_SUPPORT_LONG_LONG - #if defined(PRINTF_SUPPORT_FLOAT) #if defined(PRINTF_SUPPORT_EXPONENTIAL) // forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT -static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +static size_t _etoa(out_fct_type out, char * buffer, size_t idx, size_t maxlen, double value, unsigned int prec, + unsigned int width, unsigned int flags); #endif - // internal ftoa for fixed decimal floating point -static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +static size_t _ftoa(out_fct_type out, char * buffer, size_t idx, size_t maxlen, double value, unsigned int prec, + unsigned int width, unsigned int flags) { - char buf[PRINTF_FTOA_BUFFER_SIZE]; - size_t len = 0U; - double diff = 0.0; - - // powers of 10 - static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; - - // test for special values - if (value != value) - return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); - if (value < -DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); - if (value > DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); - - // test for very large values - // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad - if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if(value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if(value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if(value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, + flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { #if defined(PRINTF_SUPPORT_EXPONENTIAL) - return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); #else - return 0U; + return 0U; #endif - } - - // test for negative - bool negative = false; - if (value < 0) { - negative = true; - value = 0 - value; - } - - // set default precision, if not set explicitly - if (!(flags & FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; - } - // limit precision to 9, cause a prec >= 10 can lead to overflow errors - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { - buf[len++] = '0'; - prec--; - } - - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; - unsigned long frac = (unsigned long)tmp; - diff = tmp - frac; - - if (diff > 0.5) { - ++frac; - // handle rollover, e.g. case 0.99 with prec 1 is 1.0 - if (frac >= pow10[prec]) { - frac = 0; - ++whole; - } - } - else if (diff < 0.5) { - } - else if ((frac == 0U) || (frac & 1U)) { - // if halfway, round up if odd OR if last digit is 0 - ++frac; - } - - if (prec == 0U) { - diff = value - (double)whole; - if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++whole; - } - } - else { - unsigned int count = prec; - // now do fractional part, as an unsigned number - while (len < PRINTF_FTOA_BUFFER_SIZE) { - --count; - buf[len++] = (char)(48U + (frac % 10U)); - if (!(frac /= 10U)) { - break; - } - } - // add extra 0s - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { - buf[len++] = '0'; - } - if (len < PRINTF_FTOA_BUFFER_SIZE) { - // add decimal - buf[len++] = '.'; - } - } - - // do whole part, number is reversed - while (len < PRINTF_FTOA_BUFFER_SIZE) { - buf[len++] = (char)(48 + (whole % 10)); - if (!(whole /= 10)) { - break; - } - } - - // pad leading zeros - if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { - if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; - } - while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_FTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} + } + + // test for negative + bool negative = false; + if(value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if(!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if(diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if(frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if(diff < 0.5) { + } + else if((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if(prec == 0U) { + diff = value - (double)whole; + if((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while(len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if(!(frac /= 10U)) { + break; + } + } + // add extra 0s + while((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if(len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + // do whole part, number is reversed + while(len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if(!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if(!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if(width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if(len < PRINTF_FTOA_BUFFER_SIZE) { + if(negative) { + buf[len++] = '-'; + } + else if(flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if(flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} #if defined(PRINTF_SUPPORT_EXPONENTIAL) // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com> -static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +static size_t _etoa(out_fct_type out, char * buffer, size_t idx, size_t maxlen, double value, unsigned int prec, + unsigned int width, unsigned int flags) { - // check for NaN and special values - if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { - return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); - } - - // determine the sign - const bool negative = value < 0; - if (negative) { - value = -value; - } - - // default precision - if (!(flags & FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; - } - - // determine the decimal exponent - // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) - union { - uint64_t U; - double F; - } conv; - - conv.F = value; - int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 - conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) - // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 - int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); - // now we want to compute 10^expval but we want to be sure it won't overflow - exp2 = (int)(expval * 3.321928094887362 + 0.5); - const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - conv.U = (uint64_t)(exp2 + 1023) << 52U; - // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); - // correct for rounding errors - if (value < conv.F) { - expval--; - conv.F /= 10; - } - - // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters - unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; - - // in "%g" mode, "prec" is the number of *significant figures* not decimals - if (flags & FLAGS_ADAPT_EXP) { - // do we want to fall-back to "%f" mode? - if ((value >= 1e-4) && (value < 1e6)) { - if ((int)prec > expval) { - prec = (unsigned)((int)prec - expval - 1); - } - else { - prec = 0; - } - flags |= FLAGS_PRECISION; // make sure _ftoa respects precision - // no characters in exponent - minwidth = 0U; - expval = 0; + // check for NaN and special values + if((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if(negative) { + value = -value; + } + + // default precision + if(!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if(value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if(flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if((value >= 1e-4) && (value < 1e6)) { + if((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } + else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else { + // we use one sigfig for the whole part + if((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if(width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; } else { - // we use one sigfig for the whole part - if ((prec > 0) && (flags & FLAGS_PRECISION)) { - --prec; - } - } - } - - // will everything fit? - unsigned int fwidth = width; - if (width > minwidth) { - // we didn't fall-back so subtract the characters required for the exponent - fwidth -= minwidth; - } else { - // not enough characters, so go back to default sizing - fwidth = 0U; - } - if ((flags & FLAGS_LEFT) && minwidth) { - // if we're padding on the right, DON'T pad the floating part - fwidth = 0U; - } - - // rescale the float value - if (expval) { - value /= conv.F; - } - - // output the floating part - const size_t start_idx = idx; - idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); - - // output the exponent part - if (minwidth) { - // output the exponential symbol - out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); - // output the exponent value - idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); - // might need to right-pad spaces - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); - } - } - return idx; + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if(expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if(minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, + FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if(flags & FLAGS_LEFT) { + while(idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; } #endif // PRINTF_SUPPORT_EXPONENTIAL #endif // PRINTF_SUPPORT_FLOAT - // internal vsnprintf -static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +static int _vsnprintf(out_fct_type out, char * buffer, const size_t maxlen, const char * format, va_list va) { - unsigned int flags, width, precision, n; - size_t idx = 0U; - - if (!buffer) { - // use null output function - out = _out_null; - } - - while (*format) - { - // format specifier? %[flags][width][.precision][length] - if (*format != '%') { - // no - out(*format, buffer, idx++, maxlen); - format++; - continue; + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if(!buffer) { + // use null output function + out = _out_null; } - else { - // yes, evaluate it - format++; - } - - // evaluate flags - flags = 0U; - do { - switch (*format) { - case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; - case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; - case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; - case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; - case '#': flags |= FLAGS_HASH; format++; n = 1U; break; - default : n = 0U; break; - } - } while (n); - - // evaluate width field - width = 0U; - if (_is_digit(*format)) { - width = _atoi(&format); - } - else if (*format == '*') { - const int w = va_arg(va, int); - if (w < 0) { - flags |= FLAGS_LEFT; // reverse padding - width = (unsigned int)-w; - } - else { - width = (unsigned int)w; - } - format++; - } - - // evaluate precision field - precision = 0U; - if (*format == '.') { - flags |= FLAGS_PRECISION; - format++; - if (_is_digit(*format)) { - precision = _atoi(&format); - } - else if (*format == '*') { - const int prec = (int)va_arg(va, int); - precision = prec > 0 ? (unsigned int)prec : 0U; - format++; - } - } - - // evaluate length field - switch (*format) { - case 'l' : - flags |= FLAGS_LONG; - format++; - if (*format == 'l') { - flags |= FLAGS_LONG_LONG; - format++; - } - break; - case 'h' : - flags |= FLAGS_SHORT; - format++; - if (*format == 'h') { - flags |= FLAGS_CHAR; - format++; - } - break; -#if defined(PRINTF_SUPPORT_PTRDIFF_T) - case 't' : - flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; -#endif - case 'j' : - flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; - case 'z' : - flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; - default : - break; - } - - // evaluate specifier - switch (*format) { - case 'd' : - case 'i' : - case 'u' : - case 'x' : - case 'X' : - case 'o' : - case 'b' : { - // set the base - unsigned int base; - if (*format == 'x' || *format == 'X') { - base = 16U; - } - else if (*format == 'o') { - base = 8U; - } - else if (*format == 'b') { - base = 2U; + + while(*format) { + // format specifier? %[flags][width][.precision][length] + if(*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; } else { - base = 10U; - flags &= ~FLAGS_HASH; // no hash for dec format + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch(*format) { + case '0': + flags |= FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= FLAGS_HASH; + format++; + n = 1U; + break; + default : + n = 0U; + break; + } + } while(n); + + // evaluate width field + width = 0U; + if(_is_digit(*format)) { + width = _atoi(&format); } - // uppercase - if (*format == 'X') { - flags |= FLAGS_UPPERCASE; + else if(*format == '*') { + const int w = va_arg(va, int); + if(w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int) - w; + } + else { + width = (unsigned int)w; + } + format++; } - // no plus or space flag for u, x, X, o, b - if ((*format != 'i') && (*format != 'd')) { - flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + // evaluate precision field + precision = 0U; + if(*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if(_is_digit(*format)) { + precision = _atoi(&format); + } + else if(*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } } - // ignore '0' flag when precision is given - if (flags & FLAGS_PRECISION) { - flags &= ~FLAGS_ZEROPAD; + // evaluate length field + switch(*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if(*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if(*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; } - // convert the integer - if ((*format == 'i') || (*format == 'd')) { - // signed - if (flags & FLAGS_LONG_LONG) { + // evaluate specifier + switch(*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if(*format == 'x' || *format == 'X') { + base = 16U; + } + else if(*format == 'o') { + base = 8U; + } + else if(*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if(*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if(flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if((*format == 'i') || (*format == 'd')) { + // signed + if(flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - const long long value = va_arg(va, long long); - idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, + precision, width, flags); #endif - } - else if (flags & FLAGS_LONG) { - const long value = va_arg(va, long); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); - } - else { - const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); - } - } - else { - // unsigned - if (flags & FLAGS_LONG_LONG) { + } + else if(flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, + width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, + int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, + width, flags); + } + } + else { + // unsigned + if(flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); #endif - } - else if (flags & FLAGS_LONG) { - idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); - } - else { - const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); - idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); - } - } - format++; - break; - } + } + else if(flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, + unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } #if defined(PRINTF_SUPPORT_FLOAT) - case 'f' : - case 'F' : - if (*format == 'F') flags |= FLAGS_UPPERCASE; - idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); - format++; - break; + case 'f' : + case 'F' : + if(*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; #if defined(PRINTF_SUPPORT_EXPONENTIAL) - case 'e': - case 'E': - case 'g': - case 'G': - if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; - if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; - idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); - format++; - break; + case 'e': + case 'E': + case 'g': + case 'G': + if((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; #endif // PRINTF_SUPPORT_EXPONENTIAL #endif // PRINTF_SUPPORT_FLOAT - case 'c' : { - unsigned int l = 1U; - // pre padding - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - // char output - out((char)va_arg(va, int), buffer, idx++, maxlen); - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } - - case 's' : { - const char* p = va_arg(va, char*); - unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); - // pre padding - if (flags & FLAGS_PRECISION) { - l = (l < precision ? l : precision); - } - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - // string output - while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { - out(*(p++), buffer, idx++, maxlen); - } - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } - - case 'p' : { - width = sizeof(void*) * 2U; - flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; + case 'c' : { + unsigned int l = 1U; + // pre padding + if(!(flags & FLAGS_LEFT)) { + while(l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if(flags & FLAGS_LEFT) { + while(l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char * p = va_arg(va, char *); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t) -1); + // pre padding + if(flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if(!(flags & FLAGS_LEFT)) { + while(l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if(flags & FLAGS_LEFT) { + while(l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void *) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; #if defined(PRINTF_SUPPORT_LONG_LONG) - const bool is_ll = sizeof(uintptr_t) == sizeof(long long); - if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); - } - else { + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if(is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void *), false, 16U, precision, width, flags); + } + else { #endif - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void *)), false, 16U, precision, width, + flags); #if defined(PRINTF_SUPPORT_LONG_LONG) - } + } #endif - format++; - break; - } - - case '%' : - out('%', buffer, idx++, maxlen); - format++; - break; - - default : - out(*format, buffer, idx++, maxlen); - format++; - break; + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } } - } - // termination - out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); - // return written chars without terminating \0 - return (int)idx; + // return written chars without terminating \0 + return (int)idx; } - /////////////////////////////////////////////////////////////////////////////// -int lv_snprintf(char* buffer, size_t count, const char* format, ...) +int lv_snprintf(char * buffer, size_t count, const char * format, ...) { - va_list va; - va_start(va, format); - const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); - va_end(va); - return ret; + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; } -int lv_vsnprintf(char* buffer, size_t count, const char* format, va_list va) +int lv_vsnprintf(char * buffer, size_t count, const char * format, va_list va) { - return _vsnprintf(_out_buffer, buffer, count, format, va); + return _vsnprintf(_out_buffer, buffer, count, format, va); } #endif /*LV_SPRINTF_CUSTOM*/ - diff --git a/src/libs/lvgl/src/lv_misc/lv_printf.h b/src/libs/lvgl/src/lv_misc/lv_printf.h index b3b8598d..a89617cd 100644 --- a/src/libs/lvgl/src/lv_misc/lv_printf.h +++ b/src/libs/lvgl/src/lv_misc/lv_printf.h @@ -10,10 +10,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -32,17 +32,11 @@ #ifndef _LV_PRINTF_H_ #define _LV_PRINTF_H_ - #ifdef __cplusplus extern "C" { #endif - -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #if LV_SPRINTF_CUSTOM == 0 @@ -59,17 +53,15 @@ extern "C" { * null character. A value equal or larger than count indicates truncation. Only when the returned value * is non-negative and less than count, the string has been completely written. */ -int lv_snprintf(char* buffer, size_t count, const char* format, ...); -int lv_vsnprintf(char* buffer, size_t count, const char* format, va_list va); +int lv_snprintf(char * buffer, size_t count, const char * format, ...); +int lv_vsnprintf(char * buffer, size_t count, const char * format, va_list va); #else #include LV_SPRINTF_INCLUDE #endif - #ifdef __cplusplus } #endif - -#endif // _PRINTF_H_ +#endif // _LV_PRINTF_H_ diff --git a/src/libs/lvgl/src/lv_misc/lv_task.c b/src/libs/lvgl/src/lv_misc/lv_task.c index 5ac36edb..147ada68 100644 --- a/src/libs/lvgl/src/lv_misc/lv_task.c +++ b/src/libs/lvgl/src/lv_misc/lv_task.c @@ -1,6 +1,6 @@ /** * @file lv_task.c - * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * An 'lv_task' is a void (*fp) (struct _lv_task_t* param) type function which will be called periodically. * A priority (5 levels + disable) can be assigned to lv_tasks. */ @@ -9,14 +9,10 @@ *********************/ #include <stddef.h> #include "lv_task.h" -#include "../lv_core/lv_debug.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 *********************/ @@ -32,6 +28,7 @@ * STATIC PROTOTYPES **********************/ static bool lv_task_exec(lv_task_t * task); +static uint32_t lv_task_time_remaining(lv_task_t * task); /********************** * STATIC VARIABLES @@ -39,6 +36,7 @@ static bool lv_task_exec(lv_task_t * task); 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; /********************** @@ -52,36 +50,36 @@ static bool task_created; /** * Init the lv_task module */ -void lv_task_core_init(void) +void _lv_task_core_init(void) { - lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t)); + _lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t)); /*Initially enable the lv_task handling*/ lv_task_enable(true); } /** - * Call it periodically to handle lv_tasks. + * Call it periodically to handle lv_tasks. + * @return the time after which it must be called again */ -LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) +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; + 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; - if(lv_task_run == false) { already_running = false; /*Release mutex*/ - return; + return 1; } - handler_start = lv_tick_get(); + static uint32_t idle_period_start = 0; + static uint32_t busy_time = 0; + + uint32_t 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 @@ -93,14 +91,15 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) 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)); + task_list_changed = 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)); + 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) { + if(LV_GC_ROOT(_lv_task_act)->prio == LV_TASK_PRIO_OFF) { break; } @@ -113,12 +112,12 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) } /*Just try to run the tasks with highest priority.*/ - if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) { + if(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_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 */ @@ -147,16 +146,31 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) break; } + if(task_list_changed) { + task_interrupter = NULL; + end_flag = false; + break; + } + LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/ } } while(!end_flag); + uint32_t time_till_next = LV_NO_TASK_READY; + next = _lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); + while(next && 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*/ + } + 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*/ + idle_last = (busy_time * 100) / idle_period_time; /*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(); } @@ -164,54 +178,71 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) already_running = false; /*Release the mutex*/ LV_LOG_TRACE("lv_task_handler ready"); + return time_till_next; } /** - * Create an "empty" task. It needs to initialzed with at least + * Create an "empty" task. It needs to initialized with at least * `lv_task_set_cb` and `lv_task_set_period` - * @return pointer to the craeted task + * @return pointer to the created task */ lv_task_t * lv_task_create_basic(void) { + return lv_task_create(NULL, DEF_PERIOD, DEF_PRIO, NULL); +} + +/** + * 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 = 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)); + 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)); + 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); + if(tmp->prio <= 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); + 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)); + 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->period = period; + new_task->task_cb = task_xcb; + new_task->prio = prio; - new_task->once = 0; + new_task->repeat_count = -1; new_task->last_run = lv_tick_get(); - new_task->user_data = NULL; + new_task->user_data = user_data; task_created = true; @@ -219,33 +250,9 @@ 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_cb, 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_cb); - 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 teh function to call periodically + * @param task_cb the function to call periodically */ void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb) { @@ -258,7 +265,8 @@ void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb) */ void lv_task_del(lv_task_t * task) { - lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), task); + _lv_ll_remove(&LV_GC_ROOT(_lv_task_ll), task); + task_list_changed = true; lv_mem_free(task); @@ -276,18 +284,18 @@ void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio) /*Find the tasks with new priority*/ lv_task_t * i; - LV_LL_READ(LV_GC_ROOT(_lv_task_ll), 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); + 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); + _lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, NULL); } + task_list_changed = true; task->prio = prio; } @@ -312,12 +320,13 @@ void lv_task_ready(lv_task_t * task) } /** - * Delete the lv_task after one call + * 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_once(lv_task_t * task) +void lv_task_set_repeat_count(lv_task_t * task, int32_t repeat_count) { - task->once = 1; + task->repeat_count = repeat_count; } /** @@ -348,6 +357,17 @@ 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 **********************/ @@ -361,17 +381,16 @@ static bool lv_task_exec(lv_task_t * task) { bool exec = false; - /*Execute if at least 'period' time elapsed*/ - uint32_t elp = lv_tick_elaps(task->last_run); - if(elp >= task->period) { + 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); /*Delete if it was a one shot lv_task*/ if(task_deleted == false) { /*The task might be deleted by itself as well*/ - if(task->once != 0) { + if(task->repeat_count > 0) { + task->repeat_count--; + } + if(task->repeat_count == 0) { lv_task_del(task); } } @@ -380,3 +399,17 @@ static bool lv_task_exec(lv_task_t * task) 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; +} diff --git a/src/libs/lvgl/src/lv_misc/lv_task.h b/src/libs/lvgl/src/lv_misc/lv_task.h index 05ff02b6..9b5bfde1 100644 --- a/src/libs/lvgl/src/lv_misc/lv_task.h +++ b/src/libs/lvgl/src/lv_misc/lv_task.h @@ -1,6 +1,6 @@ /** - * @file lv_task.c - * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * @file lv_task.h + * An 'lv_task' is a void (*fp) (struct _lv_task_t* param) type function which will be called periodically. * A priority (5 levels + disable) can be assigned to lv_tasks. */ @@ -14,11 +14,7 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include <stdint.h> #include <stdbool.h> @@ -31,6 +27,8 @@ extern "C" { #ifndef LV_ATTRIBUTE_TASK_HANDLER #define LV_ATTRIBUTE_TASK_HANDLER #endif + +#define LV_NO_TASK_READY 0xFFFFFFFF /********************** * TYPEDEFS **********************/ @@ -38,7 +36,7 @@ extern "C" { struct _lv_task_t; /** - * Tasks execute this type type of functions. + * Tasks execute this type of functions. */ typedef void (*lv_task_cb_t)(struct _lv_task_t *); @@ -59,16 +57,15 @@ typedef uint8_t lv_task_prio_t; /** * Descriptor of a lv_task */ -typedef struct _lv_task_t -{ +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 */ - uint8_t once : 1; /**< 1: one shot task */ } lv_task_t; /********************** @@ -78,21 +75,22 @@ typedef struct _lv_task_t /** * Init the lv_task module */ -void lv_task_core_init(void); +void _lv_task_core_init(void); //! @cond Doxygen_Suppress /** - * Call it periodically to handle lv_tasks. + * Call it periodically to handle lv_tasks. + * @return time till it needs to be run next (in ms) */ -LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); +LV_ATTRIBUTE_TASK_HANDLER uint32_t lv_task_handler(void); //! @endcond /** - * Create an "empty" task. It needs to initialzed with at least + * Create an "empty" task. It needs to initialized with at least * `lv_task_set_cb` and `lv_task_set_period` - * @return pointer to the craeted task + * @return pointer to the created task */ lv_task_t * lv_task_create_basic(void); @@ -142,10 +140,11 @@ void lv_task_set_period(lv_task_t * task, uint32_t period); void lv_task_ready(lv_task_t * task); /** - * Delete the lv_task after one call + * 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_once(lv_task_t * task); +void lv_task_set_repeat_count(lv_task_t * task, int32_t repeat_count); /** * Reset a lv_task. @@ -155,7 +154,7 @@ void lv_task_once(lv_task_t * task); void lv_task_reset(lv_task_t * task); /** - * Enable or disable the whole lv_task handling + * 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); @@ -166,6 +165,13 @@ void lv_task_enable(bool en); */ 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 **********************/ diff --git a/src/libs/lvgl/src/lv_misc/lv_templ.c b/src/libs/lvgl/src/lv_misc/lv_templ.c index c5bb68c0..45683915 100644 --- a/src/libs/lvgl/src/lv_misc/lv_templ.c +++ b/src/libs/lvgl/src/lv_misc/lv_templ.c @@ -17,7 +17,7 @@ /* This typedef exists purely to keep -Wpedantic happy when the file is empty. */ /* It can be removed. */ -typedef int keep_pedantic_happy; +typedef int _keep_pedantic_happy; /********************** * STATIC PROTOTYPES diff --git a/src/libs/lvgl/src/lv_misc/lv_txt.c b/src/libs/lvgl/src/lv_misc/lv_txt.c index 9de132e9..e240485b 100644 --- a/src/libs/lvgl/src/lv_misc/lv_txt.c +++ b/src/libs/lvgl/src/lv_misc/lv_txt.c @@ -6,9 +6,12 @@ /********************* * INCLUDES *********************/ +#include <stdarg.h> #include "lv_txt.h" +#include "lv_txt_ap.h" #include "lv_math.h" #include "lv_log.h" +#include "lv_debug.h" /********************* * DEFINES @@ -25,23 +28,23 @@ static inline bool is_break_char(uint32_t letter); #if LV_TXT_ENC == LV_TXT_ENC_UTF8 -static uint8_t lv_txt_utf8_size(const char * str); -static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni); -static uint32_t lv_txt_utf8_conv_wc(uint32_t c); -static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i); -static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start); -static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id); -static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id); -static uint32_t lv_txt_utf8_get_length(const char * txt); + static uint8_t lv_txt_utf8_size(const char * str); + static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni); + static uint32_t lv_txt_utf8_conv_wc(uint32_t c); + static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i); + static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start); + static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id); + static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id); + static uint32_t lv_txt_utf8_get_length(const char * txt); #elif LV_TXT_ENC == LV_TXT_ENC_ASCII -static uint8_t lv_txt_iso8859_1_size(const char * str); -static uint32_t lv_txt_unicode_to_iso8859_1(uint32_t letter_uni); -static uint32_t lv_txt_iso8859_1_conv_wc(uint32_t c); -static uint32_t lv_txt_iso8859_1_next(const char * txt, uint32_t * i); -static uint32_t lv_txt_iso8859_1_prev(const char * txt, uint32_t * i_start); -static uint32_t lv_txt_iso8859_1_get_byte_id(const char * txt, uint32_t utf8_id); -static uint32_t lv_txt_iso8859_1_get_char_id(const char * txt, uint32_t byte_id); -static uint32_t lv_txt_iso8859_1_get_length(const char * txt); + static uint8_t lv_txt_iso8859_1_size(const char * str); + static uint32_t lv_txt_unicode_to_iso8859_1(uint32_t letter_uni); + static uint32_t lv_txt_iso8859_1_conv_wc(uint32_t c); + static uint32_t lv_txt_iso8859_1_next(const char * txt, uint32_t * i); + static uint32_t lv_txt_iso8859_1_prev(const char * txt, uint32_t * i_start); + static uint32_t lv_txt_iso8859_1_get_byte_id(const char * txt, uint32_t utf8_id); + static uint32_t lv_txt_iso8859_1_get_char_id(const char * txt, uint32_t byte_id); + static uint32_t lv_txt_iso8859_1_get_length(const char * txt); #endif /********************** * STATIC VARIABLES @@ -51,23 +54,23 @@ static uint32_t lv_txt_iso8859_1_get_length(const char * txt); * GLOBAL VARIABLES **********************/ #if LV_TXT_ENC == LV_TXT_ENC_UTF8 -uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_utf8_size; -uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8; -uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc; -uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next; -uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev; -uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id; -uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id; -uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length; + uint8_t (*_lv_txt_encoded_size)(const char *) = lv_txt_utf8_size; + uint32_t (*_lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8; + uint32_t (*_lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc; + uint32_t (*_lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next; + uint32_t (*_lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev; + uint32_t (*_lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id; + uint32_t (*_lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id; + uint32_t (*_lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length; #elif LV_TXT_ENC == LV_TXT_ENC_ASCII -uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_iso8859_1_size; -uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_iso8859_1; -uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_iso8859_1_conv_wc; -uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_iso8859_1_next; -uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_iso8859_1_prev; -uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_byte_id; -uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id; -uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_iso8859_1_get_length; + uint8_t (*_lv_txt_encoded_size)(const char *) = lv_txt_iso8859_1_size; + uint32_t (*_lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_iso8859_1; + uint32_t (*_lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_iso8859_1_conv_wc; + uint32_t (*_lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_iso8859_1_next; + uint32_t (*_lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_iso8859_1_prev; + uint32_t (*_lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_byte_id; + uint32_t (*_lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id; + uint32_t (*_lv_txt_get_encoded_length)(const char *) = lv_txt_iso8859_1_get_length; #endif @@ -83,15 +86,15 @@ uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_iso8859_ * Get size of a text * @param size_res pointer to a 'point_t' variable to store the result * @param text pointer to a text - * @param font pinter to font of the text + * @param font pointer to font of the text * @param letter_space letter space of the text * @param txt.line_space line space of the text * @param flags settings for the text from 'txt_flag_t' enum * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid * line breaks */ -void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, lv_coord_t letter_space, - lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag) +void _lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, lv_coord_t letter_space, + lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag) { size_res->x = 0; size_res->y = 0; @@ -103,23 +106,24 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * uint32_t line_start = 0; uint32_t new_line_start = 0; - lv_coord_t act_line_length; - uint8_t letter_height = lv_font_get_line_height(font); + uint16_t letter_height = lv_font_get_line_height(font); /*Calc. the height and longest line*/ while(text[line_start] != '\0') { - new_line_start += lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag); + new_line_start += _lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag); - if ((unsigned long)size_res->y + (unsigned long)letter_height + (unsigned long)line_space > LV_MAX_OF(lv_coord_t)) { + if((unsigned long)size_res->y + (unsigned long)letter_height + (unsigned long)line_space > LV_MAX_OF(lv_coord_t)) { LV_LOG_WARN("lv_txt_get_size: integer overflow while calculating text height"); return; - } else { + } + else { size_res->y += letter_height; size_res->y += line_space; } - /*Calculate the the longest line*/ - act_line_length = lv_txt_get_width(&text[line_start], new_line_start - line_start, font, letter_space, flag); + /*Calculate the longest line*/ + lv_coord_t act_line_length = _lv_txt_get_width(&text[line_start], new_line_start - line_start, font, letter_space, + flag); size_res->x = LV_MATH_MAX(act_line_length, size_res->x); line_start = new_line_start; @@ -146,7 +150,7 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * * * If the first character is a break character, returns the next index. * - * Example calls from lv_txt_get_next_line() assuming sufficent max_width and + * Example calls from lv_txt_get_next_line() assuming sufficient max_width and * txt = "Test text\n" * 0123456789 * @@ -156,7 +160,7 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * * 3. Return i=9, pointing at breakchar '\n' * 4. Parenting lv_txt_get_next_line() would detect subsequent '\0' * - * TODO: Returned word_w_ptr may overestimate the returned word's width when + * TODO: Returned word_w_ptr may overestimate the returned word's width when * max_width is reached. In current usage, this has no impact. * * @param txt a '\0' terminated string @@ -168,9 +172,9 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * * @param force Force return the fraction of the word that can fit in the provided space. * @return the index of the first char of the next word (in byte index not letter index. With UTF-8 they are different) */ -static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, - lv_coord_t letter_space, lv_coord_t max_width, - lv_txt_flag_t flag, uint32_t *word_w_ptr, lv_txt_cmd_state_t * cmd_state, bool force) +static uint32_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, + lv_txt_flag_t flag, uint32_t * word_w_ptr, lv_txt_cmd_state_t * cmd_state, bool force) { if(txt == NULL || txt[0] == '\0') return 0; if(font == NULL) return 0; @@ -186,17 +190,17 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, uint32_t break_index = NO_BREAK_FOUND; /* only used for "long" words */ uint32_t break_letter_count = 0; /* Number of characters up to the long word break point */ - letter = lv_txt_encoded_next(txt, &i_next); + letter = _lv_txt_encoded_next(txt, &i_next); i_next_next = i_next; /* Obtain the full word, regardless if it fits or not in max_width */ while(txt[i] != '\0') { - letter_next = lv_txt_encoded_next(txt, &i_next_next); + letter_next = _lv_txt_encoded_next(txt, &i_next_next); word_len++; /*Handle the recolor command*/ if((flag & LV_TXT_FLAG_RECOLOR) != 0) { - if(lv_txt_is_cmd(cmd_state, letter) != false) { + if(_lv_txt_is_cmd(cmd_state, letter) != false) { i = i_next; i_next = i_next_next; letter = letter_next; @@ -213,7 +217,7 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, /* Test if this character fits within max_width */ if(break_index == NO_BREAK_FOUND && (cur_w - letter_space) > max_width) { - break_index = i; + break_index = i; break_letter_count = word_len - 1; /* break_index is now pointing at the character that doesn't fit */ } @@ -221,15 +225,14 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, /*Check for new line chars and breakchars*/ if(letter == '\n' || letter == '\r' || is_break_char(letter)) { /* Update the output width on the first character if it fits. - * Must do this here incase first letter is a break character. */ + * Must do this here in case first letter is a break character. */ if(i == 0 && break_index == NO_BREAK_FOUND && word_w_ptr != NULL) *word_w_ptr = cur_w; word_len--; break; } /* Update the output width */ - if( word_w_ptr != NULL && break_index == NO_BREAK_FOUND ) *word_w_ptr = cur_w; - + if(word_w_ptr != NULL && break_index == NO_BREAK_FOUND) *word_w_ptr = cur_w; i = i_next; i_next = i_next_next; @@ -237,22 +240,22 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, } /* Entire Word fits in the provided space */ - if( break_index == NO_BREAK_FOUND ) { - if( word_len == 0 || (letter == '\r' && letter_next == '\n') ) i = i_next; + if(break_index == NO_BREAK_FOUND) { + if(word_len == 0 || (letter == '\r' && letter_next == '\n')) i = i_next; return i; } #if LV_TXT_LINE_BREAK_LONG_LEN > 0 /* Word doesn't fit in provided space, but isn't "long" */ if(word_len < LV_TXT_LINE_BREAK_LONG_LEN) { - if( force ) return break_index; + if(force) return break_index; if(word_w_ptr != NULL) *word_w_ptr = 0; /* Return no word */ return 0; } /* Word is "long," but insufficient amounts can fit in provided space */ if(break_letter_count < LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN) { - if( force ) return break_index; + if(force) return break_index; if(word_w_ptr != NULL) *word_w_ptr = 0; return 0; } @@ -262,15 +265,15 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, i = break_index; int32_t n_move = LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN - (word_len - break_letter_count); /* Move pointer "i" backwards */ - for(;n_move>0; n_move--){ - lv_txt_encoded_prev(txt, &i); + for(; n_move > 0; n_move--) { + _lv_txt_encoded_prev(txt, &i); // TODO: it would be appropriate to update the returned word width here // However, in current usage, this doesn't impact anything. } } return i; #else - if( force ) return break_index; + if(force) return break_index; if(word_w_ptr != NULL) *word_w_ptr = 0; /* Return no word */ (void) break_letter_count; return 0; @@ -289,23 +292,34 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font, * @param flags settings for the text from 'txt_flag_type' enum * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different) */ -uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, - lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag) +uint32_t _lv_txt_get_next_line(const char * txt, const lv_font_t * font, + lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag) { if(txt == NULL) return 0; if(font == NULL) return 0; + /* If max_width doesn't mater simply find the new line character + * without thinking about word wrapping*/ + if((flag & LV_TXT_FLAG_EXPAND) || (flag & LV_TXT_FLAG_FIT)) { + uint32_t i; + for(i = 0; txt[i] != '\n' && txt[i] != '\r' && txt[i] != '\0'; i++) { + /*Just find the new line chars or string ends by incrementing `i`*/ + } + if(txt[i] != '\0') i++; /*To go beyond `\n`*/ + return i; + } + if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; uint32_t i = 0; /* Iterating index into txt */ while(txt[i] != '\0' && max_width > 0) { uint32_t word_w = 0; - uint32_t advance = lv_txt_get_next_word(&txt[i], font, letter_space, max_width, flag, &word_w, &cmd_state, i==0); + uint32_t advance = lv_txt_get_next_word(&txt[i], font, letter_space, max_width, flag, &word_w, &cmd_state, i == 0); max_width -= word_w; - if( advance == 0 ){ - if(i == 0) lv_txt_encoded_next(txt, &i); // prevent inf loops + if(advance == 0) { + if(i == 0) _lv_txt_encoded_next(txt, &i); // prevent inf loops break; } @@ -313,7 +327,7 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, if(txt[0] == '\n' || txt[0] == '\r') break; - if(txt[i] == '\n' || txt[i] == '\r'){ + if(txt[i] == '\n' || txt[i] == '\r') { i++; /* Include the following newline in the current line */ break; } @@ -322,7 +336,7 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, /* Always step at least one to avoid infinite loops */ if(i == 0) { - lv_txt_encoded_next(txt, &i); + _lv_txt_encoded_next(txt, &i); } return i; @@ -338,24 +352,23 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, * @param flags settings for the text from 'txt_flag_t' enum * @return length of a char_num long text */ -lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, const lv_font_t * font, lv_coord_t letter_space, - lv_txt_flag_t flag) +lv_coord_t _lv_txt_get_width(const char * txt, uint32_t length, const lv_font_t * font, lv_coord_t letter_space, + lv_txt_flag_t flag) { if(txt == NULL) return 0; if(font == NULL) return 0; + if(txt[0] == '\0') return 0; uint32_t i = 0; lv_coord_t width = 0; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; - uint32_t letter; - uint32_t letter_next; if(length != 0) { while(i < length) { - letter = lv_txt_encoded_next(txt, &i); - letter_next = lv_txt_encoded_next(&txt[i], NULL); + uint32_t letter = _lv_txt_encoded_next(txt, &i); + uint32_t letter_next = _lv_txt_encoded_next(&txt[i], NULL); if((flag & LV_TXT_FLAG_RECOLOR) != 0) { - if(lv_txt_is_cmd(&cmd_state, letter) != false) { + if(_lv_txt_is_cmd(&cmd_state, letter) != false) { continue; } } @@ -379,12 +392,12 @@ lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, const lv_font_t * /** * Check next character in a string and decide if the character is part of the command or not * @param state pointer to a txt_cmd_state_t variable which stores the current state of command - * processing (Initied. to TXT_CMD_STATE_WAIT ) + * processing (Inited to TXT_CMD_STATE_WAIT ) * @param c the current character * @return true: the character is part of a command and should not be written, * false: the character should be written */ -bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c) +bool _lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c) { bool ret = false; @@ -422,12 +435,14 @@ bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c) * UTF-8) 0: before the original text, 1: after the first char etc. * @param ins_txt text to insert */ -void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt) +void _lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt) { size_t old_len = strlen(txt_buf); size_t ins_len = strlen(ins_txt); + if(ins_len == 0) return; + size_t new_len = ins_len + old_len; - pos = lv_txt_encoded_get_byte_id(txt_buf, pos); /*Convert to byte index instead of letter index*/ + pos = _lv_txt_encoded_get_byte_id(txt_buf, pos); /*Convert to byte index instead of letter index*/ /*Copy the second part into the end to make place to text to insert*/ size_t i; @@ -436,7 +451,7 @@ void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt) } /* Copy the text into the new space*/ - memcpy(txt_buf + pos, ins_txt, ins_len); + _lv_memcpy_small(txt_buf + pos, ins_txt, ins_len); } /** @@ -446,13 +461,13 @@ void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt) * char etc.) * @param len number of characters to delete */ -void lv_txt_cut(char * txt, uint32_t pos, uint32_t len) +void _lv_txt_cut(char * txt, uint32_t pos, uint32_t len) { size_t old_len = strlen(txt); - pos = lv_txt_encoded_get_byte_id(txt, pos); /*Convert to byte index instead of letter index*/ - len = lv_txt_encoded_get_byte_id(&txt[pos], len); + pos = _lv_txt_encoded_get_byte_id(txt, pos); /*Convert to byte index instead of letter index*/ + len = _lv_txt_encoded_get_byte_id(&txt[pos], len); /*Copy the second part into the end to make place to text to insert*/ uint32_t i; @@ -461,9 +476,57 @@ void lv_txt_cut(char * txt, uint32_t pos, uint32_t len) } } +/** + * return a new formatted text. Memory will be allocated to store the text. + * @param fmt `printf`-like format + * @return pointer to the allocated text string. + */ +char * _lv_txt_set_text_vfmt(const char * fmt, va_list ap) +{ + /*Allocate space for the new text by using trick from C99 standard section 7.19.6.12 */ + va_list ap_copy; + va_copy(ap_copy, ap); + uint32_t len = lv_vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); + + char * text = 0; +#if LV_USE_ARABIC_PERSIAN_CHARS + /*Put together the text according to the format string*/ + char * raw_txt = _lv_mem_buf_get(len + 1); + LV_ASSERT_MEM(raw_txt); + if(raw_txt == NULL) { + return NULL; + } + + lv_vsnprintf(raw_txt, len + 1, fmt, ap); + + /*Get the size of the Arabic text and process it*/ + size_t len_ap = _lv_txt_ap_calc_bytes_cnt(raw_txt); + text = lv_mem_alloc(len_ap + 1); + LV_ASSERT_MEM(text); + if(text == NULL) { + return NULL; + } + _lv_txt_ap_proc(raw_txt, text); + + _lv_mem_buf_release(raw_txt); +#else + text = lv_mem_alloc(len + 1); + LV_ASSERT_MEM(text); + if(text == NULL) { + return NULL; + } + text[len] = 0; /* Ensure NULL termination */ + + lv_vsnprintf(text, len + 1, fmt, ap); +#endif + + return text; +} + #if LV_TXT_ENC == LV_TXT_ENC_UTF8 /******************************* - * UTF-8 ENCODER/DECOER + * UTF-8 ENCODER/DECODER ******************************/ /** @@ -499,12 +562,14 @@ static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni) bytes[1] = ((letter_uni >> 0) & 0x3F) | 0x80; bytes[2] = 0; bytes[3] = 0; - } else if(letter_uni < 0x010000) { + } + else if(letter_uni < 0x010000) { bytes[0] = ((letter_uni >> 12) & 0x0F) | 0xE0; bytes[1] = ((letter_uni >> 6) & 0x3F) | 0x80; bytes[2] = ((letter_uni >> 0) & 0x3F) | 0x80; bytes[3] = 0; - } else if(letter_uni < 0x110000) { + } + else if(letter_uni < 0x110000) { bytes[0] = ((letter_uni >> 18) & 0x07) | 0xF0; bytes[1] = ((letter_uni >> 12) & 0x3F) | 0x80; bytes[2] = ((letter_uni >> 6) & 0x3F) | 0x80; @@ -517,16 +582,17 @@ static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni) /** * Convert a wide character, e.g. 'Á' little endian to be UTF-8 compatible - * @param c a wide character or a Little endian number + * @param c a wide character or a Little endian number * @return `c` in big endian */ static uint32_t lv_txt_utf8_conv_wc(uint32_t c) { +#if LV_BIG_ENDIAN_SYSTEM == 0 /*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/ if((c & 0x80) != 0) { uint32_t swapped; uint8_t c8[4]; - memcpy(c8, &c, 4); + _lv_memcpy_small(c8, &c, 4); swapped = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]); uint8_t i; for(i = 0; i < 4; i++) { @@ -535,7 +601,7 @@ static uint32_t lv_txt_utf8_conv_wc(uint32_t c) } c = swapped; } - +#endif return c; } @@ -606,7 +672,8 @@ static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i) if((txt[*i] & 0xC0) != 0x80) return 0; /*Invalid UTF-8 code*/ result += txt[*i] & 0x3F; (*i)++; - } else { + } + else { (*i)++; /*Not UTF-8 char. Go the next.*/ } } @@ -630,7 +697,7 @@ static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i) do { if(cnt >= 4) return 0; /*No UTF-8 char found before the initial*/ - c_size = lv_txt_encoded_size(&txt[*i]); + c_size = _lv_txt_encoded_size(&txt[*i]); if(c_size == 0) { if(*i != 0) (*i)--; @@ -641,7 +708,7 @@ static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i) } while(c_size == 0); uint32_t i_tmp = *i; - uint32_t letter = lv_txt_encoded_next(txt, &i_tmp); /*Character found, get it*/ + uint32_t letter = _lv_txt_encoded_next(txt, &i_tmp); /*Character found, get it*/ return letter; } @@ -658,7 +725,7 @@ static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id) uint32_t i; uint32_t byte_cnt = 0; for(i = 0; i < utf8_id; i++) { - uint8_t c_size = lv_txt_encoded_size(&txt[byte_cnt]); + uint8_t c_size = _lv_txt_encoded_size(&txt[byte_cnt]); byte_cnt += c_size > 0 ? c_size : 1; } @@ -678,7 +745,7 @@ static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id) uint32_t char_cnt = 0; while(i < byte_id) { - lv_txt_encoded_next(txt, &i); /*'i' points to the next letter so use the prev. value*/ + _lv_txt_encoded_next(txt, &i); /*'i' points to the next letter so use the prev. value*/ char_cnt++; } @@ -697,7 +764,7 @@ static uint32_t lv_txt_utf8_get_length(const char * txt) uint32_t i = 0; while(txt[i] != '\0') { - lv_txt_encoded_next(txt, &i); + _lv_txt_encoded_next(txt, &i); len++; } @@ -727,7 +794,7 @@ static uint8_t lv_txt_iso8859_1_size(const char * str) */ static uint32_t lv_txt_unicode_to_iso8859_1(uint32_t letter_uni) { - if(letter_uni < 128) + if(letter_uni < 256) return letter_uni; else return ' '; diff --git a/src/libs/lvgl/src/lv_misc/lv_txt.h b/src/libs/lvgl/src/lv_misc/lv_txt.h index 6dbce5d4..596846cd 100644 --- a/src/libs/lvgl/src/lv_misc/lv_txt.h +++ b/src/libs/lvgl/src/lv_misc/lv_txt.h @@ -13,16 +13,13 @@ extern "C" { /********************* * INCLUDES *********************/ -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_conf.h" -#else -#include "../../../lv_conf.h" -#endif +#include "../lv_conf_internal.h" #include <stdbool.h> -#include "lv_area.h" +#include <stdarg.h> #include "lv_area.h" #include "../lv_font/lv_font.h" +#include "lv_printf.h" /********************* * DEFINES @@ -43,9 +40,10 @@ extern "C" { enum { LV_TXT_FLAG_NONE = 0x00, LV_TXT_FLAG_RECOLOR = 0x01, /**< Enable parsing of recolor command*/ - LV_TXT_FLAG_EXPAND = 0x02, /**< Ignore width to avoid automatic word wrapping*/ + LV_TXT_FLAG_EXPAND = 0x02, /**< Ignore max-width to avoid automatic word wrapping*/ LV_TXT_FLAG_CENTER = 0x04, /**< Align the text to the middle*/ LV_TXT_FLAG_RIGHT = 0x08, /**< Align the text to the right*/ + LV_TXT_FLAG_FIT = 0x10, /**< Max-width is already equal to the longest line. (Used to skip some calculation)*/ }; typedef uint8_t lv_txt_flag_t; @@ -66,15 +64,15 @@ typedef uint8_t lv_txt_cmd_state_t; * Get size of a text * @param size_res pointer to a 'point_t' variable to store the result * @param text pointer to a text - * @param font pinter to font of the text + * @param font pointer to font of the text * @param letter_space letter space of the text * @param line_space line space of the text * @param flags settings for the text from 'txt_flag_t' enum * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid * line breaks */ -void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, lv_coord_t letter_space, - lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag); +void _lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, lv_coord_t letter_space, + lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag); /** * Get the next line of text. Check line length and break chars too. @@ -87,8 +85,8 @@ void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 * they are different) */ -uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t max_width, - lv_txt_flag_t flag); +uint32_t _lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t max_width, + lv_txt_flag_t flag); /** * Give the length of a text with a given font @@ -100,18 +98,18 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord * @param flags settings for the text from 'txt_flag_t' enum * @return length of a char_num long text */ -lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, const lv_font_t * font, lv_coord_t letter_space, - lv_txt_flag_t flag); +lv_coord_t _lv_txt_get_width(const char * txt, uint32_t length, const lv_font_t * font, lv_coord_t letter_space, + lv_txt_flag_t flag); /** - * Check next character in a string and decide if te character is part of the command or not + * Check next character in a string and decide if the character is part of the command or not * @param state pointer to a txt_cmd_state_t variable which stores the current state of command * processing * @param c the current character * @return true: the character is part of a command and should not be written, * false: the character should be written */ -bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); +bool _lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); /** * Insert a string into an other @@ -119,7 +117,7 @@ bool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c); * @param pos position to insert (0: before the original text, 1: after the first char etc.) * @param ins_txt text to insert */ -void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); +void _lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); /** * Delete a part of a string @@ -128,10 +126,17 @@ void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); * char etc.) * @param len number of characters to delete */ -void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); +void _lv_txt_cut(char * txt, uint32_t pos, uint32_t len); + +/** + * return a new formatted text. Memory will be allocated to store the text. + * @param fmt `printf`-like format + * @return pointer to the allocated text string. + */ +char * _lv_txt_set_text_vfmt(const char * fmt, va_list ap); /*************************************************************** - * GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE + * GLOBAL FUNCTION POINTERS FOR CHARACTER ENCODING INTERFACE ***************************************************************/ /** @@ -139,21 +144,21 @@ void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); * @param str pointer to a character in a string * @return length of the encoded character (1,2,3 ...). O in invalid */ -extern uint8_t (*lv_txt_encoded_size)(const char *); +extern uint8_t (*_lv_txt_encoded_size)(const char *); /** * Convert an Unicode letter to encoded * @param letter_uni an Unicode letter * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü') */ -extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t); +extern uint32_t (*_lv_txt_unicode_to_encoded)(uint32_t); /** * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format. * @param c a wide character * @return `c` in the encoded format */ -extern uint32_t (*lv_txt_encoded_conv_wc)(uint32_t c); +extern uint32_t (*_lv_txt_encoded_conv_wc)(uint32_t c); /** * Decode the next encoded character from a string. @@ -163,7 +168,7 @@ extern uint32_t (*lv_txt_encoded_conv_wc)(uint32_t c); * NULL to use txt[0] as index * @return the decoded Unicode character or 0 on invalid data code */ -extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *); +extern uint32_t (*_lv_txt_encoded_next)(const char *, uint32_t *); /** * Get the previous encoded character form a string. @@ -172,7 +177,7 @@ extern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *); * encoded char in 'txt'. * @return the decoded Unicode character or 0 on invalid data */ -extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *); +extern uint32_t (*_lv_txt_encoded_prev)(const char *, uint32_t *); /** * Convert a letter index (in an the encoded text) to byte index. @@ -181,7 +186,7 @@ extern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *); * @param enc_id letter index * @return byte index of the 'enc_id'th letter */ -extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); +extern uint32_t (*_lv_txt_encoded_get_byte_id)(const char *, uint32_t); /** * Convert a byte index (in an encoded text) to character index. @@ -190,7 +195,7 @@ extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); * @param byte_id byte index * @return character index of the letter at 'byte_id'th position */ -extern uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t); +extern uint32_t (*_lv_txt_encoded_get_char_id)(const char *, uint32_t); /** * Get the number of characters (and NOT bytes) in a string. @@ -198,7 +203,7 @@ extern uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t); * @param txt a '\0' terminated char string * @return number of characters */ -extern uint32_t (*lv_txt_get_encoded_length)(const char *); +extern uint32_t (*_lv_txt_get_encoded_length)(const char *); /********************** * MACROS diff --git a/src/libs/lvgl/src/lv_misc/lv_txt_ap.c b/src/libs/lvgl/src/lv_misc/lv_txt_ap.c new file mode 100644 index 00000000..fd99a59b --- /dev/null +++ b/src/libs/lvgl/src/lv_misc/lv_txt_ap.c @@ -0,0 +1,273 @@ +/** + * @file lv_txt_ap.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include <stddef.h> +#include "lv_bidi.h" +#include "lv_txt.h" +#include "lv_txt_ap.h" +#include "../lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +#if LV_USE_ARABIC_PERSIAN_CHARS == 1 +static uint32_t lv_ap_get_char_index(uint16_t c); +static uint32_t lv_txt_lam_alef(uint32_t ch_curr, uint32_t ch_next); + +/********************** + * STATIC VARIABLES + **********************/ + +const ap_chars_map_t ap_chars_map[] = { + /* {Key Offset, End, Beginning, Middle, Isolated, {conjunction}} */ + {1, 0xFE84, -1, 0, -1, {1, 0}}, // أ + {2, 0xFE86, -1, 0, -1, {1, 0}}, // ؤ + {3, 0xFE88, -1, 0, -1, {1, 0}}, // ﺇ + {4, 0xFE8A, 1, 2, -1, {1, 0}}, // ئ + {5, 0xFE8E, -1, 0, -1, {1, 0}}, // آ + {6, 0xFE90, 1, 2, -1, {1, 1}}, // ب + {92, 0xFB57, 1, 2, -1, {1, 1}}, // پ + {8, 0xFE96, 1, 2, -1, {1, 1}}, // ت + {9, 0xFE9A, 1, 2, -1, {1, 1}}, // ث + {10, 0xFE9E, 1, 2, -1, {1, 1}}, // ج + {100, 0xFB7B, 1, 2, -1, {1, 1}}, // چ + {11, 0xFEA2, 1, 2, -1, {1, 1}}, // ح + {12, 0xFEA6, 1, 2, -1, {1, 1}}, // خ + {13, 0xFEAA, -1, 0, -1, {1, 0}}, // د + {14, 0xFEAC, -1, 0, -1, {1, 0}}, // ذ + {15, 0xFEAE, -1, 0, -1, {1, 0}}, // ر + {16, 0xFEB0, -1, 0, -1, {1, 0}}, // ز + {118, 0xFB8B, -1, 0, -1, {1, 0}}, // ژ + {17, 0xFEB2, 1, 2, -1, {1, 1}}, // س + {18, 0xFEB6, 1, 2, -1, {1, 1}}, // ش + {19, 0xFEBA, 1, 2, -1, {1, 1}}, // ص + {20, 0xFEBE, 1, 2, -1, {1, 1}}, // ض + {21, 0xFEC2, 1, 2, -1, {1, 1}}, // ط + {22, 0xFEC6, 1, 2, -1, {1, 1}}, // ظ + {23, 0xFECA, 1, 2, -1, {1, 1}}, // ع + {24, 0xFECE, 1, 2, -1, {1, 1}}, // غ + {30, 0x0640, 0, 0, 0, {1, 1}}, // - (mad, hyphen) + {31, 0xFED2, 1, 2, -1, {1, 1}}, // ف + {32, 0xFED6, 1, 2, -1, {1, 1}}, // ق + {135, 0xFB8F, 1, 2, -1, {1, 1}}, // ک + {33, 0xFEDA, 1, 2, -1, {1, 1}}, // ﻙ + {141, 0xFB93, 1, 2, -1, {1, 1}}, // گ + {34, 0xFEDE, 1, 2, -1, {1, 1}}, // ل + {35, 0xFEE2, 1, 2, -1, {1, 1}}, // م + {36, 0xFEE6, 1, 2, -1, {1, 1}}, // ن + {38, 0xFEEE, -1, 0, -1, {1, 0}}, // و + {37, 0xFEEA, 1, 2, -1, {1, 1}}, // ه + {39, 0xFEF0, 0, 0, -1, {1, 0}}, // ى + {40, 0xFEF2, 1, 2, -1, {1, 1}}, // ي + {170, 0xFBFD, 1, 2, -1, {1, 1}}, // ی + {7, 0xFE94, 1, 2, -1, {1, 0}}, // ة + {206, 0x06F0, 1, 2, -1, {0, 0}}, // ۰ + {207, 0x06F1, 0, 0, 0, {0, 0}}, // ۱ + {208, 0x06F2, 0, 0, 0, {0, 0}}, // ۲ + {209, 0x06F3, 0, 0, 0, {0, 0}}, // ۳ + {210, 0x06F4, 0, 0, 0, {0, 0}}, // ۴ + {211, 0x06F5, 0, 0, 0, {0, 0}}, // ۵ + {212, 0x06F6, 0, 0, 0, {0, 0}}, // ۶ + {213, 0x06F7, 0, 0, 0, {0, 0}}, // ۷ + {214, 0x06F8, 0, 0, 0, {0, 0}}, // ۸ + {215, 0x06F9, 0, 0, 0, {0, 0}}, // ۹ + LV_AP_END_CHARS_LIST +}; +/********************** +* MACROS +**********************/ + +/********************** +* GLOBAL FUNCTIONS +**********************/ +uint32_t _lv_txt_ap_calc_bytes_cnt(const char * txt) +{ + uint32_t txt_length = 0; + uint32_t chars_cnt = 0; + uint32_t current_ap_idx = 0; + uint32_t i, j; + uint32_t ch_enc; + + txt_length = _lv_txt_get_encoded_length(txt); + + i = 0; + j = 0; + while(i < txt_length) { + ch_enc = _lv_txt_encoded_next(txt, &j); + current_ap_idx = lv_ap_get_char_index(ch_enc); + + if(current_ap_idx != LV_UNDEF_ARABIC_PERSIAN_CHARS) + ch_enc = ap_chars_map[current_ap_idx].char_end_form; + + if(ch_enc < 0x80) + chars_cnt++; + else if(ch_enc < 0x0800) + chars_cnt += 2; + else if(ch_enc < 0x010000) + chars_cnt += 3; + else + chars_cnt += 4; + + i++; + } + + return chars_cnt + 1; +} + +void _lv_txt_ap_proc(const char * txt, char * txt_out) +{ + uint32_t txt_length = 0; + uint32_t index_current, idx_next, idx_previous, i, j; + uint32_t * ch_enc; + uint32_t * ch_fin; + char * txt_out_temp; + + txt_length = _lv_txt_get_encoded_length(txt); + + ch_enc = (uint32_t *)lv_mem_alloc(sizeof(uint32_t) * (txt_length + 1)); + ch_fin = (uint32_t *)lv_mem_alloc(sizeof(uint32_t) * (txt_length + 1)); + + i = 0; + j = 0; + while(j < txt_length) + ch_enc[j++] = _lv_txt_encoded_next(txt, &i); + + ch_enc[j] = 0; + + i = 0; + j = 0; + idx_previous = LV_UNDEF_ARABIC_PERSIAN_CHARS; + while(i < txt_length) { + index_current = lv_ap_get_char_index(ch_enc[i]); + idx_next = lv_ap_get_char_index(ch_enc[i + 1]); + + if(index_current == LV_UNDEF_ARABIC_PERSIAN_CHARS) { + ch_fin[j] = ch_enc[i]; + j++; + i++; + idx_previous = LV_UNDEF_ARABIC_PERSIAN_CHARS; + continue; + } + + uint8_t conjunction_to_previuse = (i == 0 || + idx_previous == LV_UNDEF_ARABIC_PERSIAN_CHARS) ? 0 : ap_chars_map[idx_previous].ap_chars_conjunction.conj_to_next; + uint8_t conjunction_to_next = ((i == txt_length - 1) || + idx_next == LV_UNDEF_ARABIC_PERSIAN_CHARS) ? 0 : ap_chars_map[idx_next].ap_chars_conjunction.conj_to_previous; + + uint32_t lam_alef = lv_txt_lam_alef(index_current, idx_next); + if(lam_alef) { + if(conjunction_to_previuse) { + lam_alef ++; + } + ch_fin[j] = lam_alef; + idx_previous = LV_UNDEF_ARABIC_PERSIAN_CHARS; + i += 2; + j++; + continue; + } + + if(conjunction_to_previuse && conjunction_to_next) + ch_fin[j] = ap_chars_map[index_current].char_end_form + ap_chars_map[index_current].char_middle_form_offset; + else if(!conjunction_to_previuse && conjunction_to_next) + ch_fin[j] = ap_chars_map[index_current].char_end_form + ap_chars_map[index_current].char_begining_form_offset; + else if(conjunction_to_previuse && !conjunction_to_next) + ch_fin[j] = ap_chars_map[index_current].char_end_form; + else + ch_fin[j] = ap_chars_map[index_current].char_end_form + ap_chars_map[index_current].char_isolated_form_offset; + idx_previous = index_current; + i++; + j++; + } + ch_fin[j] = 0; + for(i = 0; i < txt_length; i++) + ch_enc[i] = 0; + for(i = 0; i < j; i++) + ch_enc[i] = ch_fin[i]; + lv_mem_free(ch_fin); + + txt_out_temp = txt_out; + i = 0; + + while(i < txt_length) { + if(ch_enc[i] < 0x80) { + *(txt_out_temp++) = ch_enc[i] & 0xFF; + } + else if(ch_enc[i] < 0x0800) { + *(txt_out_temp++) = ((ch_enc[i] >> 6) & 0x1F) | 0xC0; + *(txt_out_temp++) = ((ch_enc[i] >> 0) & 0x3F) | 0x80; + } + else if(ch_enc[i] < 0x010000) { + *(txt_out_temp++) = ((ch_enc[i] >> 12) & 0x0F) | 0xE0; + *(txt_out_temp++) = ((ch_enc[i] >> 6) & 0x3F) | 0x80; + *(txt_out_temp++) = ((ch_enc[i] >> 0) & 0x3F) | 0x80; + } + else if(ch_enc[i] < 0x110000) { + *(txt_out_temp++) = ((ch_enc[i] >> 18) & 0x07) | 0xF0; + *(txt_out_temp++) = ((ch_enc[i] >> 12) & 0x3F) | 0x80; + *(txt_out_temp++) = ((ch_enc[i] >> 6) & 0x3F) | 0x80; + *(txt_out_temp++) = ((ch_enc[i] >> 0) & 0x3F) | 0x80; + } + + i++; + } + *(txt_out_temp) = '\0'; + lv_mem_free(ch_enc); +} +/********************** +* STATIC FUNCTIONS +**********************/ + +static uint32_t lv_ap_get_char_index(uint16_t c) +{ + for(uint8_t i = 0; ap_chars_map[i].char_end_form; i++) { + if(c == (ap_chars_map[i].char_offset + LV_AP_ALPHABET_BASE_CODE)) + return i; + else if(c == ap_chars_map[i].char_end_form //is it an End form + || c == (ap_chars_map[i].char_end_form + ap_chars_map[i].char_begining_form_offset) //is it a Beginning form + || c == (ap_chars_map[i].char_end_form + ap_chars_map[i].char_middle_form_offset) //is it a middle form + || c == (ap_chars_map[i].char_end_form + ap_chars_map[i].char_isolated_form_offset)) { //is it an isolated form + return i; + } + } + return LV_UNDEF_ARABIC_PERSIAN_CHARS; +} + +static uint32_t lv_txt_lam_alef(uint32_t ch_curr, uint32_t ch_next) +{ + uint32_t ch_code = 0; + if(ap_chars_map[ch_curr].char_offset != 34) { + return 0; + } + if(ch_next == LV_UNDEF_ARABIC_PERSIAN_CHARS) { + return 0; + } + ch_code = ap_chars_map[ch_next].char_offset + LV_AP_ALPHABET_BASE_CODE; + if(ch_code == 0x0622) { + return 0xFEF5; // (lam-alef) mad + } + if(ch_code == 0x0623) { + return 0xFEF7; // (lam-alef) top hamza + } + if(ch_code == 0x0625) { + return 0xFEF9; // (lam-alef) bot hamza + } + if(ch_code == 0x0627) { + return 0xFEFB; // (lam-alef) alef + } + return 0; +} + +#endif diff --git a/src/libs/lvgl/src/lv_misc/lv_txt_ap.h b/src/libs/lvgl/src/lv_misc/lv_txt_ap.h new file mode 100644 index 00000000..d5742013 --- /dev/null +++ b/src/libs/lvgl/src/lv_misc/lv_txt_ap.h @@ -0,0 +1,60 @@ +/** + * @file lv_txt_ap.h + * + */ + +#ifndef LV_TXT_AP_H +#define LV_TXT_AP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include <stddef.h> +#include "lv_txt.h" +#include "../lv_draw/lv_draw.h" + +#if LV_USE_ARABIC_PERSIAN_CHARS == 1 + +/********************* + * DEFINES + *********************/ + +#define LV_UNDEF_ARABIC_PERSIAN_CHARS (UINT32_MAX) +#define LV_AP_ALPHABET_BASE_CODE 0x0622 +#define LV_AP_END_CHARS_LIST {0,0,0,0,0,{0,0}} +/********************** + * TYPEDEFS + **********************/ +typedef struct { + uint8_t char_offset; + uint16_t char_end_form; + int8_t char_begining_form_offset; + int8_t char_middle_form_offset; + int8_t char_isolated_form_offset; + struct { + uint8_t conj_to_previous; + uint8_t conj_to_next; + } ap_chars_conjunction; +} ap_chars_map_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +uint32_t _lv_txt_ap_calc_bytes_cnt(const char * txt); +void _lv_txt_ap_proc(const char * txt, char * txt_out); + +/********************** + * MACROS + **********************/ + +#endif // LV_USE_ARABIC_PERSIAN_CHARS + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TXT_AP_H*/ diff --git a/src/libs/lvgl/src/lv_misc/lv_types.h b/src/libs/lvgl/src/lv_misc/lv_types.h index 2c28bca1..95663e3c 100644 --- a/src/libs/lvgl/src/lv_misc/lv_types.h +++ b/src/libs/lvgl/src/lv_misc/lv_types.h @@ -17,16 +17,22 @@ extern "C" { /********************* * DEFINES *********************/ -// Check windows -#ifdef _WIN64 -#define LV_ARCH_64 + +#if defined(__cplusplus) || __STDC_VERSION__ >= 199901L // If c99 or newer, use stdint.h to determine arch size +#include <stdint.h> #endif -// Check GCC -#ifdef __GNUC__ -#if defined(__x86_64__) || defined(__ppc64__) +// If __UINTPTR_MAX__ or UINTPTR_MAX are available, use them to determine arch size +#if defined(__UINTPTR_MAX__) && __UINTPTR_MAX__ > 0xFFFFFFFF #define LV_ARCH_64 -#endif + +#elif defined(UINTPTR_MAX) && UINTPTR_MAX > 0xFFFFFFFF +#define LV_ARCH_64 + +// Otherwise use compiler-dependent means to determine arch size +#elif defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) || defined (__aarch64__) +#define LV_ARCH_64 + #endif /********************** @@ -34,7 +40,7 @@ extern "C" { **********************/ /** - * LittlevGL error codes. + * LVGL error codes. */ enum { LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action @@ -43,12 +49,21 @@ enum { }; typedef uint8_t lv_res_t; +#if defined(__cplusplus) || __STDC_VERSION__ >= 199901L +// If c99 or newer, use the definition of uintptr_t directly from <stdint.h> +typedef uintptr_t lv_uintptr_t; + +#else + +// Otherwise, use the arch size determination #ifdef LV_ARCH_64 typedef uint64_t lv_uintptr_t; #else typedef uint32_t lv_uintptr_t; #endif +#endif + /********************** * GLOBAL PROTOTYPES **********************/ @@ -57,6 +72,14 @@ typedef uint32_t lv_uintptr_t; * MACROS **********************/ +#define LV_UNUSED(x) ((void) x) + +#define _LV_CONCAT(x, y) x ## y +#define LV_CONCAT(x, y) _LV_CONCAT(x, y) + +#define _LV_CONCAT3(x, y, z) x ## y ## z +#define LV_CONCAT3(x, y, z) _LV_CONCAT3(x, y, z) + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/libs/lvgl/src/lv_misc/lv_utils.c b/src/libs/lvgl/src/lv_misc/lv_utils.c index 3f189560..ea2a17b0 100644 --- a/src/libs/lvgl/src/lv_misc/lv_utils.c +++ b/src/libs/lvgl/src/lv_misc/lv_utils.c @@ -10,6 +10,8 @@ #include "lv_utils.h" #include "lv_math.h" +#include "lv_printf.h" +#include "lv_txt.h" /********************* * DEFINES @@ -41,7 +43,7 @@ * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) * @return same as `buf` (just for convenience) */ -char * lv_utils_num_to_str(int32_t num, char * buf) +char * _lv_utils_num_to_str(int32_t num, char * buf) { if(num == 0) { buf[0] = '0'; @@ -89,8 +91,8 @@ char * lv_utils_num_to_str(int32_t num, char * buf) * * @return a pointer to a matching item, or NULL if none exists. */ -void * lv_utils_bsearch(const void * key, const void * base, uint32_t n, uint32_t size, - int32_t (*cmp)(const void * pRef, const void * pElement)) +void * _lv_utils_bsearch(const void * key, const void * base, uint32_t n, uint32_t size, + int32_t (*cmp)(const void * pRef, const void * pElement)) { const char * middle; int32_t c; @@ -100,10 +102,12 @@ void * lv_utils_bsearch(const void * key, const void * base, uint32_t n, uint32_ if((c = (*cmp)(key, middle)) > 0) { n = (n / 2) - ((n & 1) == 0); base = (middle += size); - } else if(c < 0) { + } + else if(c < 0) { n /= 2; middle = base; - } else { + } + else { return (char *)middle; } } diff --git a/src/libs/lvgl/src/lv_misc/lv_utils.h b/src/libs/lvgl/src/lv_misc/lv_utils.h index 6eed7950..4d74029f 100644 --- a/src/libs/lvgl/src/lv_misc/lv_utils.h +++ b/src/libs/lvgl/src/lv_misc/lv_utils.h @@ -33,7 +33,7 @@ extern "C" { * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) * @return same as `buf` (just for convenience) */ -char * lv_utils_num_to_str(int32_t num, char * buf); +char * _lv_utils_num_to_str(int32_t num, char * buf); /** Searches base[0] to base[n - 1] for an item that matches *key. * @@ -52,8 +52,8 @@ char * lv_utils_num_to_str(int32_t num, char * buf); * * @return a pointer to a matching item, or NULL if none exists. */ -void * lv_utils_bsearch(const void * key, const void * base, uint32_t n, uint32_t size, - int32_t (*cmp)(const void * pRef, const void * pElement)); +void * _lv_utils_bsearch(const void * key, const void * base, uint32_t n, uint32_t size, + int32_t (*cmp)(const void * pRef, const void * pElement)); /********************** * MACROS |