From b9870339c0a04779e01f09b2a0ddc285fd377813 Mon Sep 17 00:00:00 2001 From: Jinkun Hong Date: Tue, 7 Jun 2022 10:01:58 +0800 Subject: [PATCH 7/7] add rk_lvgl_demo Signed-off-by: Jinkun Hong --- rk_lvgl_demo/CMakeLists.txt | 30 + rk_lvgl_demo/main.c | 75 +++ rk_lvgl_demo/src/hal/drm_display.c | 1141 +++++++++++++++++++++++++++++++++ rk_lvgl_demo/src/hal/drm_display.h | 36 ++ rk_lvgl_demo/src/hal/evdev.c | 257 ++++++++ rk_lvgl_demo/src/hal/evdev.h | 83 +++ rk_lvgl_demo/src/hal/key.c | 110 ++++ rk_lvgl_demo/src/hal/key.h | 58 ++ rk_lvgl_demo/src/lvgl/lv_port_disp.c | 287 +++++++++ rk_lvgl_demo/src/lvgl/lv_port_disp.h | 21 + rk_lvgl_demo/src/lvgl/lv_port_indev.c | 116 ++++ rk_lvgl_demo/src/lvgl/lv_port_indev.h | 27 + rk_lvgl_demo/src/ui/demo.c | 18 + rk_lvgl_demo/src/ui/demo.h | 7 + 14 files changed, 2266 insertions(+) create mode 100644 rk_lvgl_demo/CMakeLists.txt create mode 100644 rk_lvgl_demo/main.c create mode 100644 rk_lvgl_demo/src/hal/drm_display.c create mode 100644 rk_lvgl_demo/src/hal/drm_display.h create mode 100644 rk_lvgl_demo/src/hal/evdev.c create mode 100644 rk_lvgl_demo/src/hal/evdev.h create mode 100644 rk_lvgl_demo/src/hal/key.c create mode 100644 rk_lvgl_demo/src/hal/key.h create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_disp.c create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_disp.h create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_indev.c create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_indev.h create mode 100644 rk_lvgl_demo/src/ui/demo.c create mode 100644 rk_lvgl_demo/src/ui/demo.h diff --git a/rk_lvgl_demo/CMakeLists.txt b/rk_lvgl_demo/CMakeLists.txt new file mode 100644 index 0000000..ab4683d --- /dev/null +++ b/rk_lvgl_demo/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.8) + +project(rk_lvgl_demo) + +include(FindPkgConfig) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include_directories( + ${PROJECT_SOURCE_DIR}/./ + ${PROJECT_SOURCE_DIR}/src/ + ${CMAKE_SYSROOT}/usr/include/lvgl/ + ${CMAKE_SYSROOT}/usr/include/libdrm/ + ${CMAKE_SYSROOT}/usr/include/rockchip/ + ) + +link_directories( + ${PROJECT_SOURCE_DIR}/./lib) + +aux_source_directory(./ SRCS) +aux_source_directory(./src/hal/ SRCS) +aux_source_directory(./src/lvgl SRCS) +aux_source_directory(./src/ui SRCS) + +add_executable(${PROJECT_NAME} ${SRCS}) + +target_link_libraries(${PROJECT_NAME} + drm lvgl rga pthread m lvgl_demos) + +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) diff --git a/rk_lvgl_demo/main.c b/rk_lvgl_demo/main.c new file mode 100644 index 0000000..f46179b --- /dev/null +++ b/rk_lvgl_demo/main.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 Rockchip, Inc. All Rights Reserved. + * + * Licensed 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "lvgl.h" + +#include "lvgl/lv_port_disp.h" +#include "lvgl/lv_port_indev.h" +#include "src/ui/demo.h" + +#define LVGL_TICK 5 + +static int g_ui_rotation = 0; +static int quit = 0; + +static void sigterm_handler(int sig) { + fprintf(stderr, "signal %d\n", sig); + quit = 1; +} + +static void lvgl_init(void) +{ + lv_init(); + lv_port_disp_init(g_ui_rotation); + lv_port_indev_init(g_ui_rotation); +} + +int main(int argc, char **argv) +{ + signal(SIGINT, sigterm_handler); + c_RkRgaInit(); + lvgl_init(); + + demo_start(); + + while(!quit) { + lv_tick_inc(LVGL_TICK); + lv_task_handler(); + usleep(LVGL_TICK * 1000); + } + c_RkRgaDeInit(); + + return 0; +} diff --git a/rk_lvgl_demo/src/hal/drm_display.c b/rk_lvgl_demo/src/hal/drm_display.c new file mode 100644 index 0000000..85dce61 --- /dev/null +++ b/rk_lvgl_demo/src/hal/drm_display.c @@ -0,0 +1,1141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "drm_display.h" + +#define NUM_DUMB_BO 3 + +#define DEBUG +#ifdef DEBUG +#define DRM_DEBUG(fmt, ...) \ + if (getenv("MJPG_DRM_DEBUG")) \ + printf("DRM_DEBUG: %s(%d) " fmt, __func__, __LINE__, __VA_ARGS__) +#else +#define DRM_DEBUG(fmt, ...) +#endif + +struct device { + int fd; + + struct { + int width; + int height; + + int hdisplay; + int vdisplay; + + int current; + int fb_num; + int bpp; + } mode; + + drmModeResPtr res; + + int connector_id; + int encoder_id; + int crtc_id; + int plane_id; + int video_plane_id; + int last_fb_id; + + struct drm_bo *dumb_bo[NUM_DUMB_BO]; + struct drm_bo *video_bo[NUM_DUMB_BO]; + int current_dumb; + int current_video; + + int waiting_for_flip; + struct pollfd drm_pollfd; + drmEventContext drm_evctx; + int rot; + + int drm_invalide; + int screen_state; +}; + +struct device *pdev; + +static int bo_map(struct device *dev, struct drm_bo *bo) +{ + struct drm_mode_map_dumb arg = { + .handle = bo->handle, + }; + int ret; + + ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg); + if (ret) + return ret; + + bo->ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + dev->fd, arg.offset); + if (bo->ptr == MAP_FAILED) { + bo->ptr = NULL; + return -1; + } + + return 0; +} + +static void bo_unmap(struct device *dev, struct drm_bo *bo) +{ + if (dev == NULL) + return; + if (!bo->ptr) + return; + + drmUnmap(bo->ptr, bo->size); + bo->ptr = NULL; +} + +void bo_destroy(struct device *dev, struct drm_bo *bo) +{ + struct drm_mode_destroy_dumb arg = { + .handle = bo->handle, + }; + + if (bo->fb_id) + drmModeRmFB(dev->fd, bo->fb_id); + + bo_unmap(dev, bo); + + if (bo->handle) + drmIoctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg); + + free(bo); +} + +static struct drm_bo * +bo_create(struct device *dev, int width, int height, int format) +{ + struct drm_mode_create_dumb arg = { + .bpp = 32, + .width = width, + .height = height, + }; + struct drm_bo *bo; + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + int ret; + + bo = malloc(sizeof(struct drm_bo)); + if (bo == NULL) { + fprintf(stderr, "allocate bo failed\n"); + return NULL; + } + memset(bo, 0, sizeof(*bo)); + if (format == DRM_FORMAT_NV12) { + arg.bpp = 8; + arg.height = height * 3 / 2; + } + + ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg); + if (ret) { + fprintf(stderr, "create dumb failed\n"); + goto err; + } + + bo->fd = dev->fd; + bo->handle = arg.handle; + bo->size = arg.size; + bo->pitch = arg.pitch; + + ret = bo_map(dev, bo); + if (ret) { + fprintf(stderr, "map bo failed\n"); + goto err; + } + + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + handles[0] = bo->handle; + pitches[0] = bo->pitch ; + offsets[0] = 0; + handles[1] = bo->handle; + pitches[1] = pitches[0]; + offsets[1] = pitches[0] * height; + break; + case DRM_FORMAT_RGB332: + handles[0] = bo->handle; + pitches[0] = bo->pitch; + offsets[0] = 0; + break; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + handles[0] = bo->handle; + pitches[0] = bo->pitch ; + offsets[0] = 0; + break; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + handles[0] = bo->handle; + pitches[0] = bo->pitch ; + offsets[0] = 0; + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + handles[0] = bo->handle; + pitches[0] = bo->pitch ; + offsets[0] = 0; + break; + } + + ret = drmModeAddFB2(dev->fd, width, height, format, handles, + pitches, offsets, (uint32_t *)&bo->fb_id, 0); + if (ret) { + fprintf(stderr, "add fb failed\n"); + goto err; + } + DRM_DEBUG("Created bo: %d, %dx%d\n", bo->fb_id, width, height); + + return bo; +err: + bo_destroy(dev, bo); + return NULL; +} + +static void free_fb(struct device *dev) +{ + DRM_DEBUG("Free fb, num: %d, bpp: %d\n", dev->mode.fb_num, dev->mode.bpp); + + dev->mode.fb_num = 0; + dev->mode.bpp = 0; + dev->mode.current = 0; +} + +static int alloc_fb(struct device *dev, int num, int bpp) +{ + DRM_DEBUG("Alloc fb num: %d, bpp: %d\n", num, bpp); + + dev->mode.fb_num = num; + dev->mode.bpp = bpp; + dev->mode.current = 0; + + return 0; +} + +static int drm_get_preferred_connector(void) +{ + const char *path; + char buf[256] = "\0"; + int fd; + +#define DRM_CONNECTOR_CFG_PATH_ENV "DRM_CONNECTOR_CFG_PATH" +#define DRM_CONNECTOR_CFG_PATH_DEFAULT "/tmp/drm_connector.cfg" + path = getenv(DRM_CONNECTOR_CFG_PATH_ENV); + if (!path) + path = DRM_CONNECTOR_CFG_PATH_DEFAULT; + + fd = open(path, O_RDONLY); + read(fd, buf, sizeof(buf)); + close(fd); + + if (!buf[0]) + return -1; + + return atoi(buf); +} + +static int drm_get_preferred_mode(int *width, int *height) +{ + const char *path; + char buf[256] = "\0"; + int fd, w, h; + +#define DRM_MODE_CFG_PATH_ENV "DRM_CONNECTOR_CFG_PATH" +#define DRM_MODE_CFG_PATH_DEFAULT "/tmp/drm_mode.cfg" + path = getenv(DRM_MODE_CFG_PATH_ENV); + if (!path) + path = DRM_MODE_CFG_PATH_DEFAULT; + + fd = open(path, O_RDONLY); + read(fd, buf, sizeof(buf)); + close(fd); + + if (!buf[0]) + return -1; + + if (2 != sscanf(buf, "%dx%d", &w, &h)) + return -1; + + *width = w; + *height = h; + + return 0; +} + +static drmModeConnectorPtr +drm_get_connector(struct device *dev, int connector_id) +{ + drmModeConnectorPtr conn; + + conn = drmModeGetConnector(dev->fd, connector_id); + if (!conn) + return NULL; + + DRM_DEBUG("Connector id: %d, %sconnected, modes: %d\n", connector_id, + (conn->connection == DRM_MODE_CONNECTED) ? "" : "dis", + conn->count_modes); + if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) + return conn; + + drmModeFreeConnector(conn); + return NULL; +} + +static drmModeConnectorPtr +drm_find_best_connector(struct device *dev) +{ + drmModeResPtr res = dev->res; + drmModeConnectorPtr conn; + int i, preferred_connector_id = drm_get_preferred_connector(); + + DRM_DEBUG("Preferred connector id: %d\n", preferred_connector_id); + conn = drm_get_connector(dev, preferred_connector_id); + if (conn) + return conn; + + for (i = 0; i < res->count_connectors; i++) { + conn = drm_get_connector(dev, res->connectors[i]); + if (conn) + return conn; + } + return NULL; +} + +static drmModeCrtcPtr +drm_find_best_crtc(struct device *dev, drmModeConnectorPtr conn) +{ + drmModeResPtr res = dev->res; + drmModeEncoderPtr encoder; + drmModeCrtcPtr crtc; + int i, preferred_crtc_id = 0; + int crtcs_for_connector = 0; + + encoder = drmModeGetEncoder(dev->fd, conn->encoder_id); + if (encoder) { + preferred_crtc_id = encoder->crtc_id; + drmModeFreeEncoder(encoder); + } + DRM_DEBUG("Preferred crtc: %d\n", preferred_crtc_id); + + crtc = drmModeGetCrtc(dev->fd, preferred_crtc_id); + if (crtc) + return crtc; + + for (i = 0; i < res->count_encoders; i++) { + encoder = drmModeGetEncoder(dev->fd, res->encoders[i]); + if (encoder) + crtcs_for_connector |= encoder->possible_crtcs; + drmModeFreeEncoder(encoder); + } + DRM_DEBUG("Possible crtcs: %x\n", crtcs_for_connector); + if (!crtcs_for_connector) + return NULL; + + return drmModeGetCrtc(dev->fd, res->crtcs[ffs(crtcs_for_connector) - 1]); +} + +int +drm_plane_is_primary(struct device *dev, int plane_id) +{ + drmModeObjectPropertiesPtr props; + drmModePropertyPtr prop; + unsigned int i; + int type = 0; + + props = drmModeObjectGetProperties(dev->fd, plane_id, + DRM_MODE_OBJECT_PLANE); + if (!props) + return 0; + + for (i = 0; i < props->count_props; i++) { + prop = drmModeGetProperty(dev->fd, props->props[i]); + if (prop && !strcmp(prop->name, "type")) + type = props->prop_values[i]; + drmModeFreeProperty(prop); + } + DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type); + + drmModeFreeObjectProperties(props); + return type == DRM_PLANE_TYPE_PRIMARY; +} + +int +drm_plane_is_overlay(struct device *dev, int plane_id) +{ + drmModeObjectPropertiesPtr props; + drmModePropertyPtr prop; + unsigned int i; + int type = 0; + + props = drmModeObjectGetProperties(dev->fd, plane_id, + DRM_MODE_OBJECT_PLANE); + if (!props) + return 0; + + for (i = 0; i < props->count_props; i++) { + prop = drmModeGetProperty(dev->fd, props->props[i]); + if (prop && !strcmp(prop->name, "type")) + type = props->prop_values[i]; + drmModeFreeProperty(prop); + } + DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type); + + drmModeFreeObjectProperties(props); + return type == DRM_PLANE_TYPE_OVERLAY; +} + +static drmModePlanePtr +drm_get_plane(struct device *dev, int plane_id, int pipe) +{ + drmModePlanePtr plane; + + plane = drmModeGetPlane(dev->fd, plane_id); + if (!plane) + return NULL; + + DRM_DEBUG("Check plane: %d, possible_crtcs: %x\n", plane_id, + plane->possible_crtcs); + if (drm_plane_is_overlay(dev, plane_id)) { + if (plane->possible_crtcs & (1 << pipe)) + return plane; + } + + drmModeFreePlane(plane); + return NULL; +} + +static drmModePlanePtr +drm_get_video_plane(struct device *dev, int plane_id, int pipe) +{ + drmModePlanePtr plane; + + plane = drmModeGetPlane(dev->fd, plane_id); + if (!plane) + return NULL; + + DRM_DEBUG("Check plane: %d, possible_crtcs: %x\n", plane_id, + plane->possible_crtcs); + if (drm_plane_is_primary(dev, plane_id)) { + if (plane->possible_crtcs & (1 << pipe)) + return plane; + } + + drmModeFreePlane(plane); + return NULL; +} + +static drmModePlanePtr +drm_find_best_plane(struct device *dev, drmModeCrtcPtr crtc) +{ + drmModeResPtr res = dev->res; + drmModePlaneResPtr pres; + drmModePlanePtr plane; + unsigned int i; + int pipe; + + for (pipe = 0; pipe < res->count_crtcs; pipe++) { + if (crtc->crtc_id == res->crtcs[pipe]) + break; + } + if (pipe == res->count_crtcs) + return NULL; + + pres = drmModeGetPlaneResources(dev->fd); + if (!pres) + return NULL; + + for (i = 0; i < pres->count_planes; i++) { + plane = drm_get_plane(dev, pres->planes[i], pipe); + if (plane) { + drmModeFreePlaneResources(pres); + return plane; + } + drmModeFreePlane(plane); + } + + drmModeFreePlaneResources(pres); + return NULL; +} + +static drmModePlanePtr +drm_find_video_plane(struct device *dev, drmModeCrtcPtr crtc) +{ + drmModeResPtr res = dev->res; + drmModePlaneResPtr pres; + drmModePlanePtr plane; + unsigned int i; + int pipe; + + for (pipe = 0; pipe < res->count_crtcs; pipe++) { + if (crtc->crtc_id == res->crtcs[pipe]) + break; + } + if (pipe == res->count_crtcs) + return NULL; + + pres = drmModeGetPlaneResources(dev->fd); + if (!pres) + return NULL; + + for (i = 0; i < pres->count_planes; i++) { + plane = drm_get_video_plane(dev, pres->planes[i], pipe); + if (plane) { + drmModeFreePlaneResources(pres); + return plane; + } + drmModeFreePlane(plane); + } + + drmModeFreePlaneResources(pres); + return NULL; +} + +static drmModeModeInfoPtr +drm_find_best_mode(struct device *dev, drmModeConnectorPtr conn) +{ + drmModeModeInfoPtr mode; + int i, preferred_width = 1920, preferred_height = 1080; + + if (dev == NULL) + return 0; + drm_get_preferred_mode(&preferred_width, &preferred_height); + DRM_DEBUG("Preferred mode: %dx%d\n", preferred_width, preferred_height); + + mode = &conn->modes[0]; + for (i = 0; i < conn->count_modes; i++) { + DRM_DEBUG("Check mode: %dx%d\n", + conn->modes[i].hdisplay, conn->modes[i].vdisplay); + if (conn->modes[i].hdisplay == preferred_width && + conn->modes[i].vdisplay == preferred_height) { + mode = &conn->modes[i]; + break; + } + } + + return mode; +} + +static int drm_get_preferred_fb_mode(int *width, int *height) +{ + char *buf; + int w, h; + + buf = getenv("MINIGUI_DRM_FB_MODE"); + if (!buf) + return -1; + + if (2 != sscanf(buf, "%dx%d", &w, &h)) + return -1; + + DRM_DEBUG("Preferred fb mode: %dx%d\n", w, h); + *width = w; + *height = h; + + return 0; +} + +static void drm_setup_fb_mode(struct device *dev) +{ + drmModeResPtr res = dev->res; + drmModeConnectorPtr conn; + drmModeModeInfoPtr mode; + int i; + + if (dev->mode.width && dev->mode.height) + return; + + if (!drm_get_preferred_fb_mode(&dev->mode.width, &dev->mode.height)) + return; + + dev->mode.width = dev->mode.hdisplay; + dev->mode.height = dev->mode.vdisplay; + + for (i = 0; i < res->count_connectors; i++) { + conn = drm_get_connector(dev, res->connectors[i]); + if (!conn) + continue; + + mode = drm_find_best_mode(dev, conn); + if (mode) { + DRM_DEBUG("Best mode for connector(%d): %dx%d\n", + conn->connector_id, mode->hdisplay, mode->vdisplay); + if (dev->mode.width > mode->hdisplay || + dev->mode.height > mode->vdisplay) { + dev->mode.width = mode->hdisplay; + dev->mode.height = mode->vdisplay; + } + } + drmModeFreeConnector(conn); + } +} + +static void drm_free(struct device *dev) +{ + int i; + + for (i = 0; i < NUM_DUMB_BO; i++) { + if (dev->dumb_bo[i]) { + bo_destroy(dev, dev->dumb_bo[i]); + dev->dumb_bo[i] = NULL; + } + if (dev->video_bo[i]) { + bo_destroy(dev, dev->video_bo[i]); + dev->video_bo[i] = NULL; + } + } + + if (dev->res) { + drmModeFreeResources(dev->res); + dev->res = NULL; + } + + dev->connector_id = 0; + dev->crtc_id = 0; + dev->plane_id = 0; + dev->video_plane_id = 0; + dev->mode.hdisplay = 0; + dev->mode.vdisplay = 0; +} + +static void configure_plane_zpos (struct device *self, int plane_id, uint64_t zpos) +{ + drmModeObjectPropertiesPtr props = NULL; + drmModePropertyPtr prop = NULL; + char *buf; + unsigned int i; + + if (plane_id <= 0) + return; + + if (drmSetClientCap (self->fd, DRM_CLIENT_CAP_ATOMIC, 1)) + return; + + props = drmModeObjectGetProperties (self->fd, plane_id, + DRM_MODE_OBJECT_PLANE); + if (!props) + goto out; + + for (i = 0; i < props->count_props; i++) { + prop = drmModeGetProperty (self->fd, props->props[i]); + if (prop && !strcmp (prop->name, "ZPOS")) + break; + drmModeFreeProperty (prop); + prop = NULL; + } + + if (!prop) + goto out; + + drmModeObjectSetProperty (self->fd, plane_id, + DRM_MODE_OBJECT_PLANE, props->props[i], zpos); +out: + drmModeFreeProperty (prop); + drmModeFreeObjectProperties (props); +} + +static int drm_setup(struct device *dev) +{ + drmModeConnectorPtr conn = NULL; + drmModeModeInfoPtr mode; + drmModePlanePtr plane = NULL; + drmModePlanePtr video_plane = NULL; + drmModeCrtcPtr crtc = NULL; + //int ret; + int i, success = 0; + + dev->res = drmModeGetResources(dev->fd); + if (!dev->res) { + fprintf(stderr, "drm get resource failed\n"); + goto err; + } + + conn = drm_find_best_connector(dev); + if (!conn) { + fprintf(stderr, "drm find connector failed\n"); + goto err; + } + DRM_DEBUG("Best connector id: %d\n", conn->connector_id); + + mode = drm_find_best_mode(dev, conn); + if (!mode) { + fprintf(stderr, "drm find mode failed\n"); + goto err; + } + DRM_DEBUG("Best mode: %dx%d\n", mode->hdisplay, mode->vdisplay); + + crtc = drm_find_best_crtc(dev, conn); + if (!crtc) { + fprintf(stderr, "drm find crtc failed\n"); + goto err; + } + DRM_DEBUG("Best crtc: %d\n", crtc->crtc_id); + + plane = drm_find_best_plane(dev, crtc); + if (!plane) { + fprintf(stderr, "drm find plane failed\n"); + goto err; + } + configure_plane_zpos(dev, plane->plane_id, 1); + DRM_DEBUG("Best plane: %d\n", plane->plane_id); + + video_plane = drm_find_video_plane(dev, crtc); + if (!video_plane) { + fprintf(stderr, "drm find video plane failed\n"); + goto err; + } + configure_plane_zpos(dev, video_plane->plane_id, 0); + DRM_DEBUG("video plane: %d\n", video_plane->plane_id); + + for (i = 0; i < NUM_DUMB_BO; i++) { + dev->dumb_bo[i] = bo_create(dev, mode->hdisplay, mode->vdisplay, DRM_FORMAT_ARGB8888); + if (!dev->dumb_bo[i]) { + fprintf(stderr, "create dumb bo %d failed\n", i); + goto err; + } + DRM_DEBUG("Created dumb bo fb: %d\n", dev->dumb_bo[i]->fb_id); + } + for (i = 0; i < NUM_DUMB_BO; i++) { + dev->video_bo[i] = bo_create(dev, mode->hdisplay, mode->vdisplay, DRM_FORMAT_ARGB8888/*DRM_FORMAT_NV12*/); + if (!dev->video_bo[i]) { + fprintf(stderr, "create video bo %d failed\n", i); + goto err; + } + DRM_DEBUG("Created video bo fb: %d\n", dev->video_bo[i]->fb_id); + } + + dev->current_dumb = 0; + dev->current_video = 0; +#if 0 + ret = drmModeSetCrtc(dev->fd, crtc->crtc_id, + dev->dumb_bo[dev->current_dumb]->fb_id, 0, 0, + &conn->connector_id, 1, mode); + if (ret) { + fprintf(stderr, "drm set mode failed\n"); + goto err; + } +#endif + dev->connector_id = conn->connector_id; + dev->crtc_id = crtc->crtc_id; + dev->plane_id = plane->plane_id; + dev->video_plane_id = video_plane->plane_id; + + dev->last_fb_id = 0; + dev->mode.hdisplay = mode->hdisplay; + dev->mode.vdisplay = mode->vdisplay; + + drm_setup_fb_mode(dev); + DRM_DEBUG("Drm fb mode: %dx%d\n", dev->mode.width, dev->mode.height); + + success = 1; +err: + drmModeFreeConnector(conn); + drmModeFreePlane(plane); + drmModeFreePlane(video_plane); + drmModeFreeCrtc(crtc); + if (!success) { + drm_free(dev); + return -1; + } + return 0; +} + +static void drm_flip_handler(int fd, unsigned frame, unsigned sec, + unsigned usec, void *data) +{ + // data is &dev->waiting_for_flip + DRM_DEBUG("Page flip received(%d)!, %d, %d, %d, %d\n", *(int*)data, fd, frame, sec, usec); + *(int*)data = 0; +} +#if 0 +void drm_sighandler(int sig) +{ + if (!pdev) + return; + + if (sig == SIGUSR2) { + DRM_DEBUG("Request reinit drm by sig: %d\n", sig); + pdev->drm_invalide = 1; + } +} + +static void drm_install_sighandler(struct device* dev) +{ + struct sigaction sa; + if (dev == NULL) + return; + sa.sa_sigaction = NULL; + sa.sa_handler = drm_sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGUSR2, &sa, NULL); +} +#endif + +int drm_init(int bpp, int rot) +{ + int ret; + + pdev = malloc(sizeof(struct device)); + if (pdev == NULL) { + fprintf(stderr, "allocate device failed\n"); + return -1; + } + memset(pdev, 0, sizeof(*pdev)); + pdev->screen_state = 1; + + //drm_install_sighandler(pdev); + + pdev->fd = drmOpen(NULL, NULL); + if (pdev->fd < 0) + pdev->fd = open("/dev/dri/card0", O_RDWR); + if (pdev->fd < 0) { + fprintf(stderr, "drm open failed\n"); + goto err_drm_open; + } + fcntl(pdev->fd, F_SETFD, FD_CLOEXEC); + + drmSetClientCap(pdev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + + ret = alloc_fb(pdev, NUM_DUMB_BO, bpp); + if (ret) { + fprintf(stderr, "alloc fb failed\n"); + goto err_alloc_fb; + } + + ret = drm_setup(pdev); + if (ret) { + fprintf(stderr, "drm setup failed\n"); + goto err_drm_setup; + } + + pdev->drm_pollfd.fd = pdev->fd; + pdev->drm_pollfd.events = POLLIN; + + pdev->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + pdev->drm_evctx.page_flip_handler = drm_flip_handler; + pdev->rot = rot; + + return 0; +err_alloc_fb: + drm_free(pdev); +err_drm_setup: + drmClose(pdev->fd); +err_drm_open: + free(pdev); + pdev = NULL; + return -1; +} + +int drm_deinit(void) +{ + struct device* dev = pdev; + if (!dev) + return 0; + + free_fb(dev); + drm_free(dev); + + if (pdev->fd > 0) + drmClose(dev->fd); + + free(pdev); + pdev = NULL; + + return 0; +} + +int getdrmrot(void) +{ + return pdev->rot; +} + +void getdrmdispbuff(char **buff) +{ + *buff = pdev->dumb_bo[pdev->current_dumb]->ptr; +} + +int getdrmdispinfo(struct drm_bo *bo, int *w, int *h) +{ + if (pdev->dumb_bo[pdev->current_dumb]) { + memcpy(bo, pdev->dumb_bo[pdev->current_dumb], sizeof(struct drm_bo)); + *w = pdev->mode.width; + *h = pdev->mode.height; + } + + return 0; +} + +struct drm_bo *getdrmdisp(void) +{ + if (pdev->screen_state) + pdev->current_dumb ++; + if (pdev->current_dumb >= NUM_DUMB_BO) + pdev->current_dumb = 0; + return pdev->dumb_bo[pdev->current_dumb]; +} + +static void drm_wait_flip(struct device* dev, int timeout) +{ + int ret; + + while (dev->waiting_for_flip) { + dev->drm_pollfd.revents = 0; + ret = poll(&dev->drm_pollfd, 1, timeout); + if (ret <= 0) + return; + + drmHandleEvent(dev->fd, &dev->drm_evctx); + } +} + +void setdrmdisp(struct drm_bo *bo) +{ + struct device* dev = pdev; + int crtc_x, crtc_y, crtc_w, crtc_h; + int ret; + int fb = bo->fb_id, sw = dev->mode.width, sh = dev->mode.height; + + if (dev == NULL) + return; + if (!dev->screen_state) + return; + + crtc_w = dev->mode.width; + crtc_h = dev->mode.height; + crtc_x = 0; + crtc_y = 0; + + DRM_DEBUG("Display bo %d(%dx%d) at (%d,%d) %dx%d\n", fb, sw, sh, + crtc_x, crtc_y, crtc_w, crtc_h); + ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, fb, 0, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, sw << 16, sh << 16); + if (ret) { + fprintf(stderr, "drm set plane failed\n"); + return; + } + if (0) { + // Queue page flip + dev->waiting_for_flip = 1; + ret = drmModePageFlip(dev->fd, dev->crtc_id, fb, + DRM_MODE_PAGE_FLIP_EVENT, &dev->waiting_for_flip); + if (ret) { + fprintf(stderr, "drm page flip failed\n"); + return; + } + // Wait for last page flip + drm_wait_flip(dev, -1); + } +} + +void getdrmvideodispbuff(char **buff) +{ + if (pdev->video_bo[pdev->current_video]) + *buff = pdev->video_bo[pdev->current_video]->ptr; +} + +int getdrmvideodispinfo(struct drm_bo *bo, int *w, int *h) +{ + if (pdev->video_bo[pdev->current_video]) { + memcpy(bo, pdev->video_bo[pdev->current_video], sizeof(struct drm_bo)); + *w = pdev->mode.width; + *h = pdev->mode.height; + } + + return 0; +} + +struct drm_bo *getdrmvideodisp(void) +{ + if (pdev->screen_state) + pdev->current_video ++; + if (pdev->current_video >= NUM_DUMB_BO) + pdev->current_video = 0; + return pdev->video_bo[pdev->current_video]; +} + +void setdrmvideodisp(struct drm_bo *bo) +{ + struct device* dev = pdev; + int crtc_x, crtc_y, crtc_w, crtc_h; + int ret; + int fb = bo->fb_id, sw = dev->mode.width, sh = dev->mode.height; + + if (dev == NULL) + return; + if (!dev->screen_state) + return; + + crtc_w = dev->mode.width; + crtc_h = dev->mode.height; + crtc_x = 0; + crtc_y = 0; + + DRM_DEBUG("Display bo %d(%dx%d) at (%d,%d) %dx%d\n", fb, sw, sh, + crtc_x, crtc_y, crtc_w, crtc_h); + ret = drmModeSetPlane(dev->fd, dev->video_plane_id, dev->crtc_id, fb, 0, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, sw << 16, sh << 16); + if (ret) { + fprintf(stderr, "drm set plane failed\n"); + return; + } +} + +void drmvideodispblack(void) +{ + struct drm_bo *bo; + int w; + int sw; + int h; + int *buff; + int i, j; + + getdrmresolve(&w, &h); + sw = getdrmvideowstride(); + for (j = 0; j < NUM_DUMB_BO; j++) { + bo = getdrmvideodisp(); + getdrmvideodispbuff(&buff); + for (i = 0; i < sw * h; i++) { + buff[i] = 0xff000000; + } + setdrmvideodisp(bo); + } +} + +int drm_screen_off(void) +{ + struct device *dev = pdev; + struct drm_bo *bo; + int current_dumb; + int *buff; + int sw; + int w, h; + int ret; + int i; + + if (dev == NULL) + return; + if (!dev->screen_state) + return -1; + dev->screen_state = 0; + current_dumb = pdev->current_dumb + 1; + + if (current_dumb >= NUM_DUMB_BO) + current_dumb = 0; + bo = pdev->dumb_bo[current_dumb]; + buff = bo->ptr; + getdrmresolve(&w, &h); + sw = getdrmvideowstride(); + for (i = 0; i < sw * h; i++) { + buff[i] = 0xff000000; + } + ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, bo->fb_id, 0, + 0, 0, dev->mode.width, dev->mode.height, + 0, 0, dev->mode.width << 16, dev->mode.height << 16); + if (ret) { + fprintf(stderr, "drm set plane failed\n"); + } + return 0; +} + +int drm_screen_on(void) +{ + struct device *dev = pdev; + struct drm_bo *bo; + int current_dumb; + int ret; + if (dev->screen_state) + return -1; + current_dumb = pdev->current_dumb; + + bo = pdev->dumb_bo[current_dumb]; + + ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, bo->fb_id, 0, + 0, 0, dev->mode.width, dev->mode.height, + 0, 0, dev->mode.width << 16, dev->mode.height << 16); + if (ret) { + fprintf(stderr, "drm set plane failed\n"); + } + dev->screen_state = 1; + + return 0; +} + +int drm_invalide(void) +{ + return pdev && pdev->drm_invalide; +} + +void getdrmdispbpp(int *bpp) +{ + *bpp = pdev->mode.bpp; +} + +int getdrmwstride(void) +{ + return pdev->dumb_bo[pdev->current_dumb]->pitch / 4; +} + +int getdrmvideowstride(void) +{ + return pdev->video_bo[pdev->current_video]->pitch / 4; +} + +void getdrmresolve(int *w, int *h) +{ + *w = pdev->mode.width; + *h = pdev->mode.height; +} + +#if 0 +int main(int argc, char **argv) +{ + int i; + int val = 0xff; + int w; + int h; + char *viraddr; + + printf("drm_display run\n"); + if (drm_init(32, 0) < 0) + return -1; + + getdrmresolve(&w, &h); + struct drm_bo *bo = getdrmdisp(); + getdrmdispbuff(&viraddr); + printf("%d, %d\n", w, h); + memset(viraddr, 0x00, w * h * 4); + setdrmdisp(bo); + while(1) { + if (val == 0xff) { + val = 0x80; + } else { + val = 0xff; + } + memset(viraddr, val, w * h * 4); + sleep(1); + } + + drm_deinit(); + printf("drm_display exit\n"); + + return 0; +} +#endif \ No newline at end of file diff --git a/rk_lvgl_demo/src/hal/drm_display.h b/rk_lvgl_demo/src/hal/drm_display.h new file mode 100644 index 0000000..bccbced --- /dev/null +++ b/rk_lvgl_demo/src/hal/drm_display.h @@ -0,0 +1,36 @@ +#ifndef __DRM_DISPLAY_H__ +#define __DRM_DISPLAY_H__ + +struct drm_bo { + int fd; + void *ptr; + size_t size; + size_t offset; + size_t pitch; + unsigned int handle; + int fb_id; +}; + +int drm_init(int bpp, int rot); +int drm_deinit(void); +void getdrmdispbuff(char **buff); +int getdrmdispinfo(struct drm_bo *bo, int *w, int *h); +struct drm_bo *getdrmdisp(void); +void setdrmdisp(struct drm_bo *bo); +int drm_setmode(int num, int bpp); +int drm_invalide(void); +void getdrmdispbpp(int *bpp); +void getdrmresolve(int *w, int *h); +void getdrmvideodispbuff(char **buff); +int getdrmvideodispinfo(struct drm_bo *bo, int *w, int *h); +struct drm_bo *getdrmvideodisp(void); +void setdrmvideodisp(struct drm_bo *bo); +void drmvideodispblack(void); +int getdrmwstride(void); +int getdrmvideowstride(void); +int getdrmrot(void); + +int drm_screen_off(void); +int drm_screen_on(void); + +#endif diff --git a/rk_lvgl_demo/src/hal/evdev.c b/rk_lvgl_demo/src/hal/evdev.c new file mode 100644 index 0000000..0c9c4f0 --- /dev/null +++ b/rk_lvgl_demo/src/hal/evdev.c @@ -0,0 +1,257 @@ +/** + * @file evdev.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "evdev.h" +#if USE_EVDEV != 0 || USE_BSD_EVDEV + +#include +#include +#include +#if USE_BSD_EVDEV +#include +#else +#include +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +int map(int x, int in_min, int in_max, int out_min, int out_max); + +/********************** + * STATIC VARIABLES + **********************/ +int evdev_fd; +int evdev_root_x; +int evdev_root_y; +int evdev_button; + +int evdev_key_val; + +int evdev_rot; +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the evdev interface + */ +void evdev_init(int rot) +{ + evdev_rot = rot; +#if USE_BSD_EVDEV + evdev_fd = open(EVDEV_NAME, O_RDWR | O_NOCTTY); +#else + evdev_fd = open(EVDEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY); +#endif + if(evdev_fd == -1) { + perror("unable open evdev interface:"); + return; + } + +#if USE_BSD_EVDEV + fcntl(evdev_fd, F_SETFL, O_NONBLOCK); +#else + fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK); +#endif + + evdev_root_x = 0; + evdev_root_y = 0; + evdev_key_val = 0; + evdev_button = LV_INDEV_STATE_REL; +} +/** + * reconfigure the device file for evdev + * @param dev_name set the evdev device filename + * @return true: the device file set complete + * false: the device file doesn't exist current system + */ +bool evdev_set_file(char* dev_name) +{ + if(evdev_fd != -1) { + close(evdev_fd); + } +#if USE_BSD_EVDEV + evdev_fd = open(dev_name, O_RDWR | O_NOCTTY); +#else + evdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY); +#endif + + if(evdev_fd == -1) { + perror("unable open evdev interface:"); + return false; + } + +#if USE_BSD_EVDEV + fcntl(evdev_fd, F_SETFL, O_NONBLOCK); +#else + fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK); +#endif + + evdev_root_x = 0; + evdev_root_y = 0; + evdev_key_val = 0; + evdev_button = LV_INDEV_STATE_REL; + + return true; +} +/** + * Get the current position and state of the evdev + * @param data store the evdev data here + * @return false: because the points are not buffered, so no more data to be read + */ +void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data) +{ + struct input_event in; + + while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) { + if(in.type == EV_REL) { + if(in.code == REL_X) +#if EVDEV_SWAP_AXES + evdev_root_y += in.value; +#else + evdev_root_x += in.value; +#endif + else if(in.code == REL_Y) +#if EVDEV_SWAP_AXES + evdev_root_x += in.value; +#else + evdev_root_y += in.value; +#endif + } else if(in.type == EV_ABS) { + if(in.code == ABS_X) +#if EVDEV_SWAP_AXES + evdev_root_y = in.value; +#else + evdev_root_x = in.value; +#endif + else if(in.code == ABS_Y) +#if EVDEV_SWAP_AXES + evdev_root_x = in.value; +#else + evdev_root_y = in.value; +#endif + else if(in.code == ABS_MT_POSITION_X) +#if EVDEV_SWAP_AXES + evdev_root_y = in.value; +#else + evdev_root_x = in.value; +#endif + else if(in.code == ABS_MT_POSITION_Y) +#if EVDEV_SWAP_AXES + evdev_root_x = in.value; +#else + evdev_root_y = in.value; +#endif + else if(in.code == ABS_MT_TRACKING_ID) + if(in.value == -1) + evdev_button = LV_INDEV_STATE_REL; + else if(in.value == 0) + evdev_button = LV_INDEV_STATE_PR; + } else if(in.type == EV_KEY) { + if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) { + if(in.value == 0) + evdev_button = LV_INDEV_STATE_REL; + else if(in.value == 1) + evdev_button = LV_INDEV_STATE_PR; + } else if(drv->type == LV_INDEV_TYPE_KEYPAD) { + data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + switch(in.code) { + case KEY_BACKSPACE: + data->key = LV_KEY_BACKSPACE; + break; + case KEY_ENTER: + data->key = LV_KEY_ENTER; + break; + case KEY_UP: + data->key = LV_KEY_UP; + break; + case KEY_LEFT: + data->key = LV_KEY_PREV; + break; + case KEY_RIGHT: + data->key = LV_KEY_NEXT; + break; + case KEY_DOWN: + data->key = LV_KEY_DOWN; + break; + default: + data->key = 0; + break; + } + evdev_key_val = data->key; + evdev_button = data->state; + return ; + } + } + } + + if(drv->type == LV_INDEV_TYPE_KEYPAD) { + /* No data retrieved */ + data->key = evdev_key_val; + data->state = evdev_button; + return ; + } + if(drv->type != LV_INDEV_TYPE_POINTER) + return ; + /*Store the collected data*/ + +#if EVDEV_CALIBRATE + data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, drv->disp->driver->hor_res); + data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, drv->disp->driver->ver_res); +#else + data->point.x = evdev_root_x; + data->point.y = evdev_root_y; +#endif + + data->state = evdev_button; + + if(data->point.x < 0) + data->point.x = 0; + if(data->point.y < 0) + data->point.y = 0; + if (evdev_rot == 90 || evdev_rot == 270) { + int tmp; + if(data->point.x >= drv->disp->driver->ver_res) + data->point.x = drv->disp->driver->ver_res - 1; + if(data->point.y >= drv->disp->driver->hor_res) + data->point.y = drv->disp->driver->hor_res - 1; + tmp = data->point.x; + data->point.x = data->point.y; + data->point.y = drv->disp->driver->ver_res - 1 - tmp; + } else { + if(data->point.x >= drv->disp->driver->hor_res) + data->point.x = drv->disp->driver->hor_res - 1; + if(data->point.y >= drv->disp->driver->ver_res) + data->point.y = drv->disp->driver->ver_res - 1; + } + + return ; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +int map(int x, int in_min, int in_max, int out_min, int out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +#endif diff --git a/rk_lvgl_demo/src/hal/evdev.h b/rk_lvgl_demo/src/hal/evdev.h new file mode 100644 index 0000000..95a0588 --- /dev/null +++ b/rk_lvgl_demo/src/hal/evdev.h @@ -0,0 +1,83 @@ +/** + * @file evdev.h + * + */ + +#ifndef EVDEV_H +#define EVDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------- + * Mouse or touchpad as evdev interface (for Linux based systems) + *------------------------------------------------*/ +#ifndef USE_EVDEV +# define USE_EVDEV 1 +#endif + +#ifndef USE_BSD_EVDEV +# define USE_BSD_EVDEV 0 +#endif + +#if USE_EVDEV || USE_BSD_EVDEV +# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/ +# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/ + +# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/ + +# if EVDEV_CALIBRATE +# define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/ +# define EVDEV_HOR_MAX 4096 /*"evtest" Linux tool can help to get the correct calibraion values>*/ +# define EVDEV_VER_MIN 0 +# define EVDEV_VER_MAX 4096 +# endif /*EVDEV_CALIBRATE*/ +#endif /*USE_EVDEV*/ + +#if USE_EVDEV || USE_BSD_EVDEV + +#include "lvgl.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the evdev + */ +void evdev_init(int rot); +/** + * reconfigure the device file for evdev + * @param dev_name set the evdev device filename + * @return true: the device file set complete + * false: the device file doesn't exist current system + */ +bool evdev_set_file(char* dev_name); +/** + * Get the current position and state of the evdev + * @param data store the evdev data here + * @return false: because the points are not buffered, so no more data to be read + */ +void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data); + + +/********************** + * MACROS + **********************/ + +#endif /* USE_EVDEV */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* EVDEV_H */ diff --git a/rk_lvgl_demo/src/hal/key.c b/rk_lvgl_demo/src/hal/key.c new file mode 100644 index 0000000..036b510 --- /dev/null +++ b/rk_lvgl_demo/src/hal/key.c @@ -0,0 +1,110 @@ +/** + * @file evdev.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "key.h" +#if USE_KEY != 0 + +#include +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static int key_fd; +static int key_button; + +static int key_val; +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the evdev interface + */ +void key_init(void) +{ + key_fd = open(KEY_NAME, O_RDWR | O_NOCTTY | O_NDELAY); + + if(key_fd == -1) { + perror("unable open evdev interface:"); + return; + } + + fcntl(key_fd, F_SETFL, O_ASYNC | O_NONBLOCK); + + key_val = 0; + key_button = LV_INDEV_STATE_REL; +} + +/** + * Get the current position and state of the evdev + * @param data store the evdev data here + * @return false: because the points are not buffered, so no more data to be read + */ +void key_read(lv_indev_drv_t * drv, lv_indev_data_t * data) +{ + struct input_event in; + + while(read(key_fd, &in, sizeof(struct input_event)) > 0) { + if(in.type == EV_KEY) { + data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + switch(in.code) { + case 1: + data->key = LV_KEY_ESC; + break; + case 139: + data->key = LV_KEY_ENTER; + break; + //case KEY_UP: + // data->key = LV_KEY_UP; + // break; + case 105: + data->key = LV_KEY_PREV; + break; + case 106: + data->key = LV_KEY_NEXT; + break; + //case KEY_DOWN: + // data->key = LV_KEY_DOWN; + // break; + default: + data->key = 0; + break; + } + key_val = data->key; + key_button = data->state; + return ; + } + } + + if(drv->type == LV_INDEV_TYPE_KEYPAD) { + /* No data retrieved */ + data->key = key_val; + data->state = key_button; + return ; + } +} +#endif diff --git a/rk_lvgl_demo/src/hal/key.h b/rk_lvgl_demo/src/hal/key.h new file mode 100644 index 0000000..dc3110b --- /dev/null +++ b/rk_lvgl_demo/src/hal/key.h @@ -0,0 +1,58 @@ +/** + * @file key.h + * + */ + +#ifndef KEY_H +#define KEY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------- + * Mouse or touchpad as evdev interface (for Linux based systems) + *------------------------------------------------*/ +#define USE_KEY 0 + +#if USE_KEY +# define KEY_NAME "/dev/input/event2" + +#include "lvgl.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the evdev + */ +void key_init(void); + +/** + * Get the current position and state of the evdev + * @param data store the evdev data here + * @return false: because the points are not buffered, so no more data to be read + */ +void key_read(lv_indev_drv_t * drv, lv_indev_data_t * data); + + +/********************** + * MACROS + **********************/ + +#endif /* USE_KEY */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* KEY_H */ diff --git a/rk_lvgl_demo/src/lvgl/lv_port_disp.c b/rk_lvgl_demo/src/lvgl/lv_port_disp.c new file mode 100644 index 0000000..5f6ac8b --- /dev/null +++ b/rk_lvgl_demo/src/lvgl/lv_port_disp.c @@ -0,0 +1,287 @@ +/** + * @file lv_port_disp_templ.c + * + */ + + /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/ + +#include +#include +#include + +#include +#include + +#include "lv_port_disp.h" +#include "lvgl.h" + +#include "hal/drm_display.h" + +static int rot_disp = 90; +static int lcd_w; +static int lcd_h; +static int lcd_sw; +static char* drm_buff; +static lv_color_t *buf_1; + +//static struct timeval tvCbBegin; +//static struct timeval tvCbEnd; +static int quit = 0; +static pthread_t disp_thread_pid; +static pthread_mutex_t draw_mutex; +static int draw_update = 0; + +static void disp_init(void); + +static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); +//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width, +// const lv_area_t * fill_area, lv_color_t color); + +static void *disp_thread(void *arg) +{ + while (!quit) { + pthread_mutex_lock(&draw_mutex); + if (draw_update) { + struct drm_bo *bo = getdrmdisp(); + char *dst_buff = NULL; + getdrmdispbuff(&dst_buff); + draw_update = 0; + if (rot_disp == 90 || rot_disp == 270) { + rga_info_t src; + rga_info_t dst; + memset(&src, 0, sizeof(rga_info_t)); + memset(&dst, 0, sizeof(rga_info_t)); + src.virAddr = drm_buff; + //src.fd = RK_MPI_MB_GetFD(mb1); + src.fd = -1; + src.mmuFlag = 1; + //dst.fd = bo->fb_id; + dst.fd = -1; + dst.virAddr = dst_buff; + dst.mmuFlag = 1; + //printf("%d, %d, %d, %d\n", stImageInfo.u32Width, stImageInfo.u32Height, stImageInfo.u32HorStride, stImageInfo.u32VerStride); + rga_set_rect(&src.rect, 0, 0, lcd_h, lcd_w, lcd_h, lcd_w, RK_FORMAT_BGRA_8888); + src.rotation = HAL_TRANSFORM_ROT_90; + //src.blend = 0xff0405; + rga_set_rect(&dst.rect, 0, 0, lcd_w, lcd_h, lcd_sw, lcd_h, RK_FORMAT_BGRA_8888); + + int ret = c_RkRgaBlit(&src, &dst, NULL); + if (ret) + printf("c_RkRgaBlit2 error : %s\n", strerror(errno)); + } else { +#if 0 + memcpy(dst_buff, drm_buff, lcd_w * lcd_h * 4); +#else + rga_info_t src; + rga_info_t dst; + memset(&src, 0, sizeof(rga_info_t)); + memset(&dst, 0, sizeof(rga_info_t)); + src.virAddr = drm_buff; + //src.fd = RK_MPI_MB_GetFD(mb1); + src.mmuFlag = 1; + //dst.fd = bo->fb_id; + dst.virAddr = dst_buff; + dst.mmuFlag = 1; + //printf("%d, %d, %d, %d\n", stImageInfo.u32Width, stImageInfo.u32Height, stImageInfo.u32HorStride, stImageInfo.u32VerStride); + rga_set_rect(&src.rect, 0, 0, lcd_w, lcd_h, lcd_w, lcd_h, RK_FORMAT_BGRA_8888); + //src.rotation = HAL_TRANSFORM_ROT_90; + //src.blend = 0xff0105; + rga_set_rect(&dst.rect, 0, 0, lcd_w, lcd_h, lcd_sw, lcd_h, RK_FORMAT_BGRA_8888); + + int ret = c_RkRgaBlit(&src, &dst, NULL); + if (ret) + printf("c_RkRgaBlit2 error : %s\n", strerror(errno)); +#endif + } + pthread_mutex_unlock(&draw_mutex); + setdrmdisp(bo); + } else { + pthread_mutex_unlock(&draw_mutex); + } + usleep(17000); + } + return NULL; +} + +void lv_port_disp_init(int rot) +{ + rot_disp = rot; + /*------------------------- + * Initialize your display + * -----------------------*/ + disp_init(); + + /*----------------------------- + * Create a buffer for drawing + *----------------------------*/ + + /** + * LVGL requires a buffer where it internally draws the widgets. + * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display. + * The buffer has to be greater than 1 display row + * + * There are 3 buffering configurations: + * 1. Create ONE buffer: + * LVGL will draw the display's content here and writes it to your display + * + * 2. Create TWO buffer: + * LVGL will draw the display's content to a buffer and writes it your display. + * You should use DMA to write the buffer's content to the display. + * It will enable LVGL to draw the next part of the screen to the other buffer while + * the data is being sent form the first buffer. It makes rendering and flushing parallel. + * + * 3. Double buffering + * Set 2 screens sized buffers and set disp_drv.full_refresh = 1. + * This way LVGL will always provide the whole rendered screen in `flush_cb` + * and you only need to change the frame buffer's address. + */ + + /* Example for 1) */ + static lv_disp_draw_buf_t draw_buf_dsc_1; + buf_1 = malloc(lcd_w * lcd_h * 4); + + lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, lcd_w * lcd_h); /*Initialize the display buffer*/ + + /*----------------------------------- + * Register the display in LVGL + *----------------------------------*/ + + static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + + /*Set up the functions to access to your display*/ + + /*Set the resolution of the display*/ + if (rot_disp == 0) { + disp_drv.hor_res = lcd_w; + disp_drv.ver_res = lcd_h; + + disp_drv.sw_rotate = 0; + disp_drv.rotated = LV_DISP_ROT_NONE; + } else if (rot_disp == 180) { + disp_drv.hor_res = lcd_w; + disp_drv.ver_res = lcd_h; + + disp_drv.sw_rotate = 1; + disp_drv.rotated = LV_DISP_ROT_180; + } else if (rot_disp == 90) { + disp_drv.hor_res = lcd_h; + disp_drv.ver_res = lcd_w; + + disp_drv.sw_rotate = 0; + disp_drv.rotated = LV_DISP_ROT_NONE; + } else if (rot_disp == 270) { + disp_drv.hor_res = lcd_h; + disp_drv.ver_res = lcd_w; + + disp_drv.sw_rotate = 1; + disp_drv.rotated = LV_DISP_ROT_180; + } + /*Used to copy the buffer's content to the display*/ + disp_drv.flush_cb = disp_flush; + + /*Set a display buffer*/ + disp_drv.draw_buf = &draw_buf_dsc_1; + + /*Required for Example 3)*/ + //disp_drv.full_refresh = 1 + + /* Fill a memory array with a color if you have GPU. + * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL. + * But if you have a different GPU you can use with this callback.*/ + //disp_drv.gpu_fill_cb = gpu_fill; + + /*Finally register the driver*/ + lv_disp_drv_register(&disp_drv); + pthread_mutex_init(&draw_mutex, NULL); + pthread_create(&disp_thread_pid, NULL, disp_thread, NULL); +} + +/*Initialize your display and the required peripherals.*/ +static void disp_init(void) +{ + /*You code here*/ + drm_init(32, rot_disp); + getdrmresolve(&lcd_w, &lcd_h); + lcd_sw = getdrmwstride(); + drm_buff = malloc(lcd_w * lcd_h * 4); +} + +/*Flush the content of the internal buffer the specific area on the display + *You can use DMA or any hardware acceleration to do this operation in the background but + *'lv_disp_flush_ready()' has to be called when finished.*/ +static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) +{ + /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ + int32_t x; + int32_t y; + + //printf("%s, x1 = %d, y1 = %d, x2 = %d, y2 = %d, %d, %d\n\n\n", __func__, area->x1, area->y1, area->x2, area->y2, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1); + //gettimeofday(&tvCbBegin, NULL); + pthread_mutex_lock(&draw_mutex); + if (rot_disp == 90 || rot_disp == 270) { + for(y = area->y1; y <= area->y2; y++) { + int area_w = area->x2 - area->x1 + 1; + lv_color_t *disp = (lv_color_t*)(drm_buff + (y * lcd_h + area->x1) * 4); + memcpy(disp, color_p, area_w * 4); + color_p += area_w; + } + } else { +#if 1 + for(y = area->y1; y <= area->y2; y++) { + int area_w = area->x2 - area->x1 + 1; + lv_color_t *disp = (lv_color_t*)(drm_buff + (y * lcd_w + area->x1) * 4); + memcpy(disp, color_p, area_w * 4); + color_p += area_w; + } +#else + rga_info_t src; + rga_info_t dst; + int area_w = area->x2 - area->x1 + 1; + int area_h = area->y2 - area->y1 + 1; + memset(&src, 0, sizeof(rga_info_t)); + memset(&dst, 0, sizeof(rga_info_t)); + src.virAddr = color_p; + //src.fd = RK_MPI_MB_GetFD(mb1); + src.mmuFlag = 1; + //dst.fd = bo->fb_id; + dst.virAddr = drm_buff; + dst.mmuFlag = 1; + //printf("%d, %d, %d, %d\n", stImageInfo.u32Width, stImageInfo.u32Height, stImageInfo.u32HorStride, stImageInfo.u32VerStride); + rga_set_rect(&src.rect, 0, 0, area_w, area_h, area_w, area_h, RK_FORMAT_RGBA_8888); + //src.rotation = HAL_TRANSFORM_ROT_90; + //src.blend = 0xff0105; + rga_set_rect(&dst.rect, area->x1, area->y1, area_w, area_h, lcd_w, lcd_h, RK_FORMAT_RGBA_8888); + + int ret = c_RkRgaBlit(&src, &dst, NULL); + if (ret) + printf("c_RkRgaBlit2 error : %s\n", strerror(errno)); +#endif + } + draw_update = 1; + pthread_mutex_unlock(&draw_mutex); + //gettimeofday(&tvCbEnd, NULL); + //double dDuration = 1000 * (tvCbEnd.tv_sec - tvCbBegin.tv_sec) + ((tvCbEnd.tv_usec - tvCbBegin.tv_usec) / 1000.0); + //printf("%s dDuration = %f\n", __func__, dDuration); + /*IMPORTANT!!! + *Inform the graphics library that you are ready with the flushing*/ + lv_disp_flush_ready(disp_drv); +} + +/*OPTIONAL: GPU INTERFACE*/ + +/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/ +//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width, +// const lv_area_t * fill_area, lv_color_t color) +//{ +// /*It's an example code which should be done by your GPU*/ +// int32_t x, y; +// dest_buf += dest_width * fill_area->y1; /*Go to the first line*/ +// +// for(y = fill_area->y1; y <= fill_area->y2; y++) { +// for(x = fill_area->x1; x <= fill_area->x2; x++) { +// dest_buf[x] = color; +// } +// dest_buf+=dest_width; /*Go to the next line*/ +// } +//} \ No newline at end of file diff --git a/rk_lvgl_demo/src/lvgl/lv_port_disp.h b/rk_lvgl_demo/src/lvgl/lv_port_disp.h new file mode 100644 index 0000000..2c9bfe8 --- /dev/null +++ b/rk_lvgl_demo/src/lvgl/lv_port_disp.h @@ -0,0 +1,21 @@ +/** + * @file lv_port_disp_templ.h + * + */ + + /*Copy this file as "lv_port_disp.h" and set this value to "1" to enable content*/ + +#ifndef LV_PORT_DISP_TEMPL_H +#define LV_PORT_DISP_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +void lv_port_disp_init(int rot); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_PORT_DISP_TEMPL_H*/ diff --git a/rk_lvgl_demo/src/lvgl/lv_port_indev.c b/rk_lvgl_demo/src/lvgl/lv_port_indev.c new file mode 100644 index 0000000..ea519fb --- /dev/null +++ b/rk_lvgl_demo/src/lvgl/lv_port_indev.c @@ -0,0 +1,116 @@ +/** + * @file lv_port_indev_templ.c + * + */ + + /* Copy this file as "lv_port_indev.c" and set this value to "1" to enable conten */ + +#include "lvgl.h" +#include "lv_port_indev.h" + +#include "hal/evdev.h" +#include "hal/key.h" + +typedef struct _GROUP_NODE { + struct _GROUP_NODE *next; + lv_group_t *group; +} GROUP_NODE; + +static int rot_indev; +lv_indev_t * indev_touchpad; +lv_indev_t * indev_key; + +GROUP_NODE *group_list = NULL; + +lv_group_t *lv_port_indev_group_create(void) +{ + struct _GROUP_NODE *group_node = NULL; + lv_group_t *group = lv_group_create(); + + lv_indev_set_group(indev_key, group); + lv_group_set_default(group); + + group_node = (struct _GROUP_NODE *)malloc(sizeof(struct _GROUP_NODE)); + group_node->group = group; + group_node->next = NULL; + if (group_list) { + group_node->next = group_list; + group_list = group_node; + } else { + group_list = group_node; + } + + return group; +} + +void lv_port_indev_group_destroy(lv_group_t *group) +{ + if (group_list) { + struct _GROUP_NODE *group_node = NULL; + group_node = group_list; + if (group_list->group == group) { + group_list = group_list->next; + if (group_list) { + lv_indev_set_group(indev_key, group_list->group); + lv_group_set_default(group_list->group); + } else { + lv_indev_set_group(indev_key, NULL); + lv_group_set_default(NULL); + } + free(group_node); + } else { + while (group_node->next) { + struct _GROUP_NODE *group_node_next = group_node->next; + if (group_node_next->group == group) { + group_node->next = group_node_next->next; + free(group_node_next); + break; + } + group_node = group_node->next; + } + } + lv_group_del(group); + } +} + +void lv_port_indev_init(int rot) +{ + /** + * Here you will find example implementation of input devices supported by LittelvGL: + * - Touchpad + * - Mouse (with cursor support) + * - Keypad (supports GUI usage only with key) + * - Encoder (supports GUI usage only with: left, right, push) + * - Button (external buttons to press points on the screen) + * + * The `..._read()` function are only examples. + * You should shape them according to your hardware + */ + + static lv_indev_drv_t indev_drv; + static lv_indev_drv_t key_drv; + + rot_indev = rot; + + /*------------------ + * Touchpad + * -----------------*/ + + /*Initialize your touchpad if you have*/ + evdev_init(rot); + + /*Register a touchpad input device*/ + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read_cb = evdev_read; + indev_touchpad = lv_indev_drv_register(&indev_drv); + +#if USE_KEY + key_init(); + lv_indev_drv_init(&key_drv); + key_drv.type = LV_INDEV_TYPE_KEYPAD; + key_drv.read_cb = key_read; + indev_key = lv_indev_drv_register(&key_drv); + lv_port_indev_group_create(); +#endif +} diff --git a/rk_lvgl_demo/src/lvgl/lv_port_indev.h b/rk_lvgl_demo/src/lvgl/lv_port_indev.h new file mode 100644 index 0000000..3d9c54b --- /dev/null +++ b/rk_lvgl_demo/src/lvgl/lv_port_indev.h @@ -0,0 +1,27 @@ + +/** + * @file lv_port_indev_templ.h + * + */ + + /*Copy this file as "lv_port_indev.h" and set this value to "1" to enable content*/ +#if 1 + +#ifndef LV_PORT_INDEV_TEMPL_H +#define LV_PORT_INDEV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +void lv_port_indev_init(int rot); +lv_group_t *lv_port_indev_group_create(void); +void lv_port_indev_group_destroy(lv_group_t *group); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_PORT_INDEV_TEMPL_H*/ + +#endif /*Disable/Enable content*/ diff --git a/rk_lvgl_demo/src/ui/demo.c b/rk_lvgl_demo/src/ui/demo.c new file mode 100644 index 0000000..174b08f --- /dev/null +++ b/rk_lvgl_demo/src/ui/demo.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +#include "lvgl.h" +#include "../../../demos/music/lv_demo_music.h" + +void demo_start(void) +{ + lv_demo_music(); +} + +void demo_stop(void) +{ + +} \ No newline at end of file diff --git a/rk_lvgl_demo/src/ui/demo.h b/rk_lvgl_demo/src/ui/demo.h new file mode 100644 index 0000000..1ffa602 --- /dev/null +++ b/rk_lvgl_demo/src/ui/demo.h @@ -0,0 +1,7 @@ +#ifndef __DEMO_H__ +#define __DEMO_H__ + +void demo_start(void); +void demo_start(void); + +#endif -- 2.7.4