| /* |
| * Copyright 2024 (c) TOKITA Hiroshi |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/drivers/display.h> |
| #include <zephyr/ztest.h> |
| #include <zephyr/device.h> |
| #include <zephyr/logging/log.h> |
| |
| LOG_MODULE_DECLARE(display_api, CONFIG_DISPLAY_LOG_LEVEL); |
| |
| static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); |
| static const uint32_t display_width = DT_PROP(DT_CHOSEN(zephyr_display), width); |
| static const uint32_t display_height = DT_PROP(DT_CHOSEN(zephyr_display), height); |
| static uint8_t disp_buffer[DT_PROP(DT_CHOSEN(zephyr_display), width) * |
| DT_PROP(DT_CHOSEN(zephyr_display), height) * 4]; |
| static struct display_capabilities cfg; |
| static uint8_t bpp; |
| static bool is_tiled; |
| |
| static inline uint8_t bytes_per_pixel(enum display_pixel_format pixel_format) |
| { |
| switch (pixel_format) { |
| case PIXEL_FORMAT_ARGB_8888: |
| return 4; |
| case PIXEL_FORMAT_RGB_888: |
| return 3; |
| case PIXEL_FORMAT_RGB_565: |
| case PIXEL_FORMAT_BGR_565: |
| return 2; |
| case PIXEL_FORMAT_MONO01: |
| case PIXEL_FORMAT_MONO10: |
| default: |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static void verify_bytes_of_area(uint8_t *data, int cmp_x, int cmp_y, size_t width, size_t height) |
| { |
| struct display_buffer_descriptor desc = { |
| .height = height, |
| .pitch = width, |
| .width = width, |
| .buf_size = height * width * bpp, |
| }; |
| |
| int err = display_read(dev, cmp_x, cmp_y, &desc, disp_buffer); |
| |
| zassert_ok(err, "display_read failed"); |
| |
| if (is_tiled) { |
| zassert_mem_equal(data, disp_buffer, width * height / 8, NULL); |
| } else { |
| zassert_mem_equal(data, disp_buffer, width * height * bpp, NULL); |
| } |
| } |
| |
| static void verify_background_color(int x, int y, size_t width, size_t height, uint32_t color) |
| { |
| size_t buf_size = is_tiled ? (height * width / 8) : (height * width * bpp); |
| struct display_buffer_descriptor desc = { |
| .height = height, |
| .pitch = width, |
| .width = width, |
| .buf_size = buf_size, |
| }; |
| uint32_t *buf32 = (void *)disp_buffer; |
| uint16_t *buf16 = (void *)disp_buffer; |
| uint8_t *buf8 = disp_buffer; |
| int err; |
| |
| err = display_read(dev, x, y, &desc, disp_buffer); |
| zassert_ok(err, "display_read failed"); |
| |
| for (size_t i = 0; i < width * height; i++) { |
| switch (bpp) { |
| case 4: |
| zassert_equal(buf32[i], color, "@%d", i); |
| break; |
| case 2: |
| zassert_equal(buf16[i], (uint16_t)color, "@%d", i); |
| break; |
| case 1: |
| if (is_tiled) { |
| uint16_t x = i % (width); |
| uint16_t line = (i - x) / width; |
| uint16_t tile = line / 8; |
| uint16_t y = line % 8; |
| |
| uint8_t *tptr = disp_buffer + (tile * width + x); |
| |
| zassert_equal(!!(*tptr & BIT(y)), !!(color), "@%d", i); |
| } else { |
| zassert_equal(buf8[i], (uint8_t)color, "@%d", i); |
| } |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Fill the buffer with 0 before running tests. |
| */ |
| static void display_before(void *text_fixture) |
| { |
| display_get_capabilities(dev, &cfg); |
| bpp = bytes_per_pixel(cfg.current_pixel_format); |
| is_tiled = ((bpp == 1) && (cfg.screen_info & SCREEN_INFO_MONO_VTILED)); |
| |
| struct display_buffer_descriptor desc = { |
| .height = display_height, |
| .pitch = display_width, |
| .width = display_width, |
| .buf_size = display_height * display_width * bpp, |
| }; |
| |
| memset(disp_buffer, 0, sizeof(disp_buffer)); |
| display_write(dev, 0, 0, &desc, disp_buffer); |
| } |
| |
| /* |
| * Verify that we can get a color of '0' from all pixels |
| * when after zeroing the buffer. |
| */ |
| ZTEST(display_read_write, test_clear) |
| { |
| verify_background_color(0, 0, display_width, display_height, 0); |
| } |
| |
| /* |
| * Write to the head of the buffer and check that |
| * the same value can be read. |
| */ |
| ZTEST(display_read_write, test_write_to_buffer_head) |
| { |
| uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA}; |
| uint8_t height = (is_tiled ? 8 : 1); |
| uint16_t width = sizeof(data) / bpp; |
| uint16_t buf_size = width * bpp; |
| struct display_buffer_descriptor desc = { |
| .height = height, |
| .pitch = width, |
| .width = width, |
| .buf_size = buf_size, |
| }; |
| |
| /* write data to head of buffer */ |
| display_write(dev, 0, 0, &desc, data); |
| |
| /* check write data and read data are same */ |
| verify_bytes_of_area(data, 0, 0, width, height); |
| |
| /* check remaining region still black */ |
| verify_background_color(0, height, display_width, display_height - height, 0); |
| verify_background_color(width, 0, display_width - width, display_height, 0); |
| } |
| |
| /* |
| * Write to the tail of the buffer and check that |
| * the same value can be read. |
| */ |
| ZTEST(display_read_write, test_write_to_buffer_tail) |
| { |
| uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA}; |
| uint16_t height = (is_tiled ? 8 : 1); |
| uint16_t width = sizeof(data) / bpp; |
| uint16_t buf_size = width * bpp; |
| struct display_buffer_descriptor desc = { |
| .height = height, |
| .pitch = width, |
| .width = width, |
| .buf_size = buf_size, |
| }; |
| struct display_buffer_descriptor desc_whole = { |
| .height = display_height, |
| .pitch = display_width, |
| .width = display_width, |
| .buf_size = display_height * display_width * bpp / height, |
| }; |
| int err; |
| |
| /* write data to tail of buffer */ |
| display_write(dev, display_width - width, display_height - height, &desc, data); |
| |
| /* read entire displayed data */ |
| err = display_read(dev, 0, 0, &desc_whole, disp_buffer); |
| zassert_ok(err, "display_read failed"); |
| |
| /* check write data and read data are same */ |
| if (is_tiled) { |
| zassert_mem_equal(data, |
| disp_buffer + (display_width * display_height / 8 - buf_size), |
| buf_size, NULL); |
| } else { |
| zassert_mem_equal(data, |
| disp_buffer + (display_width * display_height * bpp - buf_size), |
| buf_size, NULL); |
| } |
| |
| /* check remaining region still black */ |
| verify_background_color(0, 0, display_width, display_height - height, 0); |
| verify_background_color(0, display_height - height, display_width - width, height, 0); |
| } |
| |
| /* |
| * Verify that it will keep the drawn content even if display_read is executed |
| */ |
| ZTEST(display_read_write, test_read_does_not_clear_existing_buffer) |
| { |
| uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA}; |
| uint8_t height = (is_tiled ? 8 : 1); |
| uint16_t width = sizeof(data) / bpp; |
| uint16_t buf_size = width * bpp; |
| struct display_buffer_descriptor desc = { |
| .height = height, |
| .pitch = width, |
| .width = width, |
| .buf_size = buf_size, |
| }; |
| struct display_buffer_descriptor desc_whole = { |
| .height = display_height, |
| .pitch = display_width, |
| .width = display_width, |
| .buf_size = display_height * display_width * bpp / height, |
| }; |
| int err; |
| |
| /* write data to head of buffer */ |
| display_write(dev, 0, 0, &desc, data); |
| |
| /* check write data and read data are same */ |
| verify_bytes_of_area(data, 0, 0, width, height); |
| |
| /* check remaining region still black */ |
| verify_background_color(0, height, display_width, display_height - height, 0); |
| verify_background_color(width, 0, display_width - width, display_height, 0); |
| |
| /* write data to tail of buffer */ |
| display_write(dev, display_width - width, display_height - height, &desc, data); |
| |
| /* read entire displayed data */ |
| err = display_read(dev, 0, 0, &desc_whole, disp_buffer); |
| zassert_ok(err, "display_read failed"); |
| |
| /* checking correctly write to the tail of buffer */ |
| if (is_tiled) { |
| zassert_mem_equal(data, |
| disp_buffer + (display_width * display_height / 8 - buf_size), |
| buf_size, NULL); |
| } else { |
| zassert_mem_equal(data, |
| disp_buffer + (display_width * display_height * bpp - buf_size), |
| buf_size, NULL); |
| } |
| |
| /* checking if the content written before reading is kept */ |
| verify_bytes_of_area(data, 0, 0, width, height); |
| |
| /* checking remaining region is still black */ |
| verify_background_color(width, 0, display_width - width, display_height - height, 0); |
| verify_background_color(0, height, display_width - width, display_height - height, 0); |
| } |
| |
| ZTEST_SUITE(display_read_write, NULL, NULL, display_before, NULL, NULL); |