diff --git a/testing/drivertest/Makefile b/testing/drivertest/Makefile index 3949cbc92..ca30bdc8b 100644 --- a/testing/drivertest/Makefile +++ b/testing/drivertest/Makefile @@ -109,4 +109,9 @@ MAINSRC += drivertest_framebuffer.c PROGNAME += cmocka_driver_framebuffer endif +ifneq ($(CONFIG_LCD_DEV),) +MAINSRC += drivertest_lcd.c +PROGNAME += cmocka_driver_lcd +endif + include $(APPDIR)/Application.mk diff --git a/testing/drivertest/drivertest_lcd.c b/testing/drivertest/drivertest_lcd.c new file mode 100644 index 000000000..494b9d80c --- /dev/null +++ b/testing/drivertest/drivertest_lcd.c @@ -0,0 +1,405 @@ +/**************************************************************************** + * apps/testing/drivertest/drivertest_lcd.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define LCD_DEFAULT_DEVPATH "/dev/lcd0" +#define LCD_TEST_CASE_NUM 4 + +#define COLOR_888_TO_565(color) (((((color) >> 19) & 0x1f) << 11) \ + |((((color) >> 10) & 0x3f) << 5) \ + |(((color) >> 3) & 0x1f)) + +#define OPTARG_TO_VALUE(value, type, base) \ + do \ + { \ + FAR char *ptr; \ + value = (type)strtoul(optarg, &ptr, base); \ + if (*ptr != '\0') \ + { \ + printf("Parameter error: -%c %s\n", ch, optarg); \ + lcd_help(argv[0], lcd_state, EXIT_FAILURE); \ + } \ + } while (0) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +struct lcd_info_s +{ + int fd; + struct lcd_planeinfo_s plane_info; + struct fb_videoinfo_s video_info; +}; + +struct lcd_state_s +{ + char devpath[PATH_MAX]; + int test_case_id; + struct lcd_info_s lcd_info; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lcd_help + ****************************************************************************/ + +static void lcd_help(FAR const char *progname, + FAR struct lcd_state_s *lcd_state, int exitcode) +{ + printf("Usage: %s" + " -p -t \n", + progname); + printf(" [-p devpath] selects the lcd device. " + "Default: %s Current: %s\n", LCD_DEFAULT_DEVPATH, + lcd_state->devpath); + printf(" [-t testcase] selects the testcase to show color on LCD.\n" + " Case 0: show black color on LCD\n" + " Case 1: show white color on LCD\n" + " Case 2: show black|red|green|blue|white rectangle on LCD\n" + " Case 3: show grayscale rectangle on LCD\n" + ); + + printf(" [-h] shows this message and exits\n"); + + exit(exitcode); +} + +/**************************************************************************** + * Name: parse_commandline + ****************************************************************************/ + +static void parse_commandline(FAR struct lcd_state_s *lcd_state, int argc, + FAR char **argv) +{ + int ch; + int converted; + + while ((ch = getopt(argc, argv, "p:d:n:f:t:h")) != ERROR) + { + switch (ch) + { + case 'p': + snprintf(lcd_state->devpath, sizeof(lcd_state->devpath), "%s", + optarg); + break; + case 't': + OPTARG_TO_VALUE(converted, uint8_t, 10); + if (converted < 0 || converted >= LCD_TEST_CASE_NUM) + { + printf("Testcase out of range: %d\n", converted); + lcd_help(argv[0], lcd_state, EXIT_FAILURE); + } + + lcd_state->test_case_id = converted; + break; + case 'h': + lcd_help(argv[0], lcd_state, EXIT_FAILURE); + break; + case '?': + printf("Unsupported option: %s\n", optarg); + lcd_help(argv[0], lcd_state, EXIT_FAILURE); + break; + } + } + + printf("devname = %s\n" + "testcase = %d\n", + lcd_state->devpath, + lcd_state->test_case_id); +} + +/**************************************************************************** + * Name: lcd_setup + ****************************************************************************/ + +static int lcd_setup(FAR void **state) +{ + FAR struct lcd_state_s * lcd_state; + int ret = 0; + + lcd_state = (struct lcd_state_s *)*state; + lcd_state->lcd_info.fd = open(lcd_state->devpath, 0); + assert_true(lcd_state->lcd_info.fd > 0); + + ret = ioctl(lcd_state->lcd_info.fd, LCDDEVIO_GETPLANEINFO, + &lcd_state->lcd_info.plane_info); + assert_int_equal(ret, 0); + + ret = ioctl(lcd_state->lcd_info.fd, LCDDEVIO_GETVIDEOINFO, + &lcd_state->lcd_info.video_info); + assert_int_equal(ret, 0); + + return 0; +} + +/**************************************************************************** + * Name: draw_rect + ****************************************************************************/ + +static void draw_rect(FAR struct lcd_info_s *lcd_info, int x, int y, + int w, int h, uint32_t color) +{ + int i = 0; + int j = 0; + int ret = 0; + int offset = 0; + int valid_w = w; + int valid_h = h; + uint32_t *fb_bpp32 = NULL; + uint16_t *fb_bpp16 = NULL; + const uint8_t bpp = lcd_info->plane_info.bpp; + const uint32_t xres = lcd_info->video_info.xres; + const uint32_t yres = lcd_info->video_info.yres; + struct lcddev_area_s draw_area; + + memset(&draw_area, 0, sizeof(draw_area)); + if (x + w > xres) + { + valid_w = xres - x; + } + + if (y + h > yres) + { + valid_h = yres - y; + } + + draw_area.row_start = x; + draw_area.col_start = y; + draw_area.row_end = x + valid_w - 1; + draw_area.col_end = y + valid_h - 1; + draw_area.data = malloc(valid_w * valid_h * (bpp >> 3)); + assert_ptr_not_equal(draw_area.data, NULL); + fb_bpp16 = draw_area.data; + fb_bpp32 = draw_area.data; + for (j = 0; j <= (draw_area.col_end - draw_area.col_start); j++) + { + offset = j * valid_w; + for (i = 0; i <= (draw_area.row_end - draw_area.row_start); i++) + { + if (bpp == 32) + { + *(fb_bpp32 + offset + i) = color; + } + else if (bpp == 16) + { + *(fb_bpp16 + offset + i) = COLOR_888_TO_565(color); + } + } + } + + ret = ioctl(lcd_info->fd, LCDDEVIO_PUTAREA, (unsigned long)&draw_area); + assert_int_equal(ret, 0); + free(draw_area.data); +} + +/**************************************************************************** + * Name: test_case_lcd_0 + ****************************************************************************/ + +static void test_case_lcd_0(FAR void **state) +{ + FAR struct lcd_state_s * lcd_state; + lcd_state = (struct lcd_state_s *)*state; + + const uint32_t xres = lcd_state->lcd_info.video_info.xres; + const uint32_t yres = lcd_state->lcd_info.video_info.yres; + + draw_rect(&lcd_state->lcd_info, 0, 0, xres, yres, 0xff000000); +} + +/**************************************************************************** + * Name: test_case_lcd_1 + ****************************************************************************/ + +static void test_case_lcd_1(FAR void **state) +{ + FAR struct lcd_state_s * lcd_state; + lcd_state = (struct lcd_state_s *)*state; + + const uint32_t xres = lcd_state->lcd_info.video_info.xres; + const uint32_t yres = lcd_state->lcd_info.video_info.yres; + + draw_rect(&lcd_state->lcd_info, 0, 0, xres, yres, 0xffffffff); +} + +/**************************************************************************** + * Name: test_case_lcd_2 + ****************************************************************************/ + +static void test_case_lcd_2(FAR void **state) +{ + FAR struct lcd_state_s * lcd_state = (struct lcd_state_s *)*state; + int i = 0; + int start_x = 0; + int step_width = 0; + int step_num = 0; + uint32_t colors_to_show[] = + { + 0x00000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ffffff + }; + + const uint32_t xres = lcd_state->lcd_info.video_info.xres; + const uint32_t yres = lcd_state->lcd_info.video_info.yres; + + step_num = sizeof(colors_to_show) / sizeof(uint32_t); + step_width = xres / step_num; + for (i = 0; i < step_num; i++) + { + start_x = step_width * i; + if (i == step_num - 1) + { + step_width = xres - start_x + 1; + } + + draw_rect(&lcd_state->lcd_info, start_x, 0, step_width, yres, + colors_to_show[i]); + } +} + +/**************************************************************************** + * Name: test_case_lcd_3 + ****************************************************************************/ + +static void test_case_lcd_3(FAR void **state) +{ + FAR struct lcd_state_s * lcd_state = (struct lcd_state_s *)*state; + int i = 0; + int start_y = 0; + int step_height = 0; + int step_num = 8; + uint32_t gray_color = 0; + + const uint32_t xres = lcd_state->lcd_info.video_info.xres; + const uint32_t yres = lcd_state->lcd_info.video_info.yres; + + step_height = xres / step_num; + for (i = 0; i < step_num; i++) + { + start_y = step_height * i; + if (i == step_num - 1) + { + step_height = yres - start_y + 1; + } + + gray_color = (0xff / step_num) * i; + draw_rect(&lcd_state->lcd_info, 0, start_y, xres, step_height, + gray_color << 16 | gray_color << 8 | gray_color); + } +} + +/**************************************************************************** + * Name: lcd_teardown + ****************************************************************************/ + +static int lcd_teardown(FAR void **state) +{ + FAR struct lcd_state_s * lcd_state; + + lcd_state = (struct lcd_state_s *)*state; + + close(lcd_state->lcd_info.fd); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + /* Initialize the state data */ + + struct lcd_state_s lcd_state; + char test_filter[64]; + + memset(&lcd_state, 0, sizeof(struct lcd_state_s)); + snprintf(lcd_state.devpath, sizeof(lcd_state.devpath), "%s", + LCD_DEFAULT_DEVPATH); + + parse_commandline(&lcd_state, argc, argv); + + const struct CMUnitTest tests[] = + { + cmocka_unit_test_prestate_setup_teardown(test_case_lcd_0, lcd_setup, + lcd_teardown, &lcd_state), + cmocka_unit_test_prestate_setup_teardown(test_case_lcd_1, lcd_setup, + lcd_teardown, &lcd_state), + cmocka_unit_test_prestate_setup_teardown(test_case_lcd_2, lcd_setup, + lcd_teardown, &lcd_state), + cmocka_unit_test_prestate_setup_teardown(test_case_lcd_3, lcd_setup, + lcd_teardown, &lcd_state), + }; + + snprintf(test_filter, sizeof(test_filter), "test_case_lcd_%d", + lcd_state.test_case_id); + cmocka_set_test_filter(test_filter); + + return cmocka_run_group_tests(tests, NULL, NULL); +}