diff --git a/README.md b/README.md index cb9a00527..6bfd28d7d 100644 --- a/README.md +++ b/README.md @@ -72,24 +72,31 @@ In the most simple case you need to do these steps: 1. Copy `lv_conf_templ.h` as `lv_conf.h` next to `lvgl` and set at least `LV_HOR_RES`, `LV_VER_RES` and `LV_COLOR_DEPTH`. 2. Call `lv_tick_inc(x)` every `x` milliseconds in a Timer or Task (`x` should be between 1 and 10) 3. Call `lv_init()` -4. Register a function which can **copy a pixel array** to an area of the screen: +4. Create a buffer for LittlevGL +```c +static lv_disp_buf_t disp_buf; +static lv_color_t buf[LV_HOR_RES_MAX * 10]; /*Declare a buffer for 10 lines*/ +v_disp_buf_init(&disp_buf1, buf, NULL, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/ +``` +4. Implement and register a function which can **copy a pixel array** to an area of your diplay: ```c lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ -disp_drv.disp_flush = disp_flush; /*Set your driver function*/ +disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/ +disp_drv.buffer = &disp_buf; /*Assign the buffer to teh display*/ lv_disp_drv_register(&disp_drv); /*Finally register the driver*/ -void disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p) { int32_t x, y; - for(y = y1; y <= y2; y++) { - for(x = x1; x <= x2; x++) { - sep_pixel(x, y, *color_p); /* Put a pixel to the display.*/ + for(y = area->y1; y <= area->y2; y++) { + for(x = area->x1; x <= area->x2; x++) { + set_pixel(x, y, *color_p); /* Put a pixel to the display.*/ color_p++; } } - lv_flush_ready(); /* Tell you are ready with the flushing*/ + lv_disp_flush_ready(disp); /* Tell you are ready with the flushing*/ } ``` diff --git a/lv_core/lv_core.mk b/lv_core/lv_core.mk index 9992e3fe7..ac69f25e3 100644 --- a/lv_core/lv_core.mk +++ b/lv_core/lv_core.mk @@ -1,9 +1,9 @@ CSRCS += lv_group.c CSRCS += lv_indev.c +CSRCS += lv_disp.c CSRCS += lv_obj.c CSRCS += lv_refr.c CSRCS += lv_style.c -CSRCS += lv_vdb.c CSRCS += lv_lang.c DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core diff --git a/lv_core/lv_disp.c b/lv_core/lv_disp.c index 6017ba27c..dc4578d17 100644 --- a/lv_core/lv_disp.c +++ b/lv_core/lv_disp.c @@ -33,34 +33,82 @@ **********************/ /** - * Get the number of areas in the buffer - * @return number of invalid areas + * Return with a pointer to the active screen + * @param disp pointer to display which active screen should be get. (NULL to use the default screen) + * @return pointer to the active screen object (loaded by 'lv_scr_load()') */ -uint16_t lv_disp_get_inv_buf_size(lv_disp_t * disp) +lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp) { - return disp->inv_p; + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("lv_scr_act: no display registered to get its top layer"); + return NULL; + } + + return disp->act_scr; } /** - * Pop (delete) the last 'num' invalidated areas from the buffer - * @param num number of areas to delete + * Make a screen active + * @param scr pointer to a screen */ -void lv_disp_pop_from_inv_buf(lv_disp_t * disp, uint16_t num) +void lv_disp_set_scr_act(lv_obj_t * scr) { + lv_disp_t * d = lv_obj_get_disp(scr); - if(disp->inv_p < num) disp->inv_p = 0; - else disp->inv_p -= num; + d->act_scr = scr; + + lv_obj_invalidate(scr); } +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @param disp pointer to display which top layer should be get. (NULL to use the default screen) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp) +{ + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("lv_layer_top: no display registered to get its top layer"); + return NULL; + } + + return disp->top_layer; +} + +/** + * Return with the sys. layer. (Same on every screen and it is above the normal screen and the top layer) + * @param disp pointer to display which sys. layer should be get. (NULL to use the default screen) + * @return pointer to the sys layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp) +{ + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("lv_layer_sys: no display registered to get its top layer"); + return NULL; + } + + return disp->sys_layer; +} + +/** + * Assign a screen to a display. + * @param disp pointer to a display where to assign the screen + * @param scr pointer to a screen object to assign + */ void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr) { - lv_disp_t * old_disp = lv_scr_get_disp(scr); - - if(old_disp == disp) { - LV_LOG_WARN("lv_disp_assign_screen: tried to assign to the same screen") + if(lv_obj_get_parent(scr) != NULL) { + LV_LOG_WARN("lv_disp_assign_screen: try to assign a non-screen object"); return; } + lv_disp_t * old_disp = lv_obj_get_disp(scr); + + if(old_disp == disp) return; + lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr); } diff --git a/lv_core/lv_disp.h b/lv_core/lv_disp.h index 62690f551..def7bceed 100644 --- a/lv_core/lv_disp.h +++ b/lv_core/lv_disp.h @@ -27,20 +27,41 @@ extern "C" { /********************** * GLOBAL PROTOTYPES **********************/ + +/** + * Return with a pointer to the active screen + * @param disp pointer to display which active screen should be get. (NULL to use the default screen) + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp); + +/** + * Make a screen active + * @param scr pointer to a screen + */ +void lv_disp_set_scr_act(lv_obj_t * scr); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @param disp pointer to display which top layer should be get. (NULL to use the default screen) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp); + +/** + * Return with the sys. layer. (Same on every screen and it is above the normal screen and the top layer) + * @param disp pointer to display which sys. layer should be get. (NULL to use the default screen) + * @return pointer to the sys layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp); + +/** + * Assign a screen to a display. + * @param disp pointer to a display where to assign the screen + * @param scr pointer to a screen object to assign + */ void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr); -/** - * Get the number of areas in the buffer - * @return number of invalid areas - */ -uint16_t lv_disp_get_inv_buf_size(lv_disp_t * disp); - -/** - * Pop (delete) the last 'num' invalidated areas from the buffer - * @param num number of areas to delete - */ -void lv_disp_pop_from_inv_buf(lv_disp_t * disp, uint16_t num); - /********************** * MACROS **********************/ diff --git a/lv_core/lv_indev.c b/lv_core/lv_indev.c index 01d1f03ce..989277c64 100644 --- a/lv_core/lv_indev.c +++ b/lv_core/lv_indev.c @@ -126,12 +126,12 @@ void lv_indev_reset_lpr(lv_indev_t * indev) void lv_indev_enable(lv_hal_indev_type_t type, bool enable) { -// lv_indev_t * i = lv_indev_next(NULL); -// -// while(i) { -// if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0; -// i = lv_indev_next(i); -// } + lv_indev_t * i = lv_indev_next(NULL); + + while(i) { + if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0; + i = lv_indev_next(i); + } } /** @@ -144,7 +144,7 @@ void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj) if(indev->driver.type != LV_INDEV_TYPE_POINTER) return; indev->cursor = cur_obj; - lv_obj_set_parent(indev->cursor, lv_layer_sys(indev->driver.disp)); + lv_obj_set_parent(indev->cursor, lv_disp_get_layer_sys(indev->driver.disp)); lv_obj_set_pos(indev->cursor, indev->proc.act_point.x, indev->proc.act_point.y); } @@ -250,22 +250,19 @@ void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point) uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev) { - //TODO -// uint32_t t; -// -// if(indev) return t = lv_tick_elaps(indev->last_activity_time); -// -// lv_indev_t * i; -// t = UINT16_MAX; -// i = lv_indev_next(NULL); -// while(i) { -// t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time)); -// i = lv_indev_next(i); -// } -// -// return t; + uint32_t t; - return 0; + if(indev) return t = lv_tick_elaps(indev->last_activity_time); + + lv_indev_t * i; + t = UINT16_MAX; + i = lv_indev_next(NULL); + while(i) { + t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time)); + i = lv_indev_next(i); + } + + return t; } /** @@ -547,8 +544,8 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data) */ static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data) { - i->proc.act_point.x = i->btn_points[data->btn].x; - i->proc.act_point.y = i->btn_points[data->btn].y; + i->proc.act_point.x = i->btn_points[data->btn_id].x; + i->proc.act_point.y = i->btn_points[data->btn_id].y; /*Still the same point is pressed*/ if(i->proc.last_point.x == i->proc.act_point.x && @@ -586,16 +583,16 @@ static void indev_proc_press(lv_indev_proc_t * proc) /*If there is no last object then search*/ if(proc->act_obj == NULL) { - pr_obj = indev_search_obj(proc, lv_layer_sys(disp)); - if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_layer_top(disp)); - if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act(disp)); + pr_obj = indev_search_obj(proc, lv_disp_get_layer_sys(disp)); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_layer_top(disp)); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_scr_act(disp)); } /*If there is last object but it is not dragged and not protected also search*/ else if(proc->drag_in_prog == 0 && lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST) == false) {/*Now act_obj != NULL*/ - pr_obj = indev_search_obj(proc, lv_layer_sys(disp)); - if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_layer_top(disp)); - if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act(disp)); + pr_obj = indev_search_obj(proc, lv_disp_get_layer_sys(disp)); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_layer_top(disp)); + if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_scr_act(disp)); } /*If a dragable or a protected object was the last then keep it*/ else { diff --git a/lv_core/lv_obj.c b/lv_core/lv_obj.c index 59c3d2c0f..16798ff87 100644 --- a/lv_core/lv_obj.c +++ b/lv_core/lv_obj.c @@ -10,6 +10,7 @@ #include "lv_indev.h" #include "lv_refr.h" #include "lv_group.h" +#include "lv_disp.h" #include "../lv_themes/lv_theme.h" #include "../lv_draw/lv_draw.h" #include "../lv_misc/lv_anim.h" @@ -356,7 +357,7 @@ lv_res_t lv_obj_del(lv_obj_t * obj) /*Remove the object from parent's children list*/ lv_obj_t * par = lv_obj_get_parent(obj); if(par == NULL) { /*It is a screen*/ - lv_disp_t * d = lv_scr_get_disp(obj); + lv_disp_t * d = lv_obj_get_disp(obj); lv_ll_rem(&d->scr_ll, obj); } else { lv_ll_rem(&(par->child_ll), obj); @@ -415,10 +416,10 @@ void lv_obj_invalidate(const lv_obj_t * obj) /*Invalidate the object only if it belongs to the 'LV_GC_ROOT(_lv_act_scr)'*/ lv_obj_t * obj_scr = lv_obj_get_screen(obj); - lv_disp_t * disp = lv_scr_get_disp(obj_scr); - if(obj_scr == lv_scr_act(disp) || - obj_scr == lv_layer_top(disp)|| - obj_scr == lv_layer_sys(disp)) { + lv_disp_t * disp = lv_obj_get_disp(obj_scr); + if(obj_scr == lv_disp_get_scr_act(disp) || + obj_scr == lv_disp_get_layer_top(disp)|| + obj_scr == lv_disp_get_layer_sys(disp)) { /*Truncate recursively to the parents*/ lv_area_t area_trunc; lv_obj_t * par = lv_obj_get_parent(obj); @@ -449,23 +450,6 @@ void lv_obj_invalidate(const lv_obj_t * obj) * Setter functions *====================*/ - -/*-------------- - * Screen set - *--------------*/ -/** - * Load a new screen - * @param scr pointer to a screen - */ -void lv_scr_load(lv_obj_t * scr) -{ - lv_disp_t * d = lv_scr_get_disp(scr); - - d->act_scr = scr; - - lv_obj_invalidate(scr); -} - /*-------------------- * Parent/children set *--------------------*/ @@ -1302,55 +1286,6 @@ void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint1 * Getter functions *======================*/ -/*------------------ - * Screen get - *-----------------*/ - -/** - * Return with a pointer to the active screen - * @return pointer to the active screen object (loaded by 'lv_scr_load()') - */ -lv_obj_t * lv_scr_act(lv_disp_t * disp) -{ - if(!disp) disp = lv_disp_get_default(); - if(!disp) { - LV_LOG_WARN("lv_scr_act: no display registered to get its top layer"); - return NULL; - } - - return disp->act_scr; -} - -/** - * Return with the top layer. (Same on every screen and it is above the normal screen layer) - * @return pointer to the top layer object (transparent screen sized lv_obj) - */ -lv_obj_t * lv_layer_top(lv_disp_t * disp) -{ - if(!disp) disp = lv_disp_get_default(); - if(!disp) { - LV_LOG_WARN("lv_layer_top: no display registered to get its top layer"); - return NULL; - } - - return disp->top_layer; -} - -/** - * Return with the sys. layer. (Same on every screen and it is above the normal screen layer) - * @return pointer to the sys layer object (transparent screen sized lv_obj) - */ -lv_obj_t * lv_layer_sys(lv_disp_t * disp) -{ - if(!disp) disp = lv_disp_get_default(); - if(!disp) { - LV_LOG_WARN("lv_layer_sys: no display registered to get its top layer"); - return NULL; - } - - return disp->sys_layer; -} - /** * Return with the screen of an object * @param obj pointer to an object @@ -1369,10 +1304,19 @@ lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj) return (lv_obj_t *)act_p; } -lv_disp_t * lv_scr_get_disp(lv_obj_t * scr) +/** + * Get the display of an object + * @param scr pointer to an object + * @return pointer the object's display + */ +lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj) { - lv_disp_t * d; + const lv_obj_t * scr; + if(obj->par == NULL) scr = obj; /*`obj` is a screen*/ + else scr = lv_obj_get_screen(obj); /*get the screen of `obj`*/ + + lv_disp_t * d; LL_READ(LV_GC_ROOT(_lv_disp_ll), d) { lv_obj_t * s; LL_READ(d->scr_ll, s) { @@ -1384,14 +1328,6 @@ lv_disp_t * lv_scr_get_disp(lv_obj_t * scr) return NULL; } - - -lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj) -{ - lv_obj_t * scr = lv_obj_get_screen(obj); - return lv_scr_get_disp(scr); -} - /*--------------------- * Parent/children get *--------------------*/ diff --git a/lv_core/lv_obj.h b/lv_core/lv_obj.h index 29f3ac9dd..ca4380c0b 100644 --- a/lv_core/lv_obj.h +++ b/lv_core/lv_obj.h @@ -261,16 +261,6 @@ void lv_obj_invalidate(const lv_obj_t * obj); * Setter functions *====================*/ -/*-------------- - * Screen set - *--------------*/ - -/** - * Load a new screen - * @param scr pointer to a screen - */ -void lv_scr_load(lv_obj_t * scr); - /*-------------------- * Parent/children set *--------------------*/ @@ -540,28 +530,6 @@ void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint1 * Getter functions *======================*/ -/*------------------ - * Screen get - *-----------------*/ - -/** - * Return with a pointer to the active screen - * @return pointer to the active screen object (loaded by 'lv_scr_load()') - */ -lv_obj_t * lv_scr_act(lv_disp_t * disp); - -/** - * Return with the top layer. (Same on every screen and it is above the normal screen layer) - * @return pointer to the top layer object (transparent screen sized lv_obj) - */ -lv_obj_t * lv_layer_top(lv_disp_t * disp); - -/** - * Return with the sys. layer. (Same on every screen and it is above the normal screen layer) - * @return pointer to the sys layer object (transparent screen sized lv_obj) - */ -lv_obj_t * lv_layer_sys(lv_disp_t * disp); - /** * Return with the screen of an object * @param obj pointer to an object @@ -569,9 +537,11 @@ lv_obj_t * lv_layer_sys(lv_disp_t * disp); */ lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj); - -lv_disp_t * lv_scr_get_disp(lv_obj_t * scr); - +/** + * Get the display of an object + * @param scr pointer to an object + * @return pointer the object's display + */ lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj); /*--------------------- diff --git a/lv_core/lv_refr.c b/lv_core/lv_refr.c index 3f854c1ad..e665e1a11 100644 --- a/lv_core/lv_refr.c +++ b/lv_core/lv_refr.c @@ -39,8 +39,6 @@ static void lv_refr_vdb_flush(void); /********************** * STATIC VARIABLES **********************/ -static void (*monitor_cb)(uint32_t, uint32_t); /*Monitor the rendering time*/ -static void (*round_cb)(lv_area_t *); /*If set then called to modify invalidated areas for special display controllers*/ static uint32_t px_num; static lv_disp_t * disp_refr; /*Display being refreshed*/ @@ -103,7 +101,7 @@ void lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p) /*The area is truncated to the screen*/ if(suc != false) { - if(round_cb) round_cb(&com_area); + if(disp_refr->driver.rounder_cb) disp_refr->driver.rounder_cb(disp_refr, &com_area); /*Save only if this area is not in one of the saved areas*/ uint16_t i; @@ -122,29 +120,6 @@ void lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p) } } - -/** - * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels - * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) - * time_ms: refresh time in [ms] - * px_num: not the drawn pixels but the number of affected pixels of the screen - * (more pixels are drawn because of overlapping objects) - */ -void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)) -{ - monitor_cb = cb; -} - -/** - * Called when an area is invalidated to modify the coordinates of the area. - * Special display controllers may require special coordinate rounding - * @param cb pointer to the a function which will modify the area - */ -void lv_refr_set_round_cb(void(*cb)(lv_area_t *)) -{ - round_cb = cb; -} - /** * Get the display which is being refreshed * @return the display being refreshed @@ -180,8 +155,8 @@ static void lv_refr_task(void * param) /*If refresh happened ...*/ if(disp_refr->inv_p != 0) { /*In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date*/ - if(lv_disp_is_true_double_buffered(disp_refr)) { - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp_refr); + if(lv_disp_is_true_double_buf(disp_refr)) { + lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr); /*Flush the content of the VDB*/ lv_refr_vdb_flush(); @@ -194,16 +169,17 @@ static void lv_refr_task(void * param) uint8_t * buf_act = (uint8_t *) vdb->buf_act; uint8_t * buf_ina = (uint8_t *) vdb->buf_act == vdb->buf1 ? vdb->buf2 : vdb->buf1; + lv_coord_t hres = lv_disp_get_hor_res(disp_refr); uint16_t a; for(a = 0; a < disp_refr->inv_p; a++) { if(disp_refr->inv_area_joined[a] == 0) { lv_coord_t y; - uint32_t start_offs = ((disp_refr->driver.hor_res * disp_refr->inv_areas[a].y1 + disp_refr->inv_areas[a].x1) * LV_VDB_PX_BPP) >> 3; - uint32_t line_length = (lv_area_get_width(&disp_refr->inv_areas[a]) * LV_VDB_PX_BPP) >> 3; + uint32_t start_offs = (hres * disp_refr->inv_areas[a].y1 + disp_refr->inv_areas[a].x1) * sizeof(lv_color_t); + uint32_t line_length = lv_area_get_width(&disp_refr->inv_areas[a]) * sizeof(lv_color_t); for(y = disp_refr->inv_areas[a].y1; y <= disp_refr->inv_areas[a].y2; y++) { memcpy(buf_act + start_offs, buf_ina + start_offs, line_length); - start_offs += (LV_HOR_RES * LV_VDB_PX_BPP) >> 3; + start_offs += hres * sizeof(lv_color_t); } } } @@ -215,8 +191,8 @@ static void lv_refr_task(void * param) disp_refr->inv_p = 0; /*Call monitor cb if present*/ - if(monitor_cb != NULL) { - monitor_cb(lv_tick_elaps(start), px_num); + if(disp_refr->driver.monitor_cb) { + disp_refr->driver.monitor_cb(disp_refr, lv_tick_elaps(start), px_num); } } } @@ -278,7 +254,7 @@ static void lv_refr_areas(void) lv_refr_area(&disp_refr->inv_areas[i]); - if(monitor_cb != NULL) px_num += lv_area_get_size(&disp_refr->inv_areas[i]); + if(disp_refr->driver.monitor_cb) px_num += lv_area_get_size(&disp_refr->inv_areas[i]); } } } @@ -290,17 +266,17 @@ static void lv_refr_areas(void) static void lv_refr_area(const lv_area_t * area_p) { /*True double buffering: there are two screen sized buffers. Just redraw directly into a buffer*/ - if(lv_disp_is_true_double_buffered(disp_refr)) { - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp_refr); + if(lv_disp_is_true_double_buf(disp_refr)) { + lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr); vdb->area.x1 = 0; - vdb->area.x2 = LV_HOR_RES-1; + vdb->area.x2 = lv_disp_get_hor_res(disp_refr) - 1; vdb->area.y1 = 0; - vdb->area.y2 = LV_VER_RES - 1; + vdb->area.y2 = lv_disp_get_ver_res(disp_refr) - 1; lv_refr_area_part(area_p); } /*The buffer is smaller: refresh the area in parts*/ else { - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp_refr); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr); /*Calculate the max row num*/ lv_coord_t w = lv_area_get_width(area_p); lv_coord_t h = lv_area_get_height(area_p); @@ -311,7 +287,7 @@ static void lv_refr_area(const lv_area_t * area_p) if(max_row > h) max_row = h; /*Round down the lines of VDB if rounding is added*/ - if(round_cb) { + if(disp_refr->driver.rounder_cb) { lv_area_t tmp; tmp.x1 = 0; tmp.x2 = 0; @@ -321,7 +297,7 @@ static void lv_refr_area(const lv_area_t * area_p) lv_coord_t y_tmp = max_row; do { tmp.y2 = y_tmp; - round_cb(&tmp); + disp_refr->driver.rounder_cb(disp_refr, &tmp); y_tmp --; /*Decrement the number of line until it is rounded to a smaller (or equal) value then the original. */ } while(lv_area_get_height(&tmp) > max_row && y_tmp != 0); @@ -368,10 +344,10 @@ static void lv_refr_area(const lv_area_t * area_p) static void lv_refr_area_part(const lv_area_t * area_p) { - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp_refr); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr); /*In non double buffered mode, before rendering the next part wait until the previous image is flushed*/ - if(lv_disp_is_double_vdb(disp_refr) == false) { + if(lv_disp_is_double_buf(disp_refr) == false) { while(vdb->flushing); } @@ -383,18 +359,18 @@ static void lv_refr_area_part(const lv_area_t * area_p) lv_area_intersect(&start_mask, area_p, &vdb->area); /*Get the most top object which is not covered by others*/ - top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act(disp_refr)); + top_p = lv_refr_get_top_obj(&start_mask, lv_disp_get_scr_act(disp_refr)); /*Do the refreshing from the top object*/ lv_refr_obj_and_children(top_p, &start_mask); /*Also refresh top and sys layer unconditionally*/ - lv_refr_obj_and_children(lv_layer_top(disp_refr), &start_mask); - lv_refr_obj_and_children(lv_layer_sys(disp_refr), &start_mask); + lv_refr_obj_and_children(lv_disp_get_layer_top(disp_refr), &start_mask); + lv_refr_obj_and_children(lv_disp_get_layer_sys(disp_refr), &start_mask); /* In true double buffered mode flush only once when all areas were rendered. * In normal mode flush after every area */ - if(lv_disp_is_true_double_buffered(disp_refr) == false) { + if(lv_disp_is_true_double_buf(disp_refr) == false) { lv_refr_vdb_flush(); } } @@ -445,7 +421,7 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p) /* Normally always will be a top_obj (at least the screen) * but in special cases (e.g. if the screen has alpha) it won't. * In this case use the screen directly */ - if(top_p == NULL) top_p = lv_scr_act(disp_refr); + if(top_p == NULL) top_p = lv_disp_get_scr_act(disp_refr); /*Refresh the top object and its children*/ lv_refr_obj(top_p, mask_p); @@ -552,7 +528,7 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) */ static void lv_refr_vdb_flush(void) { - lv_disp_buf_t * vdb = lv_disp_get_vdb(lv_refr_get_disp_refreshing()); + lv_disp_buf_t * vdb = lv_disp_get_buf(lv_refr_get_disp_refreshing()); /*In double buffered mode wait until the other buffer is flushed before flushing the current one*/ if(vdb->buf1 && vdb->buf2) { @@ -563,7 +539,7 @@ static void lv_refr_vdb_flush(void) /*Flush the rendered content to the display*/ lv_disp_t * disp = lv_refr_get_disp_refreshing(); - if(disp->driver.disp_flush) disp->driver.disp_flush(disp, &vdb->area, vdb->buf_act); + if(disp->driver.flush_cb) disp->driver.flush_cb(disp, &vdb->area, vdb->buf_act); if(vdb->buf1 && vdb->buf2) { diff --git a/lv_core/lv_refr.h b/lv_core/lv_refr.h index a00e6ef92..2bd7d2b63 100644 --- a/lv_core/lv_refr.h +++ b/lv_core/lv_refr.h @@ -60,20 +60,6 @@ void lv_refr_now(void); */ void lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p); - -/** - * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels - * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) - */ -void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)); - -/** - * Called when an area is invalidated to modify the coordinates of the area. - * Special display controllers may require special coordinate rounding - * @param cb pointer to the a function which will modify the area - */ -void lv_refr_set_round_cb(void(*cb)(lv_area_t*)); - /** * Get the number of areas in the buffer * @return number of invalid areas diff --git a/lv_draw/lv_draw.mk b/lv_draw/lv_draw.mk index a384eefea..70fa7103f 100644 --- a/lv_draw/lv_draw.mk +++ b/lv_draw/lv_draw.mk @@ -1,5 +1,4 @@ -CSRCS += lv_draw_vbasic.c -CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw_basic.c CSRCS += lv_draw.c CSRCS += lv_draw_rect.c CSRCS += lv_draw_label.c diff --git a/lv_draw/lv_draw_basic.c b/lv_draw/lv_draw_basic.c index 516af1b9e..f675e54b5 100644 --- a/lv_draw/lv_draw_basic.c +++ b/lv_draw/lv_draw_basic.c @@ -79,15 +79,15 @@ void lv_draw_px(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t } lv_disp_t * disp = lv_refr_get_disp_refreshing(); - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); uint32_t vdb_width = lv_area_get_width(&vdb->area); /*Make the coordinates relative to VDB*/ x -= vdb->area.x1; y -= vdb->area.y1; - if(disp->driver.vdb_wr) { - disp->driver.vdb_wr((uint8_t *)vdb->buf_act, vdb_width, x, y, color, opa); + if(disp->driver.set_px_cb) { + disp->driver.set_px_cb(disp, (uint8_t *)vdb->buf_act, vdb_width, x, y, color, opa); } else { lv_color_t * vdb_px_p = vdb->buf_act; vdb_px_p += y * vdb_width + x; @@ -129,7 +129,7 @@ void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p, if(union_ok == false) return; lv_disp_t * disp = lv_refr_get_disp_refreshing(); - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); lv_area_t vdb_rel_a; /*Stores relative coordinates on vdb*/ vdb_rel_a.x1 = res_a.x1 - vdb->area.x1; @@ -290,7 +290,7 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return; lv_disp_t * disp = lv_refr_get_disp_refreshing(); - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); lv_coord_t vdb_width = lv_area_get_width(&vdb->area); lv_color_t * vdb_buf_tmp = vdb->buf_act; @@ -335,8 +335,8 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; } - if(disp->driver.vdb_wr) { - disp->driver.vdb_wr((uint8_t *)vdb->buf_act, vdb_width, + if(disp->driver.set_px_cb) { + disp->driver.set_px_cb(disp, (uint8_t *)vdb->buf_act, vdb_width, (col + pos_x) - vdb->area.x1, (row + pos_y) - vdb->area.y1, color, px_opa); } else { @@ -409,7 +409,7 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, } lv_disp_t * disp = lv_refr_get_disp_refreshing(); - lv_disp_buf_t * vdb = lv_disp_get_vdb(disp); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); /*Stores coordinates relative to the current VDB*/ masked_a.x1 = masked_a.x1 - vdb->area.x1; @@ -429,12 +429,12 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) { /*Use the custom VDB write function is exists*/ - if(disp->driver.vdb_wr) { + if(disp->driver.set_px_cb) { lv_coord_t col; for(row = masked_a.y1; row <= masked_a.y2; row++) { for(col = 0; col < map_useful_w; col++) { lv_color_t px_color = *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]); - disp->driver.vdb_wr((uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, px_color, opa); + disp->driver.set_px_cb(disp, (uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, px_color, opa); } map_p += map_width * px_size_byte; /*Next row on the map*/ } @@ -496,8 +496,8 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa); } /*Handle custom VDB write is present*/ - if(disp->driver.vdb_wr) { - disp->driver.vdb_wr((uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, recolored_px, opa_result); + if(disp->driver.set_px_cb) { + disp->driver.set_px_cb(disp, (uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, recolored_px, opa_result); } /*Normal native VDB write*/ else { @@ -506,8 +506,8 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, } } else { /*Handle custom VDB write is present*/ - if(disp->driver.vdb_wr) { - disp->driver.vdb_wr((uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, px_color, opa_result); + if(disp->driver.set_px_cb) { + disp->driver.set_px_cb(disp, (uint8_t *)vdb->buf_act, vdb_width, col + masked_a.x1, row, px_color, opa_result); } /*Normal native VDB write*/ else { @@ -568,10 +568,10 @@ static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_ lv_coord_t mem_width = lv_area_get_width(mem_area); lv_disp_t * disp = lv_refr_get_disp_refreshing(); - if(disp->driver.vdb_wr) { + if(disp->driver.set_px_cb) { for(col = fill_area->x1; col <= fill_area->x2; col++) { for(row = fill_area->y1; row <= fill_area->y2; row++) { - disp->driver.vdb_wr((uint8_t *)mem, mem_width, col, row, color, opa); + disp->driver.set_px_cb(disp, (uint8_t *)mem, mem_width, col, row, color, opa); } } } else { diff --git a/lv_hal/lv_hal_disp.c b/lv_hal/lv_hal_disp.c index 9e02c1fab..82e597fb3 100644 --- a/lv_hal/lv_hal_disp.c +++ b/lv_hal/lv_hal_disp.c @@ -24,9 +24,6 @@ /********************* * DEFINES *********************/ -#ifndef LV_ATTRIBUTE_FLUSH_READY -# define LV_ATTRIBUTE_FLUSH_READY -#endif /********************** * TYPEDEFS @@ -59,7 +56,7 @@ void lv_disp_drv_init(lv_disp_drv_t * driver) { memset(driver, 0, sizeof(lv_disp_drv_t)); - driver->disp_flush = NULL; + driver->flush_cb = NULL; driver->hor_res = LV_HOR_RES_MAX; driver->ver_res = LV_VER_RES_MAX; driver->buffer = NULL; @@ -69,7 +66,7 @@ void lv_disp_drv_init(lv_disp_drv_t * driver) driver->mem_fill = NULL; #endif - driver->vdb_wr = NULL; + driver->set_px_cb = NULL; } @@ -119,54 +116,48 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver) if(disp_def == NULL) disp_def = disp; + lv_disp_t * disp_def_tmp = disp_def; + disp_def = disp; /*Temporarily change the default screen to create the default screens on the new display*/ + disp->act_scr = lv_obj_create(NULL, NULL); /*Create a default screen on the display*/ disp->top_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/ disp->sys_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/ lv_obj_set_style(disp->top_layer, &lv_style_transp); lv_obj_set_style(disp->sys_layer, &lv_style_transp); - lv_disp_assign_screen(disp, disp->act_scr); - lv_disp_assign_screen(disp, disp->top_layer); - lv_disp_assign_screen(disp, disp->sys_layer); - disp->inv_p = 0; - disp->vdb_act = 0; - disp->vdb_flushing = 0; lv_obj_invalidate(disp->act_scr); + disp_def = disp_def_tmp; /*Revert the default display*/ + return disp; } /** - * Get the next display. - * @param disp pointer to the current display. NULL to initialize. - * @return the next display or NULL if no more. Give the first display when the parameter is NULL + * Set a default screen. The new screens will be created on it by default. + * @param disp pointer to a display */ -lv_disp_t * lv_disp_get_next(lv_disp_t * disp) -{ - if(disp == NULL) return lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll)); - else return lv_ll_get_next(&LV_GC_ROOT(_lv_disp_ll), disp); -} - - void lv_disp_set_default(lv_disp_t * disp) { disp_def = disp; } - +/** + * Get the default display + * @return pointer to the default display + */ lv_disp_t * lv_disp_get_default(void) { return disp_def; } -lv_disp_buf_t * lv_disp_get_vdb(lv_disp_t * disp) -{ - return disp->driver.buffer; -} - +/** + * Get the horizontal resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the horizontal resolution of the display + */ lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp) { if(disp == NULL) disp = lv_disp_get_default(); @@ -175,7 +166,11 @@ lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp) else return disp->driver.hor_res; } - +/** + * Get the vertical resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the vertical resolution of the display + */ lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp) { if(disp == NULL) disp = lv_disp_get_default(); @@ -184,19 +179,6 @@ lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp) else return disp->driver.ver_res; } -bool lv_disp_is_double_vdb(lv_disp_t * disp) -{ - if(disp->driver.buffer->buf1 && disp->driver.buffer->buf2) return true; - else return false; -} - -bool lv_disp_is_true_double_buffered(lv_disp_t * disp) -{ - if(lv_disp_is_double_vdb(disp) && disp->driver.buffer->size == disp->driver.hor_res * disp->driver.ver_res) return true; - else return false; -} - - /** * Call in the display driver's `flush` function when the flushing is finished */ @@ -211,7 +193,77 @@ LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_t * disp) } +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_get_next(lv_disp_t * disp) +{ + if(disp == NULL) return lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll)); + else return lv_ll_get_next(&LV_GC_ROOT(_lv_disp_ll), disp); +} + +/** + * Get the internal buffer of a display + * @param disp pointer to a display + * @return pointer to the internal buffers + */ +lv_disp_buf_t * lv_disp_get_buf(lv_disp_t * disp) +{ + return disp->driver.buffer; +} + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_disp_get_inv_buf_size(lv_disp_t * disp) +{ + return disp->inv_p; +} + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_disp_pop_from_inv_buf(lv_disp_t * disp, uint16_t num) +{ + + if(disp->inv_p < num) disp->inv_p = 0; + else disp->inv_p -= num; +} + +/** + * Check the driver configuration if it's double buffered (both `buf1` and `buf2` are set) + * @param disp pointer to to display to check + * @return true: double buffered; false: not double buffered + */ +bool lv_disp_is_double_buf(lv_disp_t * disp) +{ + if(disp->driver.buffer->buf1 && disp->driver.buffer->buf2) return true; + else return false; +} + +/** + * Check the driver configuration if it's TRUE double buffered (both `buf1` and `buf2` are set and `size` is screen sized) + * @param disp pointer to to display to check + * @return true: double buffered; false: not double buffered + */ +bool lv_disp_is_true_double_buf(lv_disp_t * disp) +{ + uint32_t scr_size = disp->driver.hor_res * disp->driver.ver_res; + + if(lv_disp_is_double_buf(disp) && + disp->driver.buffer->size == scr_size) { + return true; + } + else { + return false; + } +} + + /********************** * STATIC FUNCTIONS **********************/ - diff --git a/lv_hal/lv_hal_disp.h b/lv_hal/lv_hal_disp.h index 01be7003a..256e377f1 100644 --- a/lv_hal/lv_hal_disp.h +++ b/lv_hal/lv_hal_disp.h @@ -29,6 +29,10 @@ extern "C" { #define LV_INV_BUF_SIZE 32 /*Buffer size for invalid areas */ #endif +#ifndef LV_ATTRIBUTE_FLUSH_READY +# define LV_ATTRIBUTE_FLUSH_READY +#endif + /********************** * TYPEDEFS **********************/ @@ -53,28 +57,42 @@ typedef struct * Display Driver structure to be registered by HAL */ typedef struct _disp_drv_t { - int user_data; + /*Horizontal and vertical resolution*/ lv_coord_t hor_res; - lv_coord_t ver_res; + /* Pointer to a buffer initialized with `lv_disp_buf_init()`. + * LittlevGL will use this buffer(s) to draw the screens contents */ lv_disp_buf_t * buffer; - /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/ - void (*disp_flush)(struct _disp_t * disp, const lv_area_t * area, lv_color_t * color_p); + /* MANDATORY: Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished */ + void (*flush_cb)(struct _disp_t * disp, const lv_area_t * area, lv_color_t * color_p); + lv_disp_user_data_t flush_user_data; + + /* OPTIONAL: Called after every refresh cycle to tell the rendering and flushing time + the number of flushed pixels */ + void (*monitor_cb)(struct _disp_t * disp, uint32_t time, uint32_t px); + lv_disp_user_data_t monitor_user_data; + + /* OPTIONAL: Extend the invalidated areas to match with the display drivers requirements + * E.g. round `y` to, 8, 16 ..) on a monochrome display*/ + void (*rounder_cb)(struct _disp_t * disp, lv_area_t * area); + lv_disp_user_data_t rounder_user_data; + + /* OPTIONAL: Set a pixel in a buffer according to the special requirements of the display + * Can be used for color format not supported in LittelvGL. E.g. 2 bit -> 4 gray scales + * Note: Much slower then drawing with supported color formats. */ + void (*set_px_cb)(struct _disp_t * disp, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); + lv_disp_user_data_t set_px_user_data; - /*Optional interface functions to use GPU*/ #if USE_LV_GPU - /*Blend two memories using opacity (GPU only)*/ + /*OPTIONAL: Blend two memories using opacity (GPU only)*/ void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); - /*Fill a memory with a color (GPU only)*/ + /*OPTIONAL: Fill a memory with a color (GPU only)*/ void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color); #endif - /*Optional: Set a pixel in a buffer according to the requirements of the display*/ - void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); } lv_disp_drv_t; struct _lv_obj_t; @@ -88,9 +106,6 @@ typedef struct _disp_t { lv_area_t inv_areas[LV_INV_BUF_SIZE]; uint8_t inv_area_joined[LV_INV_BUF_SIZE]; uint32_t inv_p :10; - uint32_t orientation :2; - uint32_t vdb_flushing :1; - uint32_t vdb_act :1; } lv_disp_t; /********************** @@ -103,15 +118,7 @@ typedef struct _disp_t { * After it you can set the fields. * @param driver pointer to driver variable to initialize */ -void lv_disp_drv_init(lv_disp_drv_t *driver); - -/** - * Register an initialized display driver. - * Automatically set the first display as active. - * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) - * @return pointer to the new display or NULL on error - */ -lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); +void lv_disp_drv_init(lv_disp_drv_t * driver); /** @@ -131,12 +138,46 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); */ void lv_disp_buf_init(lv_disp_buf_t * disp_buf, void * buf1, void * buf2, uint32_t size); +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver); +/** + * Set a default screen. The new screens will be created on it by default. + * @param disp pointer to a display + */ void lv_disp_set_default(lv_disp_t * disp); +/** + * Get the default display + * @return pointer to the default display + */ lv_disp_t * lv_disp_get_default(void); -lv_disp_buf_t * lv_disp_get_vdb(lv_disp_t * disp); +/** + * Get the horizontal resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the horizontal resolution of the display + */ +lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp); + +/** + * Get the vertical resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the vertical resolution of the display + */ +lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp); + +/** + * Call in the display driver's `flush` function when the flushing is finished + */ +LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_t * disp); + + /** * Get the next display. * @param disp pointer to the current display. NULL to initialize. @@ -144,13 +185,39 @@ lv_disp_buf_t * lv_disp_get_vdb(lv_disp_t * disp); */ lv_disp_t * lv_disp_get_next(lv_disp_t * disp); +/** + * Get the internal buffer of a display + * @param disp pointer to a display + * @return pointer to the internal buffers + */ +lv_disp_buf_t * lv_disp_get_buf(lv_disp_t * disp); -lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp); -lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp); +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_disp_get_inv_buf_size(lv_disp_t * disp); -bool lv_disp_is_double_vdb(lv_disp_t * disp); +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_disp_pop_from_inv_buf(lv_disp_t * disp, uint16_t num); + +/** + * Check the driver configuration if it's double buffered (both `buf1` and `buf2` are set) + * @param disp pointer to to display to check + * @return true: double buffered; false: not double buffered + */ +bool lv_disp_is_double_buf(lv_disp_t * disp); + +/** + * Check the driver configuration if it's TRUE double buffered (both `buf1` and `buf2` are set and `size` is screen sized) + * @param disp pointer to to display to check + * @return true: double buffered; false: not double buffered + */ +bool lv_disp_is_true_double_buf(lv_disp_t * disp); -bool lv_disp_is_true_double_buffered(lv_disp_t * disp); /********************** * MACROS **********************/ diff --git a/lv_hal/lv_hal_indev.c b/lv_hal/lv_hal_indev.c index 6adb4be96..2604bc08c 100644 --- a/lv_hal/lv_hal_indev.c +++ b/lv_hal/lv_hal_indev.c @@ -50,10 +50,9 @@ */ void lv_indev_drv_init(lv_indev_drv_t * driver) { - driver->read = NULL; + memset(driver, 0, sizeof(lv_indev_drv_t)); + driver->type = LV_INDEV_TYPE_NONE; - driver->disp = NULL; - driver->user_data = NULL; } /** @@ -110,13 +109,11 @@ bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data) bool cont = false; memset(data, 0, sizeof(lv_indev_data_t)); - data->state = LV_INDEV_STATE_REL; - if(indev->driver.read) { - data->user_data = indev->driver.user_data; + if(indev->driver.read_cb) { LV_LOG_TRACE("idnev read started"); - cont = indev->driver.read(data); + cont = indev->driver.read_cb(indev, data); LV_LOG_TRACE("idnev read finished"); } else { LV_LOG_WARN("indev function registered"); diff --git a/lv_hal/lv_hal_indev.h b/lv_hal/lv_hal_indev.h index 2186e2dab..a9208d997 100644 --- a/lv_hal/lv_hal_indev.h +++ b/lv_hal/lv_hal_indev.h @@ -15,6 +15,12 @@ extern "C" { /********************* * INCLUDES *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../lv_conf.h" +#endif + #include #include #include "../lv_misc/lv_area.h" @@ -28,6 +34,7 @@ extern "C" { **********************/ struct _disp_t; +struct _lv_indev_t; /*Possible input device types*/ enum { @@ -48,22 +55,23 @@ typedef uint8_t lv_indev_state_t; /*Data type when an input device is read */ typedef struct { - void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ union { - lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ - uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ - uint32_t btn; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ - int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + lv_point_t point; /*For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn_id; /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ }; + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ + } lv_indev_data_t; /*Initialized by the user and registered by 'lv_indev_add()'*/ typedef struct { - lv_hal_indev_type_t type; /*Input device type*/ - bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/ + lv_hal_indev_type_t type; /*Input device type*/ + bool (*read_cb)(struct _lv_indev_t * indev, lv_indev_data_t *data); /*Function pointer to read_cb data. Return 'true' if there is still data to be read_cb (buffered)*/ + lv_indev_user_data_t read_user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ struct _disp_t * disp; - void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ } lv_indev_drv_t; struct _lv_obj_t; @@ -100,8 +108,6 @@ typedef struct _lv_indev_proc_t { uint8_t disabled :1; } lv_indev_proc_t; -struct _lv_indev_t; - typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, uint8_t); struct _lv_obj_t; diff --git a/lv_objx/lv_win.c b/lv_objx/lv_win.c index 49fb3eb1c..bbeee6736 100644 --- a/lv_objx/lv_win.c +++ b/lv_objx/lv_win.c @@ -10,6 +10,7 @@ #if USE_LV_WIN != 0 #include "../lv_themes/lv_theme.h" +#include "../lv_core/lv_disp.h" /********************* * DEFINES @@ -70,7 +71,7 @@ lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy) /*Init the new window object*/ if(copy == NULL) { - lv_obj_t * disp = lv_obj_get_disp(new_win); + lv_disp_t * disp = lv_obj_get_disp(new_win); lv_coord_t hres = lv_disp_get_hor_res(disp); lv_coord_t vres = lv_disp_get_ver_res(disp); lv_obj_set_size(new_win, hres, vres); diff --git a/lv_porting/lv_port_disp_templ.c b/lv_porting/lv_port_disp_templ.c index 18e676372..c2d819027 100644 --- a/lv_porting/lv_port_disp_templ.c +++ b/lv_porting/lv_port_disp_templ.c @@ -24,9 +24,7 @@ **********************/ static void disp_init(void); -static void disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -static void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -static void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +static void disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p); #if USE_LV_GPU static void mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); static void mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color); @@ -51,6 +49,41 @@ void lv_port_disp_init(void) * -----------------------*/ disp_init(); + /*----------------------------- + * Create a buffer for drawing + *----------------------------*/ + + /* LittlevGL requires a buffer where it draw the objects. The buffer's has to be greater than 1 display row + * + * There are three buffering configurations: + * 1. Create ONE buffer some rows: LittlevGL will draw the display's content here and writes it to your display + * 2. Create TWO buffer some rows: LittlevGL will draw the display's content to a buffer and writes it your display. + * You should use DMA to write the buffer's content to the display. + * It will enable LittlevGL to draw the next part of the screen to the other buffer while + * the data is being sent form the first buffer. It makes rendering and flushing parallel. + * 3. Create TWO screen buffer: Similar to 2) but the buffer have to be screen sized. When LittlevGL is ready it will give the + * whole frame to display. This way you only need to change the frame buffer's address instead of + * copying the pixels. + * */ + + /* Example for 1) */ + static lv_disp_buf_t disp_buf_1; + static lv_color_t buf1_1[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/ + lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/ + + /* Example for 2) */ + static lv_disp_buf_t disp_buf_2; + static lv_color_t buf2_1[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/ + static lv_color_t buf2_2[LV_HOR_RES_MAX * 10]; /*An other buffer for 10 rows*/ + lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/ + + /* Example for 3) */ + static lv_disp_buf_t disp_buf_3; + static lv_color_t buf3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX]; /*A screen sized buffer*/ + static lv_color_t buf3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX]; /*An other screen sized buffer*/ + lv_disp_buf_init(&disp_buf_3, buf3_1, buf3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX); /*Initialize the display buffer*/ + + /*----------------------------------- * Register the display in LittlevGL *----------------------------------*/ @@ -60,14 +93,8 @@ void lv_port_disp_init(void) /*Set up the functions to access to your display*/ - /*Used in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/ - disp_drv.disp_flush = disp_flush; - - /*Used in unbuffered mode (LV_VDB_SIZE == 0 in lv_conf.h)*/ - disp_drv.disp_fill = disp_fill; - - /*Used in unbuffered mode (LV_VDB_SIZE == 0 in lv_conf.h)*/ - disp_drv.disp_map = disp_map; + /*Used to copy the buffer's content to the display*/ + disp_drv.flush_cb = disp_flush; #if USE_LV_GPU /*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/ @@ -95,16 +122,15 @@ static void disp_init(void) /* Flush the content of the internal buffer the specific area on the display * You can use DMA or any hardware acceleration to do this operation in the background but - * 'lv_flush_ready()' has to be called when finished - * This function is required only when LV_VDB_SIZE != 0 in lv_conf.h*/ -static void disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) + * 'lv_disp_flush_ready()' has to be called when finished. */ +static void disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p) { /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ int32_t x; int32_t y; - for(y = y1; y <= y2; y++) { - for(x = x1; x <= x2; x++) { + for(y = area->y1; y <= area->y2; y++) { + for(x = area->x1; x <= area->x2; x++) { /* Put a pixel to the display. For example: */ /* put_px(x, y, *color_p)*/ color_p++; @@ -113,46 +139,10 @@ static void disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_ /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ - lv_flush_ready(); + lv_disp_flush_ready(disp); } -/* Write a pixel array (called 'map') to the a specific area on the display - * This function is required only when LV_VDB_SIZE == 0 in lv_conf.h*/ -static void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) -{ - /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ - - int32_t x; - int32_t y; - for(y = y1; y <= y2; y++) { - for(x = x1; x <= x2; x++) { - /* Put a pixel to the display. For example: */ - /* put_px(x, y, *color_p)*/ - color_p++; - } - } -} - - -/* Write a pixel array (called 'map') to the a specific area on the display - * This function is required only when LV_VDB_SIZE == 0 in lv_conf.h*/ -static void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) -{ - /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ - - int32_t x; - int32_t y; - for(y = y1; y <= y2; y++) { - for(x = x1; x <= x2; x++) { - /* Put a pixel to the display. For example: */ - /* put_px(x, y, *color)*/ - } - } - - (void)color; /*Just to avid warnings*/ -} - /*OPTIONAL: GPU INTERFACE*/ #if USE_LV_GPU diff --git a/lv_porting/lv_port_indev_templ.c b/lv_porting/lv_port_indev_templ.c index 60089270e..c89eb0744 100644 --- a/lv_porting/lv_port_indev_templ.c +++ b/lv_porting/lv_port_indev_templ.c @@ -24,25 +24,25 @@ **********************/ static void touchpad_init(void); -static bool touchpad_read(lv_indev_data_t * data); +static bool touchpad_read(lv_indev_t * indev, lv_indev_data_t * data); static bool touchpad_is_pressed(void); static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y); static void mouse_init(void); -static bool mouse_read(lv_indev_data_t * data); +static bool mouse_read(lv_indev_t * indev, lv_indev_data_t * data); static bool mouse_is_pressed(void); static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y); static void keypad_init(void); -static bool keypad_read(lv_indev_data_t * data); +static bool keypad_read(lv_indev_t * indev, lv_indev_data_t * data); static uint32_t keypad_get_key(void); static void encoder_init(void); -static bool encoder_read(lv_indev_data_t * data); +static bool encoder_read(lv_indev_t * indev, lv_indev_data_t * data); static void encoder_handler(void); static void button_init(void); -static bool button_read(lv_indev_data_t * data); +static bool button_read(lv_indev_t * indev, lv_indev_data_t * data); static int8_t button_get_pressed_id(void); static bool button_is_pressed(uint8_t id); @@ -92,7 +92,7 @@ void lv_port_indev_init(void) /*Register a touchpad input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; - indev_drv.read = touchpad_read; + indev_drv.read_cb = touchpad_read; indev_touchpad = lv_indev_drv_register(&indev_drv); /*------------------ @@ -105,11 +105,11 @@ void lv_port_indev_init(void) /*Register a mouse input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; - indev_drv.read = mouse_read; + indev_drv.read_cb = mouse_read; indev_mouse = lv_indev_drv_register(&indev_drv); /*Set cursor. For simplicity set a HOME symbol now.*/ - lv_obj_t * mouse_cursor = lv_img_create(lv_scr_act(NULL), NULL); + lv_obj_t * mouse_cursor = lv_img_create(lv_disp_get_scr_act(NULL), NULL); lv_img_set_src(mouse_cursor, SYMBOL_HOME); lv_indev_set_cursor(indev_mouse, mouse_cursor); @@ -123,7 +123,7 @@ void lv_port_indev_init(void) /*Register a keypad input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_KEYPAD; - indev_drv.read = keypad_read; + indev_drv.read_cb = keypad_read; indev_keypad = lv_indev_drv_register(&indev_drv); /* Later you should create group(s) with `lv_group_t * group = lv_group_create()`, @@ -141,7 +141,7 @@ void lv_port_indev_init(void) /*Register a encoder input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_KEYPAD; - indev_drv.read = encoder_read; + indev_drv.read_cb = encoder_read; indev_encoder = lv_indev_drv_register(&indev_drv); /* Later you should create group(s) with `lv_group_t * group = lv_group_create()`, @@ -159,7 +159,7 @@ void lv_port_indev_init(void) /*Register a button input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_BUTTON; - indev_drv.read = button_read; + indev_drv.read_cb = button_read; indev_button = lv_indev_drv_register(&indev_drv); /*Assign buttons to points on the screen*/ @@ -187,7 +187,7 @@ static void touchpad_init(void) } /* Will be called by the library to read the touchpad */ -static bool touchpad_read(lv_indev_data_t * data) +static bool touchpad_read(lv_indev_t * indev, lv_indev_data_t * data) { static lv_coord_t last_x = 0; static lv_coord_t last_y = 0; @@ -237,7 +237,7 @@ static void mouse_init(void) } /* Will be called by the library to read the mouse */ -static bool mouse_read(lv_indev_data_t * data) +static bool mouse_read(lv_indev_t * indev, lv_indev_data_t * data) { /*Get the current x and y coordinates*/ mouse_get_xy(&data->point.x, &data->point.y); @@ -281,7 +281,7 @@ static void keypad_init(void) } /* Will be called by the library to read the mouse */ -static bool keypad_read(lv_indev_data_t * data) +static bool keypad_read(lv_indev_t * indev, lv_indev_data_t * data) { static uint32_t last_key = 0; @@ -342,7 +342,7 @@ static void encoder_init(void) } /* Will be called by the library to read the encoder */ -static bool encoder_read(lv_indev_data_t * data) +static bool encoder_read(lv_indev_t * indev, lv_indev_data_t * data) { data->enc_diff = encoder_diff; @@ -373,7 +373,7 @@ static void button_init(void) } /* Will be called by the library to read the button */ -static bool button_read(lv_indev_data_t * data) +static bool button_read(lv_indev_t * indev, lv_indev_data_t * data) { static uint8_t last_btn = 0; @@ -389,7 +389,7 @@ static bool button_read(lv_indev_data_t * data) } /*Save the last pressed button's ID*/ - data->btn = last_btn; + data->btn_id = last_btn; /*Return `false` because we are not buffering and no more data to read*/ return false; diff --git a/lv_version.h b/lv_version.h index 1e62e1e2b..b718be951 100644 --- a/lv_version.h +++ b/lv_version.h @@ -14,10 +14,10 @@ extern "C" { * INCLUDES *********************/ /*Current version of LittlevGL*/ -#define LVGL_VERSION_MAJOR 5 -#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_MAJOR 6 +#define LVGL_VERSION_MINOR 0 #define LVGL_VERSION_PATCH 0 -#define LVGL_VERSION_INFO "" +#define LVGL_VERSION_INFO "dev" /*********************