/** * @file lv_nuttx_lcd.c * */ /********************* * INCLUDES *********************/ #include "lv_nuttx_lcd.h" #if LV_USE_NUTTX #if LV_USE_NUTTX_LCD #include #include #include #include #include #include #include #include #include "../../../lvgl.h" #include "../../lvgl_private.h" /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ typedef struct { /* fd should be defined at the beginning */ int fd; lv_display_t * disp; struct lcddev_area_s area; struct lcddev_area_align_s align_info; } lv_nuttx_lcd_t; /********************** * STATIC PROTOTYPES **********************/ static int32_t align_round_up(int32_t v, uint16_t align); static void rounder_cb(lv_event_t * e); static void flush_cb(lv_display_t * disp, const lv_area_t * area_p, uint8_t * color_p); static lv_display_t * lcd_init(int fd, int hor_res, int ver_res); static void display_release_cb(lv_event_t * e); /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ lv_display_t * lv_nuttx_lcd_create(const char * dev_path) { struct fb_videoinfo_s vinfo; struct lcd_planeinfo_s pinfo; lv_display_t * disp; int fd; int ret; LV_ASSERT_NULL(dev_path); LV_LOG_USER("lcd %s opening", dev_path); fd = open(dev_path, 0); if(fd < 0) { perror("Error: cannot open lcd device"); return NULL; } LV_LOG_USER("lcd %s open success", dev_path); ret = ioctl(fd, LCDDEVIO_GETVIDEOINFO, (unsigned long)((uintptr_t)&vinfo)); if(ret < 0) { perror("Error: ioctl(LCDDEVIO_GETVIDEOINFO) failed"); close(fd); return NULL; } ret = ioctl(fd, LCDDEVIO_GETPLANEINFO, (unsigned long)((uintptr_t)&pinfo)); if(ret < 0) { perror("ERROR: ioctl(LCDDEVIO_GETPLANEINFO) failed"); close(fd); return NULL; } disp = lcd_init(fd, vinfo.xres, vinfo.yres); if(disp == NULL) { close(fd); } return disp; } /********************** * STATIC FUNCTIONS **********************/ static int32_t align_round_up(int32_t v, uint16_t align) { return (v + align - 1) & ~(align - 1); } static void rounder_cb(lv_event_t * e) { lv_nuttx_lcd_t * lcd = lv_event_get_user_data(e); lv_area_t * area = lv_event_get_param(e); struct lcddev_area_align_s * align_info = &lcd->align_info; int32_t w; int32_t h; area->x1 &= ~(align_info->col_start_align - 1); area->y1 &= ~(align_info->row_start_align - 1); w = align_round_up(lv_area_get_width(area), align_info->width_align); h = align_round_up(lv_area_get_height(area), align_info->height_align); area->x2 = area->x1 + w - 1; area->y2 = area->y1 + h - 1; } static void flush_cb(lv_display_t * disp, const lv_area_t * area_p, uint8_t * color_p) { lv_nuttx_lcd_t * lcd = disp->driver_data; lcd->area.row_start = area_p->y1; lcd->area.row_end = area_p->y2; lcd->area.col_start = area_p->x1; lcd->area.col_end = area_p->x2; lcd->area.data = (uint8_t *)color_p; ioctl(lcd->fd, LCDDEVIO_PUTAREA, (unsigned long) & (lcd->area)); lv_display_flush_ready(disp); } static lv_display_t * lcd_init(int fd, int hor_res, int ver_res) { uint8_t * draw_buf = NULL; uint8_t * draw_buf_2 = NULL; lv_nuttx_lcd_t * lcd = lv_malloc_zeroed(sizeof(lv_nuttx_lcd_t)); LV_ASSERT_MALLOC(lcd); if(lcd == NULL) { LV_LOG_ERROR("lv_nuttx_lcd_t malloc failed"); return NULL; } lv_display_t * disp = lv_display_create(hor_res, ver_res); if(disp == NULL) { lv_free(lcd); return NULL; } uint32_t px_size = lv_color_format_get_size(lv_display_get_color_format(disp)); #if LV_NUTTX_LCD_BUFFER_COUNT > 0 uint32_t buf_size = hor_res * ver_res * px_size; lv_display_render_mode_t render_mode = LV_DISPLAY_RENDER_MODE_FULL; #else uint32_t buf_size = hor_res * LV_NUTTX_LCD_BUFFER_SIZE * px_size; lv_display_render_mode_t render_mode = LV_DISPLAY_RENDER_MODE_PARTIAL; #endif draw_buf = lv_malloc(buf_size); if(draw_buf == NULL) { LV_LOG_ERROR("display draw_buf malloc failed"); lv_free(lcd); return NULL; } #if LV_NUTTX_LCD_BUFFER_COUNT == 2 draw_buf_2 = lv_malloc(buf_size); if(draw_buf_2 == NULL) { LV_LOG_ERROR("display draw_buf_2 malloc failed"); lv_free(lcd); lv_free(draw_buf); return NULL; } #endif lcd->fd = fd; if(ioctl(fd, LCDDEVIO_GETAREAALIGN, &lcd->align_info) < 0) { perror("Error: ioctl(LCDDEVIO_GETAREAALIGN) failed"); } lcd->disp = disp; lv_display_set_buffers(lcd->disp, draw_buf, draw_buf_2, buf_size, render_mode); lv_display_set_flush_cb(lcd->disp, flush_cb); lv_display_add_event_cb(lcd->disp, rounder_cb, LV_EVENT_INVALIDATE_AREA, lcd); lv_display_add_event_cb(lcd->disp, display_release_cb, LV_EVENT_DELETE, lcd->disp); lv_display_set_driver_data(lcd->disp, lcd); return lcd->disp; } static void display_release_cb(lv_event_t * e) { lv_display_t * disp = (lv_display_t *) lv_event_get_user_data(e); lv_nuttx_lcd_t * dsc = lv_display_get_driver_data(disp); if(dsc) { lv_display_set_driver_data(disp, NULL); lv_display_set_flush_cb(disp, NULL); /* clear display buffer */ if(disp->buf_1) { lv_free(disp->buf_1); disp->buf_1 = NULL; } if(disp->buf_2) { lv_free(disp->buf_2); disp->buf_2 = NULL; } /* close device fb */ if(dsc->fd >= 0) { close(dsc->fd); dsc->fd = -1; } lv_free(dsc); LV_LOG_USER("Done"); } } #endif /*LV_USE_NUTTX_LCD*/ #endif /* LV_USE_NUTTX*/