#include #include #include #define MODULE display_test_module #include #include #include #include #include #include #include LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); #define DISPLAY_TEST_LINE_PIXELS 320U #define COLOR_RED 0xF800U #define COLOR_GREEN 0x07E0U #define COLOR_BLUE 0x001FU #define COLOR_YELLOW 0xFFE0U BUILD_ASSERT(DT_HAS_CHOSEN(zephyr_display), "Missing zephyr,display chosen node"); BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_ALIAS(backlight), okay), "Missing backlight alias"); static const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); static const struct device *const backlight_dev = DEVICE_DT_GET(DT_PARENT(DT_ALIAS(backlight))); static const uint32_t backlight_idx = DT_NODE_CHILD_IDX(DT_ALIAS(backlight)); static uint16_t line_buf[DISPLAY_TEST_LINE_PIXELS]; static bool initialized; static bool running; static void fill_test_line(size_t width) { const uint16_t colors[] = { COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, }; size_t segment = MAX(width / ARRAY_SIZE(colors), 1U); for (size_t x = 0; x < width; x++) { size_t color_idx = MIN(x / segment, ARRAY_SIZE(colors) - 1U); line_buf[x] = colors[color_idx]; } } static int draw_test_pattern(void) { struct display_capabilities caps; struct display_buffer_descriptor desc; int err; display_get_capabilities(display_dev, &caps); LOG_INF("Display caps: %ux%u fmt:%u orient:%u info:0x%x", caps.x_resolution, caps.y_resolution, caps.current_pixel_format, caps.current_orientation, caps.screen_info); if (caps.x_resolution > ARRAY_SIZE(line_buf)) { LOG_ERR("Display width %u exceeds line buffer", caps.x_resolution); return -ENOMEM; } if (caps.current_pixel_format != PIXEL_FORMAT_RGB_565) { LOG_WRN("Unexpected pixel format %u", caps.current_pixel_format); } fill_test_line(caps.x_resolution); desc.width = caps.x_resolution; desc.height = 1U; desc.pitch = caps.x_resolution; desc.buf_size = caps.x_resolution * sizeof(line_buf[0]); for (uint16_t y = 0; y < caps.y_resolution; y++) { err = display_write(display_dev, 0U, y, &desc, line_buf); if (err) { LOG_ERR("display_write failed at line %u (%d)", y, err); return err; } } err = display_blanking_off(display_dev); if (err) { LOG_ERR("display_blanking_off failed (%d)", err); return err; } LOG_INF("Display test pattern rendered (%ux%u)", caps.x_resolution, caps.y_resolution); return 0; } static int module_init(void) { int err; LOG_INF("Display test init on %s", display_dev->name); if (!device_is_ready(display_dev)) { LOG_ERR("Display device %s not ready", display_dev->name); return -ENODEV; } if (!device_is_ready(backlight_dev)) { LOG_ERR("Backlight device %s not ready", backlight_dev->name); return -ENODEV; } err = led_off(backlight_dev, backlight_idx); if (err) { LOG_ERR("Backlight off failed (%d)", err); return err; } LOG_INF("Backlight device %s channel %u ready", backlight_dev->name, backlight_idx); return 0; } static int module_start(void) { int err; if (running) { return 0; } LOG_INF("Display test start"); err = led_on(backlight_dev, backlight_idx); if (err) { LOG_ERR("Backlight enable failed (%d)", err); return err; } LOG_INF("Backlight enabled"); k_sleep(K_MSEC(50)); err = draw_test_pattern(); if (err) { (void)led_off(backlight_dev, backlight_idx); return err; } running = true; return 0; } static void module_pause(void) { if (!running) { return; } LOG_INF("Display test pause"); (void)display_blanking_on(display_dev); (void)led_off(backlight_dev, backlight_idx); running = false; } static bool app_event_handler(const struct app_event_header *aeh) { if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); int err; if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { LOG_INF("main READY received"); if (!initialized) { err = module_init(); if (err) { module_set_state(MODULE_STATE_ERROR); return false; } initialized = true; } err = module_start(); if (err) { module_set_state(MODULE_STATE_ERROR); } else { module_set_state(MODULE_STATE_READY); } } return false; } if (is_power_down_event(aeh)) { if (initialized) { module_pause(); module_set_state(MODULE_STATE_STANDBY); } return false; } if (is_wake_up_event(aeh)) { if (initialized) { int err = module_start(); if (err) { module_set_state(MODULE_STATE_ERROR); } else { module_set_state(MODULE_STATE_READY); } } return false; } return false; } APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);