summaryrefslogtreecommitdiff
path: root/lib/lvgl/tests/unity/unity_support.c
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-06-12 17:54:40 +1000
committerjacqueline <me@jacqueline.id.au>2024-06-12 17:54:40 +1000
commit64bd9053a25297f7a442ca831c7da5b44bd33f84 (patch)
treea90c6cad25a12028302ab1a5334510fba0229bae /lib/lvgl/tests/unity/unity_support.c
parent611176ed667c4ed7ee9f609e958f9404f4aee91d (diff)
downloadtangara-fw-64bd9053a25297f7a442ca831c7da5b44bd33f84.tar.gz
Update LVGL to v9.1.0
Diffstat (limited to 'lib/lvgl/tests/unity/unity_support.c')
-rw-r--r--lib/lvgl/tests/unity/unity_support.c467
1 files changed, 342 insertions, 125 deletions
diff --git a/lib/lvgl/tests/unity/unity_support.c b/lib/lvgl/tests/unity/unity_support.c
index 6906bd22..e5e4c3a2 100644
--- a/lib/lvgl/tests/unity/unity_support.c
+++ b/lib/lvgl/tests/unity/unity_support.c
@@ -1,24 +1,24 @@
/**
- * @file lv_test_assert.c
- *
- * Copyright 2002-2010 Guillaume Cottenceau.
- *
- * This software may be freely redistributed under the terms
- * of the X11 license.
- *
- */
+* @file lv_test_assert.c
+*
+* Copyright 2002-2010 Guillaume Cottenceau.
+*
+* This software may be freely redistributed under the terms
+* of the X11 license.
+*
+*/
/*********************
* INCLUDES
*********************/
#if LV_BUILD_TEST
#include "../lvgl.h"
-
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <sys/stat.h>
#include "unity.h"
#define PNG_DEBUG 3
#include <png.h>
@@ -28,6 +28,8 @@
*********************/
//#define REF_IMGS_PATH "lvgl/tests/lv_test_ref_imgs/"
#define REF_IMGS_PATH "ref_imgs/"
+#define ERR_FILE_NOT_FOUND -1
+#define ERR_PNG -2
/**********************
* TYPEDEFS
@@ -41,13 +43,17 @@ typedef struct {
png_infop info_ptr;
int number_of_passes;
png_bytep * row_pointers;
-}png_img_t;
+} png_image_t;
/**********************
* STATIC PROTOTYPES
**********************/
-static int read_png_file(png_img_t * p, const char* file_name);
-static void png_release(png_img_t * p);
+static bool screenhot_compare(const char * fn_ref, const char * mode, uint8_t tolerance);
+static int read_png_file(png_image_t * p, const char * file_name);
+static int write_png_file(void * raw_img, uint32_t width, uint32_t height, char * file_name);
+static void png_release(png_image_t * p);
+static void buf_to_xrgb8888(const uint8_t * buf_in, uint8_t * buf_out, lv_color_format_t cf_in);
+static void create_folders_if_needed(const char * path) ;
/**********************
* STATIC VARIABLES
@@ -61,137 +67,179 @@ static void png_release(png_img_t * p);
* GLOBAL FUNCTIONS
**********************/
-bool lv_test_assert_img_eq(const char * fn_ref)
+bool lv_test_assert_image_eq(const char * fn_ref)
{
- char fn_ref_full[512];
- sprintf(fn_ref_full, "%s%s", REF_IMGS_PATH, fn_ref);
-
- png_img_t p;
- int res = read_png_file(&p, fn_ref_full);
- if(res < 0) return false;
- uint8_t * screen_buf;
-
- lv_obj_invalidate(lv_scr_act());
- lv_refr_now(NULL);
-
- extern lv_color_t test_fb[];
-
- screen_buf = (uint8_t *)test_fb;
-
- uint8_t * ptr_act = NULL;
- const png_byte* ptr_ref = NULL;
-
- bool err = false;
- int x, y, i_buf = 0;
- for (y = 0; y < p.height; y++) {
- png_byte* row = p.row_pointers[y];
-
- for (x = 0; x < p.width; x++) {
- ptr_ref = &(row[x*3]);
- ptr_act = &(screen_buf[i_buf*4]);
-
- uint32_t ref_px = 0;
- uint32_t act_px = 0;
- memcpy(&ref_px, ptr_ref, 3);
- memcpy(&act_px, ptr_act, 3);
- //printf("0xFF%06x, ", act_px);
-
- uint8_t act_swap[3] = {ptr_act[2], ptr_act[1], ptr_act[0]};
-
- if(memcmp(act_swap, ptr_ref, 3) != 0) {
- err = true;
- break;
- }
- i_buf++;
- }
- if(err) break;
- }
-
- if(err) {
- uint32_t ref_px = 0;
- uint32_t act_px = 0;
- memcpy(&ref_px, ptr_ref, 3);
- memcpy(&act_px, ptr_act, 3);
-
- FILE * f = fopen("../test_screenshot_error.h", "w");
-
- fprintf(f, "//Diff in %s at (%d;%d), %x instead of %x)\n\n", fn_ref, x, y, act_px, ref_px);
- fprintf(f, "static const uint32_t test_screenshot_error_data[] = {\n");
-
- i_buf = 0;
- for (y = 0; y < 480; y++) {
- fprintf(f, "\n");
- for (x = 0; x < 800; x++) {
- ptr_act = &(screen_buf[i_buf * 4]);
- act_px = 0;
- memcpy(&act_px, ptr_act, 3);
- fprintf(f, "0xFF%06X, ", act_px);
- i_buf++;
- }
- }
- fprintf(f, "};\n\n");
+ bool pass;
+
+ lv_obj_t * scr = lv_screen_active();
+ lv_obj_invalidate(scr);
+
+ pass = screenhot_compare(fn_ref, "full refresh", 0);
+ if(!pass) return false;
+
+ //Software has minor rounding errors when not the whole image is updated
+ //so ignore stripe invalidation for now
+ // uint32_t i;
+ // for(i = 0; i < 800; i += 50 ) {
+ // lv_area_t a;
+ // a.y1 = 0;
+ // a.y2 = 479;
+ // a.x1 = i;
+ // a.x2 = i + 12;
+ // lv_obj_invalidate_area(scr, &a);
+ //
+ // a.x1 = i + 25;
+ // a.x2 = i + 32;
+ // lv_obj_invalidate_area(scr, &a);
+ // }
+ //
+ // pass = screenhot_compare(fn_ref, "vertical stripes", 32);
+ // if(!pass) return false;
+ //
+ //
+ // for(i = 0; i < 480; i += 40) {
+ // lv_area_t a;
+ // a.x1 = 0;
+ // a.x2 = 799;
+ // a.y1 = i;
+ // a.y2 = i + 9;
+ // lv_obj_invalidate_area(scr, &a);
+ //
+ // a.y1 = i + 25;
+ // a.y2 = i + 32;
+ // lv_obj_invalidate_area(scr, &a);
+ // }
+ //
+ // pass = screenhot_compare(fn_ref, "horizontal stripes", 32);
+ // if(!pass) return false;
+
+ return true;
+}
- fprintf(f, "static lv_img_dsc_t test_screenshot_error_dsc = { \n"
- " .header.w = 800,\n"
- " .header.h = 480,\n"
- " .header.always_zero = 0,\n"
- " .header.cf = LV_IMG_CF_TRUE_COLOR,\n"
- " .data_size = 800 * 480 * 4,\n"
- " .data = test_screenshot_error_data};\n\n"
- "static inline void test_screenshot_error_show(void)\n"
- "{\n"
- " lv_obj_t * img = lv_img_create(lv_scr_act());\n"
- " lv_img_set_src(img, &test_screenshot_error_dsc);\n"
- "}\n");
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
- fclose(f);
+static uint8_t screen_buf_xrgb8888[800 * 480 * 4];
+/**
+ * Compare the content of the frame buffer with a reference image
+ * @param fn_ref reference image name
+ * @param mode arbitrary string to tell more about the compare
+ * @return true: test passed; false: test failed
+ */
+static bool screenhot_compare(const char * fn_ref, const char * mode, uint8_t tolerance)
+{
- }
+ char fn_ref_full[256];
+ lv_snprintf(fn_ref_full, sizeof(fn_ref_full), "%s%s", REF_IMGS_PATH, fn_ref);
+ create_folders_if_needed(fn_ref_full);
- png_release(&p);
+ lv_refr_now(NULL);
- return !err;
+ extern uint8_t * last_flushed_buf;
-}
+ lv_color_format_t cf = lv_display_get_color_format(NULL);
+ uint8_t * screen_buf = lv_draw_buf_align(last_flushed_buf, cf);
+ buf_to_xrgb8888(screen_buf, screen_buf_xrgb8888, cf);
-/**********************
- * STATIC FUNCTIONS
- **********************/
+ png_image_t p;
+ int res = read_png_file(&p, fn_ref_full);
+ if(res == ERR_FILE_NOT_FOUND) {
+ TEST_PRINTF("%s%s", fn_ref_full, " was not found, creating is now from the rendered screen");
+ fflush(stderr);
+ write_png_file(screen_buf_xrgb8888, 800, 480, fn_ref_full);
+ return true;
+ }
+ else if(res == ERR_PNG) {
+ return false;
+ }
+
+ uint8_t * ptr_act = NULL;
+ const png_byte * ptr_ref = NULL;
+
+ bool err = false;
+ int x, y;
+ for(y = 0; y < p.height; y++) {
+ uint8_t * screen_buf_tmp = screen_buf_xrgb8888 + 800 * 4 * y;
+ png_byte * row = p.row_pointers[y];
+ for(x = 0; x < p.width; x++) {
+ ptr_ref = &(row[x * 3]);
+ ptr_act = screen_buf_tmp;
+
+ if(LV_ABS((int32_t) ptr_act[0] - ptr_ref[0]) > tolerance ||
+ LV_ABS((int32_t) ptr_act[1] - ptr_ref[1]) > tolerance ||
+ LV_ABS((int32_t) ptr_act[2] - ptr_ref[2]) > tolerance) {
+ uint32_t act_px = (ptr_act[2] << 16) + (ptr_act[1] << 8) + (ptr_act[0] << 0);
+ uint32_t ref_px = 0;
+ memcpy(&ref_px, ptr_ref, 3);
+ TEST_PRINTF("\nScreenshot compare error\n"
+ " - File: %s\n"
+ " - Mode: %s\n"
+ " - At x:%d, y:%d.\n"
+ " - Expected: %X\n"
+ " - Actual: %X",
+ fn_ref_full, mode, x, y, ref_px, act_px);
+ fflush(stderr);
+ err = true;
+ break;
+ }
+ screen_buf_tmp += 4;
+ }
+ if(err) break;
+ }
+
+ if(err) {
+ char fn_ref_no_ext[128];
+ strcpy(fn_ref_no_ext, fn_ref);
+ fn_ref_no_ext[strlen(fn_ref_no_ext) - 4] = '\0';
+
+ char fn_err_full[256];
+ lv_snprintf(fn_err_full, sizeof(fn_err_full), "%s%s_err.png", REF_IMGS_PATH, fn_ref_no_ext);
+
+ write_png_file(screen_buf_xrgb8888, 800, 480, fn_err_full);
+ }
+
+ png_release(&p);
+
+ fflush(stdout);
+ return !err;
-static int read_png_file(png_img_t * p, const char* file_name)
+}
+
+static int read_png_file(png_image_t * p, const char * file_name)
{
char header[8]; // 8 is the maximum size that can be checked
/*open file and test for it being a png*/
- FILE *fp = fopen(file_name, "rb");
- if (!fp) {
- TEST_PRINTF("%s", "PNG file %s could not be opened for reading");
- return -1;
+ FILE * fp = fopen(file_name, "rb");
+ if(!fp) {
+ TEST_PRINTF("[read_png_file %s] could not be opened for reading", file_name);
+ return ERR_FILE_NOT_FOUND;
}
size_t rcnt = fread(header, 1, 8, fp);
- if (rcnt != 8 || png_sig_cmp((png_const_bytep)header, 0, 8)) {
- TEST_PRINTF("%s is not recognized as a PNG file", file_name);
- return -1;
+ if(rcnt != 8 || png_sig_cmp((png_const_bytep)header, 0, 8)) {
+ TEST_PRINTF("[read_png_file %s] not recognized as a PNG file", file_name);
+ return ERR_PNG;
}
/*initialize stuff*/
p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!p->png_ptr) {
- TEST_PRINTF("%s", "png_create_read_struct failed");
- return -1;
+ if(!p->png_ptr) {
+ TEST_PRINTF("[read_png_file %s] png_create_read_struct failed", file_name);
+ return ERR_PNG;
}
p->info_ptr = png_create_info_struct(p->png_ptr);
- if (!p->info_ptr) {
- TEST_PRINTF("%s", "png_create_info_struct failed");
- return -1;
+ if(!p->info_ptr) {
+ TEST_PRINTF("[read_png_file %s] png_create_info_struct failed", file_name);
+ return ERR_PNG;
}
- if (setjmp(png_jmpbuf(p->png_ptr))) {
- TEST_PRINTF("%s", "Error during init_io");
- return -1;
+ if(setjmp(png_jmpbuf(p->png_ptr))) {
+ TEST_PRINTF("[read_png_file %s] Error during init_io", file_name);
+ return ERR_PNG;
}
png_init_io(p->png_ptr, fp);
png_set_sig_bytes(p->png_ptr, 8);
@@ -207,15 +255,15 @@ static int read_png_file(png_img_t * p, const char* file_name)
png_read_update_info(p->png_ptr, p->info_ptr);
/*read file*/
- if (setjmp(png_jmpbuf(p->png_ptr))) {
- TEST_PRINTF("%s", "Error during read_image");
- return -1;
+ if(setjmp(png_jmpbuf(p->png_ptr))) {
+ TEST_PRINTF("[read_png_file %s] Error during read_image", file_name);
+ return ERR_PNG;
}
- p->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * p->height);
+ p->row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * p->height);
int y;
- for (y=0; y<p->height; y++)
- p->row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(p->png_ptr,p->info_ptr));
+ for(y = 0; y < p->height; y++)
+ p->row_pointers[y] = (png_byte *) malloc(png_get_rowbytes(p->png_ptr, p->info_ptr));
png_read_image(p->png_ptr, p->row_pointers);
@@ -223,15 +271,184 @@ static int read_png_file(png_img_t * p, const char* file_name)
return 0;
}
-static void png_release(png_img_t * p)
+static int write_png_file(void * raw_img, uint32_t width, uint32_t height, char * file_name)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ /* create file */
+ FILE * fp = fopen(file_name, "wb");
+ if(!fp) {
+ printf("###### %s\n", file_name);
+ fflush(stdout);
+ TEST_PRINTF("[write_png_file %s] could not be opened for writing", file_name);
+ TEST_PRINTF("%s", file_name);
+ return -1;
+ }
+
+ /* initialize stuff */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+ if(!png_ptr) {
+ TEST_PRINTF("[write_png_file %s] png_create_write_struct failed", file_name);
+ return -1;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if(!info_ptr) {
+ TEST_PRINTF("[write_png_file %s] png_create_info_struct failed", file_name);
+ return -1;
+ }
+
+ if(setjmp(png_jmpbuf(png_ptr))) {
+ TEST_PRINTF("[write_png_file %s] Error during init_io", file_name);
+ return -1;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ /* write header */
+ if(setjmp(png_jmpbuf(png_ptr))) {
+ TEST_PRINTF("[write_png_file %s] Error during writing header", file_name);
+ return -1;
+ }
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_write_info(png_ptr, info_ptr);
+
+ /* write bytes */
+ if(setjmp(png_jmpbuf(png_ptr))) {
+ TEST_PRINTF("[write_png_file %s] Error during writing bytes", file_name);
+ return -1;
+ }
+
+ uint8_t * raw_img8 = (uint8_t *)raw_img;
+ png_bytep * row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * height);
+ for(uint32_t y = 0; y < height; y++) {
+ row_pointers[y] = malloc(3 * width);
+ uint8_t * line = raw_img8 + y * width * 4;
+ for(uint32_t x = 0; x < width; x++) {
+ row_pointers[y][x * 3 + 0] = line[x * 4 + 0];
+ row_pointers[y][x * 3 + 1] = line[x * 4 + 1];
+ row_pointers[y][x * 3 + 2] = line[x * 4 + 2];
+ }
+ }
+ png_write_image(png_ptr, row_pointers);
+
+ /* end write */
+ if(setjmp(png_jmpbuf(png_ptr))) {
+ TEST_PRINTF("[write_png_file %s] Error during end of write", file_name);
+ return -1;
+ }
+ png_write_end(png_ptr, NULL);
+
+ /* cleanup heap allocation */
+ for(uint32_t y = 0; y < height; y++) free(row_pointers[y]);
+ free(row_pointers);
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ fclose(fp);
+ return 0;
+}
+
+static void png_release(png_image_t * p)
{
int y;
- for (y=0; y<p->height; y++) free(p->row_pointers[y]);
+ for(y = 0; y < p->height; y++) free(p->row_pointers[y]);
free(p->row_pointers);
png_destroy_read_struct(&p->png_ptr, &p->info_ptr, NULL);
}
+static void buf_to_xrgb8888(const uint8_t * buf_in, uint8_t * buf_out, lv_color_format_t cf_in)
+{
+ uint32_t stride = lv_draw_buf_width_to_stride(800, cf_in);
+ if(cf_in == LV_COLOR_FORMAT_RGB565) {
+ uint32_t y;
+ for(y = 0; y < 480; y++) {
+
+ uint32_t x;
+ for(x = 0; x < 800; x++) {
+ const lv_color16_t * c16 = (const lv_color16_t *)&buf_in[x * 2];
+
+ buf_out[x * 4 + 3] = 0xff;
+ buf_out[x * 4 + 2] = (c16->blue * 2106) >> 8; /*To make it rounded*/
+ buf_out[x * 4 + 1] = (c16->green * 1037) >> 8;
+ buf_out[x * 4 + 0] = (c16->red * 2106) >> 8;
+ }
+
+ buf_in += stride;
+ buf_out += 800 * 4;
+ }
+ }
+ else if(cf_in == LV_COLOR_FORMAT_ARGB8888 || cf_in == LV_COLOR_FORMAT_XRGB8888) {
+ uint32_t y;
+ for(y = 0; y < 480; y++) {
+ uint32_t x;
+ for(x = 0; x < 800; x++) {
+ buf_out[x * 4 + 3] = buf_in[x * 4 + 3];
+ buf_out[x * 4 + 2] = buf_in[x * 4 + 0];
+ buf_out[x * 4 + 1] = buf_in[x * 4 + 1];
+ buf_out[x * 4 + 0] = buf_in[x * 4 + 2];
+ }
+
+ buf_in += stride;
+ buf_out += 800 * 4;
+ }
+ }
+ else if(cf_in == LV_COLOR_FORMAT_RGB888) {
+ uint32_t y;
+ for(y = 0; y < 480; y++) {
+ uint32_t x;
+ for(x = 0; x < 800; x++) {
+ buf_out[x * 4 + 3] = 0xff;
+ buf_out[x * 4 + 2] = buf_in[x * 3 + 0];
+ buf_out[x * 4 + 1] = buf_in[x * 3 + 1];
+ buf_out[x * 4 + 0] = buf_in[x * 3 + 2];
+ }
+
+ buf_in += stride;
+ buf_out += 800 * 4;
+ }
+ }
+}
+
+static void create_folders_if_needed(const char * path)
+{
+ char * ptr;
+ char * pathCopy = strdup(path);
+ if(pathCopy == NULL) {
+ perror("Error duplicating path");
+ exit(EXIT_FAILURE);
+ }
+
+ char * token = strtok_r(pathCopy, "/", &ptr);
+ char current_path[1024] = {'\0'}; // Adjust the size as needed
+ struct stat st;
+
+ while(token && ptr && *ptr != '\0') {
+ strcat(current_path, token);
+ strcat(current_path, "/");
+
+ if(stat(current_path, &st) != 0) {
+ // Folder doesn't exist, create it
+ if(mkdir(current_path, 0777) != 0) {
+ perror("Error creating folder");
+ free(pathCopy);
+ exit(EXIT_FAILURE);
+ }
+ printf("Created folder: %s\n", current_path);
+ }
+
+ token = strtok_r(NULL, "/", &ptr);
+ }
+
+ free(pathCopy);
+}
#endif