Update to LVGL 9.0.0 (#47)

- Updated LVGL from 8.3 to 9.0 (removed example/docs/demo folders)
- Updated esp_lvgl_port  to current status of the `lvgl9` branch on `esp-bsp`: https://github.com/espressif/esp-bsp/tree/lvgl9
- Updated all boards and drivers
- Removed `libs/lv_drivers` subproject as SDL is now supported by LVGL directly (although keyboard input seems broken)
- Updated `libs/lv_screenshot`
- Fixed the way `tt_statusbar` widget works due to behaviour change in LVGL
- Updated other lvgl code
This commit is contained in:
Ken Van Hoeylandt 2024-02-18 17:40:02 +01:00 committed by GitHub
parent 5fef25fb13
commit 473fb673bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1630 changed files with 142517 additions and 182264 deletions

View File

@ -65,8 +65,6 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION})
PUBLIC app-sim/src # for lv_conf.h and lv_drv_conf.h
)
add_subdirectory(libs/lv_drivers)
option(LV_USE_DRAW_SDL "Use SDL draw unit" OFF)
option(LV_USE_LIBPNG "Use libpng to decode PNG" OFF)
option(LV_USE_LIBJPEG_TURBO "Use libjpeg turbo to decode JPEG" OFF)

View File

@ -6,7 +6,6 @@ target_link_libraries(app-sim
PRIVATE tactility
PRIVATE tactility-core
PRIVATE lvgl
PRIVATE lv_drivers
)
find_package(SDL2 REQUIRED CONFIG)

View File

@ -1,6 +1,6 @@
#include "hardware_config.h"
#include "lvgl_task.h"
#include <src/core/lv_obj.h>
#include "src/lv_init.h"
#include <stdbool.h>
#define TAG "hardware"

File diff suppressed because it is too large Load Diff

View File

@ -1,496 +0,0 @@
/**
* @file lv_drv_conf.h
* Configuration file for v8.3.0-dev
*/
/*
* COPY THIS FILE AS lv_drv_conf.h
*/
/* clang-format off */
#if 1 /*Set it to "1" to enable the content*/
#ifndef LV_DRV_CONF_H
#define LV_DRV_CONF_H
#include "lv_conf.h"
/*********************
* DELAY INTERFACE
*********************/
#define LV_DRV_DELAY_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/
#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/
/*********************
* DISPLAY INTERFACE
*********************/
/*------------
* Common
*------------*/
#define LV_DRV_DISP_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/
#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
/*---------
* SPI
*---------*/
#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/
/*------------------
* Parallel port
*-----------------*/
#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/
#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/
#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/
#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/
/***************************
* INPUT DEVICE INTERFACE
***************************/
/*----------
* Common
*----------*/
#define LV_DRV_INDEV_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/
/*---------
* SPI
*---------*/
#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/
/*---------
* I2C
*---------*/
#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/
#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/
#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/
#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/
#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/
/*********************
* DISPLAY DRIVERS
*********************/
/*-------------------
* SDL
*-------------------*/
/* SDL based drivers for display, mouse, mousewheel and keyboard*/
#ifndef USE_SDL
# define USE_SDL 1
#endif
/* Hardware accelerated SDL driver */
#ifndef USE_SDL_GPU
# define USE_SDL_GPU 0
#endif
#define SDL_WINDOW_NAME "Tactility"
#if USE_SDL || USE_SDL_GPU
# define SDL_HOR_RES 320
# define SDL_VER_RES 240
/* Scale window by this factor (useful when simulating small screens) */
# define SDL_ZOOM 1
/* Used to test true double buffering with only address changing.
* Use 2 draw buffers, bith with SDL_HOR_RES x SDL_VER_RES size*/
# define SDL_DOUBLE_BUFFERED 0
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
# define SDL_INCLUDE_PATH <SDL2/SDL.h>
/*Open two windows to test multi display support*/
# define SDL_DUAL_DISPLAY 0
#endif
/*-------------------
* Monitor of PC
*-------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_MONITOR
# define USE_MONITOR 0
#endif
#if USE_MONITOR
# define MONITOR_HOR_RES 480
# define MONITOR_VER_RES 320
/* Scale window by this factor (useful when simulating small screens) */
# define MONITOR_ZOOM 1
/* Used to test true double buffering with only address changing.
* Use 2 draw buffers, bith with MONITOR_HOR_RES x MONITOR_VER_RES size*/
# define MONITOR_DOUBLE_BUFFERED 0
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
/*Open two windows to test multi display support*/
# define MONITOR_DUAL 0
#endif
/*-----------------------------------
* Native Windows (including mouse)
*----------------------------------*/
#ifndef USE_WINDOWS
# define USE_WINDOWS 0
#endif
#if USE_WINDOWS
# define WINDOW_HOR_RES 480
# define WINDOW_VER_RES 320
#endif
/*----------------------------
* Native Windows (win32drv)
*---------------------------*/
#ifndef USE_WIN32DRV
# define USE_WIN32DRV 0
#endif
#if USE_WIN32DRV
/* Scale window by this factor (useful when simulating small screens) */
# define WIN32DRV_MONITOR_ZOOM 1
#endif
/*----------------------------------------
* GTK drivers (monitor, mouse, keyboard
*---------------------------------------*/
#ifndef USE_GTK
# define USE_GTK 0
#endif
/*----------------------------------------
* Wayland drivers (monitor, mouse, keyboard, touchscreen)
*---------------------------------------*/
#ifndef USE_WAYLAND
# define USE_WAYLAND 0
#endif
#if USE_WAYLAND
/* Support for client-side decorations */
# ifndef LV_WAYLAND_CLIENT_SIDE_DECORATIONS
# define LV_WAYLAND_CLIENT_SIDE_DECORATIONS 1
# endif
/* Support for (deprecated) wl-shell protocol */
# ifndef LV_WAYLAND_WL_SHELL
# define LV_WAYLAND_WL_SHELL 1
# endif
/* Support for xdg-shell protocol */
# ifndef LV_WAYLAND_XDG_SHELL
# define LV_WAYLAND_XDG_SHELL 0
# endif
#endif
/*----------------
* SSD1963
*--------------*/
#ifndef USE_SSD1963
# define USE_SSD1963 0
#endif
#if USE_SSD1963
# define SSD1963_HOR_RES LV_HOR_RES
# define SSD1963_VER_RES LV_VER_RES
# define SSD1963_HT 531
# define SSD1963_HPS 43
# define SSD1963_LPS 8
# define SSD1963_HPW 10
# define SSD1963_VT 288
# define SSD1963_VPS 12
# define SSD1963_FPS 4
# define SSD1963_VPW 10
# define SSD1963_HS_NEG 0 /*Negative hsync*/
# define SSD1963_VS_NEG 0 /*Negative vsync*/
# define SSD1963_ORI 0 /*0, 90, 180, 270*/
# define SSD1963_COLOR_DEPTH 16
#endif
/*----------------
* R61581
*--------------*/
#ifndef USE_R61581
# define USE_R61581 0
#endif
#if USE_R61581
# define R61581_HOR_RES LV_HOR_RES
# define R61581_VER_RES LV_VER_RES
# define R61581_HSPL 0 /*HSYNC signal polarity*/
# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/
# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/
# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */
# define R61581_VSPL 0 /*VSYNC signal polarity*/
# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/
# define R61581_VFP 8 /*Vertical Front poarch*/
# define R61581_VBP 8 /*Vertical Back poarch */
# define R61581_DPL 0 /*DCLK signal polarity*/
# define R61581_EPL 1 /*ENABLE signal polarity*/
# define R61581_ORI 0 /*0, 180*/
# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/
#endif
/*------------------------------
* ST7565 (Monochrome, low res.)
*-----------------------------*/
#ifndef USE_ST7565
# define USE_ST7565 0
#endif
#if USE_ST7565
/*No settings*/
#endif /*USE_ST7565*/
/*------------------------------
* GC9A01 (color, low res.)
*-----------------------------*/
#ifndef USE_GC9A01
# define USE_GC9A01 0
#endif
#if USE_GC9A01
/*No settings*/
#endif /*USE_GC9A01*/
/*------------------------------------------
* UC1610 (4 gray 160*[104|128])
* (EA DOGXL160 160x104 tested)
*-----------------------------------------*/
#ifndef USE_UC1610
# define USE_UC1610 0
#endif
#if USE_UC1610
# define UC1610_HOR_RES LV_HOR_RES
# define UC1610_VER_RES LV_VER_RES
# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */
# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */
# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */
#endif /*USE_UC1610*/
/*-------------------------------------------------
* SHARP memory in pixel monochrome display series
* LS012B7DD01 (184x38 pixels.)
* LS013B7DH03 (128x128 pixels.)
* LS013B7DH05 (144x168 pixels.)
* LS027B7DH01 (400x240 pixels.) (tested)
* LS032B7DD02 (336x536 pixels.)
* LS044Q7DH01 (320x240 pixels.)
*------------------------------------------------*/
#ifndef USE_SHARP_MIP
# define USE_SHARP_MIP 0
#endif
#if USE_SHARP_MIP
# define SHARP_MIP_HOR_RES LV_HOR_RES
# define SHARP_MIP_VER_RES LV_VER_RES
# define SHARP_MIP_SOFT_COM_INVERSION 0
# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/
#endif /*USE_SHARP_MIP*/
/*-------------------------------------------------
* ILI9341 240X320 TFT LCD
*------------------------------------------------*/
#ifndef USE_ILI9341
# define USE_ILI9341 0
#endif
#if USE_ILI9341
# define ILI9341_HOR_RES LV_HOR_RES
# define ILI9341_VER_RES LV_VER_RES
# define ILI9341_GAMMA 1
# define ILI9341_TEARING 0
#endif /*USE_ILI9341*/
/*-----------------------------------------
* Linux frame buffer device (/dev/fbx)
*-----------------------------------------*/
#ifndef USE_FBDEV
# define USE_FBDEV 0
#endif
#if USE_FBDEV
# define FBDEV_PATH "/dev/fb0"
#endif
/*-----------------------------------------
* FreeBSD frame buffer device (/dev/fbx)
*.........................................*/
#ifndef USE_BSD_FBDEV
# define USE_BSD_FBDEV 0
#endif
#if USE_BSD_FBDEV
# define FBDEV_PATH "/dev/fb0"
#endif
/*-----------------------------------------
* DRM/KMS device (/dev/dri/cardX)
*-----------------------------------------*/
#ifndef USE_DRM
# define USE_DRM 0
#endif
#if USE_DRM
# define DRM_CARD "/dev/dri/card0"
# define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */
#endif
/*********************
* INPUT DEVICES
*********************/
/*--------------
* XPT2046
*--------------*/
#ifndef USE_XPT2046
# define USE_XPT2046 0
#endif
#if USE_XPT2046
# define XPT2046_HOR_RES 480
# define XPT2046_VER_RES 320
# define XPT2046_X_MIN 200
# define XPT2046_Y_MIN 200
# define XPT2046_X_MAX 3800
# define XPT2046_Y_MAX 3800
# define XPT2046_AVG 4
# define XPT2046_X_INV 0
# define XPT2046_Y_INV 0
# define XPT2046_XY_SWAP 0
#endif
/*-----------------
* FT5406EE8
*-----------------*/
#ifndef USE_FT5406EE8
# define USE_FT5406EE8 0
#endif
#if USE_FT5406EE8
# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/
#endif
/*---------------
* AD TOUCH
*--------------*/
#ifndef USE_AD_TOUCH
# define USE_AD_TOUCH 0
#endif
#if USE_AD_TOUCH
/*No settings*/
#endif
/*---------------------------------------
* Mouse or touchpad on PC (using SDL)
*-------------------------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_MOUSE
# define USE_MOUSE 0
#endif
#if USE_MOUSE
/*No settings*/
#endif
/*-------------------------------------------
* Mousewheel as encoder on PC (using SDL)
*------------------------------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_MOUSEWHEEL
# define USE_MOUSEWHEEL 0
#endif
#if USE_MOUSEWHEEL
/*No settings*/
#endif
/*-------------------------------------------------
* Touchscreen, mouse/touchpad or keyboard as libinput interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_LIBINPUT
# define USE_LIBINPUT 0
#endif
#ifndef USE_BSD_LIBINPUT
# define USE_BSD_LIBINPUT 0
#endif
#if USE_LIBINPUT || USE_BSD_LIBINPUT
/*If only a single device of the same type is connected, you can also auto detect it, e.g.:
*#define LIBINPUT_NAME libinput_find_dev(LIBINPUT_CAPABILITY_TOUCH, false)*/
# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT*/
/*-------------------------------------------------
* Mouse or touchpad as evdev interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_EVDEV
# define USE_EVDEV 0
#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*/
/*-------------------------------------------------
* Full keyboard support for evdev and libinput interface
*------------------------------------------------*/
# ifndef USE_XKB
# define USE_XKB 0
# endif
#if USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV
# if USE_XKB
# define XKB_KEY_MAP { .rules = NULL, \
.model = "pc101", \
.layout = "us", \
.variant = NULL, \
.options = NULL } /*"setxkbmap -query" can help find the right values for your keyboard*/
# endif /*USE_XKB*/
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV*/
/*-------------------------------
* Keyboard of a PC (using SDL)
*------------------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_KEYBOARD
# define USE_KEYBOARD 0
#endif
#if USE_KEYBOARD
/*No settings*/
#endif
#endif /*LV_DRV_CONF_H*/
#endif /*End of "Content enable"*/

View File

@ -1,68 +1,15 @@
#include "lvgl.h"
#include "tactility_core.h"
#include <sdl/sdl.h>
#include "ui/lvgl_keypad.h"
#define TAG "lvgl_hal"
lv_display_t* lvgl_hal_init() {
static lv_display_t* display = NULL;
static lv_indev_t* mouse = NULL;
static lv_indev_t* keyboard = NULL;
#define BUFFER_SIZE (SDL_HOR_RES * SDL_VER_RES * 3)
lv_disp_t* lvgl_hal_init() {
// Use the 'monitor' driver to simulate a display on PC
// Note: this is part of lv_drivers and not SDL!
sdl_init();
// Create display buffer
static lv_disp_draw_buf_t disp_buf1;
static lv_color_t buf1_1[BUFFER_SIZE];
lv_disp_draw_buf_init(&disp_buf1, buf1_1, NULL, BUFFER_SIZE);
// Create display
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.draw_buf = &disp_buf1;
disp_drv.flush_cb = sdl_display_flush;
disp_drv.hor_res = SDL_HOR_RES;
disp_drv.ver_res = SDL_VER_RES;
lv_disp_t* display = lv_disp_drv_register(&disp_drv);
lv_theme_t* theme = lv_theme_default_init(
display,
lv_palette_main(LV_PALETTE_BLUE),
lv_palette_main(LV_PALETTE_RED),
LV_THEME_DEFAULT_DARK,
LV_FONT_DEFAULT
);
lv_disp_set_theme(display, theme);
lv_group_t* group = lv_group_create();
lv_group_set_default(group);
/* Add the mouse as input device
* Use the 'mouse' driver which reads the PC's mouse*/
static lv_indev_drv_t indev_drv_1;
lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
indev_drv_1.type = LV_INDEV_TYPE_POINTER;
/*This function will be called periodically (by the library) to get the mouse position and state*/
indev_drv_1.read_cb = sdl_mouse_read;
lv_indev_t* mouse_indev = lv_indev_drv_register(&indev_drv_1);
static lv_indev_drv_t indev_drv_2;
lv_indev_drv_init(&indev_drv_2); /*Basic initialization*/
indev_drv_2.type = LV_INDEV_TYPE_KEYPAD;
indev_drv_2.read_cb = sdl_keyboard_read;
lv_indev_t* kb_indev = lv_indev_drv_register(&indev_drv_2);
lv_indev_set_group(kb_indev, group);
static lv_indev_drv_t indev_drv_3;
lv_indev_drv_init(&indev_drv_3); /*Basic initialization*/
indev_drv_3.type = LV_INDEV_TYPE_ENCODER;
indev_drv_3.read_cb = sdl_mousewheel_read;
lv_indev_t* enc_indev = lv_indev_drv_register(&indev_drv_3);
lv_indev_set_group(enc_indev, group);
display = lv_sdl_window_create(320, 240);
mouse = lv_sdl_mouse_create();
keyboard = lv_sdl_keyboard_create();
tt_lvgl_keypad_set_indev(keyboard);
return display;
}

View File

@ -7,7 +7,7 @@
extern "C" {
#endif
lv_disp_t* lvgl_hal_init();
lv_display_t* lvgl_hal_init();
#ifdef __cplusplus
}

View File

@ -44,7 +44,7 @@ void tdeck_backlight_set(uint8_t duty) {
}
}
lv_disp_t* tdeck_display_init() {
lv_display_t* tdeck_display_init() {
const esp_lcd_panel_io_spi_config_t panel_io_config = {
.cs_gpio_num = TDECK_LCD_PIN_CS,
.dc_gpio_num = TDECK_LCD_PIN_DC,
@ -134,10 +134,12 @@ lv_disp_t* tdeck_display_init() {
.flags = {
.buff_dma = false,
.buff_spiram = true,
.sw_rotate = false,
.swap_bytes = true
}
};
lv_disp_t* display = lvgl_port_add_disp(&disp_cfg);
lv_display_t* display = lvgl_port_add_disp(&disp_cfg);
return display;
}

View File

@ -1,13 +1,13 @@
#pragma once
#include "hal/lv_hal_disp.h"
#include "lvgl.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
lv_disp_t* tdeck_display_init();
lv_display_t* tdeck_display_init();
bool tdeck_backlight_init();

View File

@ -1,6 +1,6 @@
#include "keyboard.h"
#include "config.h"
#include "hal/lv_hal.h"
#include "lvgl.h"
#include "tactility_core.h"
#include "ui/lvgl_keypad.h"
#include <driver/i2c.h>
@ -8,7 +8,6 @@
#define TAG "tdeck_keyboard"
typedef struct {
lv_indev_drv_t* driver;
lv_indev_t* device;
} KeyboardData;
@ -44,7 +43,7 @@ void keyboard_wait_for_response() {
* @param indev_drv
* @param data
*/
static void keyboard_read_callback(TT_UNUSED struct _lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
static void keyboard_read_callback(TT_UNUSED lv_indev_t* indev, lv_indev_data_t* data) {
static uint8_t last_buffer = 0x00;
uint8_t read_buffer = 0x00;
@ -70,16 +69,10 @@ static void keyboard_read_callback(TT_UNUSED struct _lv_indev_drv_t* indev_drv,
Keyboard keyboard_alloc(_Nullable lv_disp_t* display) {
KeyboardData* data = malloc(sizeof(KeyboardData));
data->driver = malloc(sizeof(lv_indev_drv_t));
memset(data->driver, 0, sizeof(lv_indev_drv_t));
lv_indev_drv_init(data->driver);
data->driver->type = LV_INDEV_TYPE_KEYPAD;
data->driver->read_cb = &keyboard_read_callback;
data->driver->disp = display;
data->device = lv_indev_drv_register(data->driver);
tt_check(data->device != NULL);
data->device = lv_indev_create();
lv_indev_set_type(data->device, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(data->device, &keyboard_read_callback);
lv_indev_set_display(data->device, display);
tt_lvgl_keypad_set_indev(data->device);
@ -89,6 +82,5 @@ Keyboard keyboard_alloc(_Nullable lv_disp_t* display) {
void keyboard_free(Keyboard keyboard) {
KeyboardData* data = (KeyboardData*)keyboard;
lv_indev_delete(data->device);
free(data->driver);
free(data);
}

View File

@ -29,7 +29,6 @@
#define WAVESHARE_LCD_PIN_NUM_DATA15 40 // R7
#define WAVESHARE_LCD_PIN_NUM_DISP_EN (-1)
#define WAVESHARE_LCD_BUFFER_HEIGHT (WAVESHARE_LCD_VER_RES / 3) // How many rows of pixels to buffer - 1/3rd is about 1MB
#define WAVESHARE_LCD_BUFFER_SIZE (WAVESHARE_LCD_HOR_RES * WAVESHARE_LCD_BUFFER_HEIGHT * sizeof(lv_color_t))
#define WAVESHARE_LCD_USE_DOUBLE_FB true // Performance boost at the cost of about extra PSRAM(SPIRAM)

View File

@ -81,8 +81,8 @@ static void lvgl_tick_task(TT_UNUSED void* arg) {
lv_tick_inc(WAVESHARE_LVGL_TICK_PERIOD_MS);
}
static void display_flush_callback(lv_disp_drv_t* drv, const lv_area_t* area, lv_color_t* color_map) {
esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data;
static void display_flush_callback(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map) {
esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)lv_display_get_user_data(disp);
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
@ -90,14 +90,12 @@ static void display_flush_callback(lv_disp_drv_t* drv, const lv_area_t* area, lv
xSemaphoreGive(sem_gui_ready);
xSemaphoreTake(sem_vsync_end, portMAX_DELAY);
// pass the draw buffer to the driver
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
lv_disp_flush_ready(drv);
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map);
lv_disp_flush_ready(disp);
}
lv_disp_t* ws3t_display_create() {
TT_LOG_I(TAG, "display init");
static lv_disp_drv_t display_driver;
static lv_disp_draw_buf_t display_buffer;
sem_vsync_end = xSemaphoreCreateBinary();
tt_assert(sem_vsync_end);
@ -151,7 +149,7 @@ lv_disp_t* ws3t_display_create() {
.on_bounce_empty = NULL,
.on_bounce_frame_finish = NULL
};
if (esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, &display_driver) != ESP_OK) {
if (esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, NULL) != ESP_OK) {
TT_LOG_E(TAG, "Failed to register callbacks");
return NULL;
}
@ -170,33 +168,23 @@ lv_disp_t* ws3t_display_create() {
NULL;
#if WAVESHARE_LCD_USE_DOUBLE_FB
void* buffer1 = heap_caps_malloc(WAVESHARE_LCD_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
void* buffer2 = heap_caps_malloc(WAVESHARE_LCD_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
// initialize LVGL draw buffers
lv_draw_buf_t* buffer1 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_BUFFER_HEIGHT, LV_COLOR_FORMAT_RGB565, 0);
lv_draw_buf_t* buffer2 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_BUFFER_HEIGHT, LV_COLOR_FORMAT_RGB565, 0);
tt_assert(buffer1);
tt_assert(buffer2);
// initialize LVGL draw buffers
lv_disp_draw_buf_init(&display_buffer, buffer1, buffer2, WAVESHARE_LCD_HOR_RES * WAVESHARE_LCD_BUFFER_HEIGHT);
#else
ESP_LOGI(TAG, "Allocate separate LVGL draw buffers from PSRAM");
void* buffer = heap_caps_malloc(WAVESHARE_LCD_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
tt_assert(buffer);
lv_disp_draw_buf_init(&display_buffer, buffer, NULL, WAVESHARE_LCD_H_RES * WAVESHARE_BUFFER_HEIGHT);
lv_draw_buf_t* buffer1 = lv_draw_buf_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_VER_RES, LV_COLOR_FORMAT_RGB565, 0);
lv_draw_buf_t* buffer2 = NULL;
tt_assert(buffer1);
#endif // WAVESHARE_USE_DOUBLE_FB
lv_disp_drv_init(&display_driver);
display_driver.hor_res = WAVESHARE_LCD_HOR_RES;
display_driver.ver_res = WAVESHARE_LCD_VER_RES;
display_driver.flush_cb = display_flush_callback;
display_driver.draw_buf = &display_buffer;
display_driver.user_data = panel_handle;
display_driver.antialiasing = false;
display_driver.direct_mode = false;
display_driver.sw_rotate = false;
display_driver.rotated = 0;
display_driver.screen_transp = false;
display_driver.full_refresh = WAVESHARE_LCD_USE_DOUBLE_FB; // Maintains the synchronization between the two frame buffers
lv_disp_t* display = lv_disp_drv_register(&display_driver);
lv_display_t* display = lv_display_create(WAVESHARE_LCD_HOR_RES, WAVESHARE_LCD_VER_RES);
lv_display_set_draw_buffers(display, buffer1, buffer2);
lv_display_set_flush_cb(display, &display_flush_callback);
lv_display_set_user_data(display, panel_handle);
lv_display_set_antialiasing(display, false);
lv_display_set_render_mode(display, LV_DISPLAY_RENDER_MODE_PARTIAL);
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_tick_task,

View File

@ -1,6 +1,6 @@
#pragma once
#include "hal/lv_hal_disp.h"
#include "lvgl.h"
#include <stdbool.h>
#include <stdint.h>
@ -11,7 +11,7 @@ extern "C" {
bool ws3t_display_lock(uint32_t timeout_ms);
void ws3t_display_unlock(void);
lv_disp_t* ws3t_display_create();
lv_display_t* ws3t_display_create();
void ws3t_display_destroy();
#ifdef __cplusplus

View File

@ -7,7 +7,7 @@
bool ws3t_init_lvgl() {
tt_lvgl_sync_set(&ws3t_display_lock, &ws3t_display_unlock);
lv_disp_t* display = ws3t_display_create();
lv_display_t* display = ws3t_display_create();
if (display == NULL) {
return false;
}

View File

@ -4,7 +4,7 @@
#include "esp_err.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_log.h"
#include "lv_api_map.h"
#include "lvgl.h"
#define TAG "waveshare_s3_touch_i2c"
@ -33,16 +33,17 @@ static esp_lcd_touch_handle_t touch_init_internal() {
return tp;
}
static void touch_callback(lv_indev_drv_t* drv, lv_indev_data_t* data) {
static void touch_callback(lv_indev_t* indev, lv_indev_data_t* data) {
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
/* Read touch controller data */
esp_lcd_touch_read_data(drv->user_data);
esp_lcd_touch_handle_t touch_handle = lv_indev_get_user_data(indev);
esp_lcd_touch_read_data(touch_handle);
/* Get coordinates */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_handle, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
@ -53,15 +54,15 @@ static void touch_callback(lv_indev_drv_t* drv, lv_indev_data_t* data) {
}
}
void ws3t_touch_init(lv_disp_t* display) {
void ws3t_touch_init(lv_display_t* display) {
esp_lcd_touch_handle_t touch_handle = touch_init_internal();
ESP_LOGI(TAG, "Register display indev to LVGL");
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.disp = display;
indev_drv.read_cb = &touch_callback;
indev_drv.user_data = touch_handle;
lv_indev_drv_register(&indev_drv); // TODO: store result for deinit purposes
static lv_indev_t* device = NULL;
device = lv_indev_create();
lv_indev_set_type(device, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(device, &touch_callback);
lv_indev_set_display(device, display);
lv_indev_set_user_data(device, touch_handle);
}

View File

@ -1,12 +1,12 @@
#pragma once
#include "hal/lv_hal.h"
#include "lvgl.h"
#ifdef __cplusplus
extern "C" {
#endif
void ws3t_touch_init(lv_disp_t* display);
void ws3t_touch_init(lv_display_t* display);
#ifdef __cplusplus
}

View File

@ -8,7 +8,6 @@
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lvgl_port.h"
#include "hal/lv_hal_disp.h"
#define TAG "twodotfour_ili9341"
@ -117,10 +116,13 @@ lv_disp_t* twodotfour_display_init() {
},
.flags = {
.buff_dma = true,
.buff_spiram = false,
.sw_rotate = false,
.swap_bytes = true
}
};
lv_disp_t* display = lvgl_port_add_disp(&disp_cfg);
lv_display_t* display = lvgl_port_add_disp(&disp_cfg);
return display;
}

View File

@ -5,11 +5,11 @@
#define TAG "twodotfour_lvgl"
lv_disp_t* twodotfour_display_init();
lv_display_t* twodotfour_display_init();
bool twodotfour_touch_init(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle);
bool twodotfour_lvgl_init() {
static lv_disp_t* display = NULL;
static lv_display_t* display = NULL;
static esp_lcd_panel_io_handle_t touch_io_handle;
static esp_lcd_touch_handle_t touch_handle;

View File

@ -12,6 +12,8 @@
- Localisation of texts
- Portrait support for GPIO app
- App lifecycle docs mention on_create/on_destroy but app lifecycle is on_start/on_stop
- Explore LVGL9's FreeRTOS functionality
- Explore LVGL9's ILI93414 driver for 2.4" Yellow Board
# Core Ideas
- Make a HAL? It would mainly be there to support PC development. It's a lot of effort for supporting what's effectively a dev-only feature.

View File

@ -0,0 +1,32 @@
# Changelog
## 1.5.0
### Features
- Divided into files per feature
- Added support for LVGL9
## 1.4.0
### Features
- Added support for USB HID mouse/keyboard as an input device
## 1.3.0
### Features
- Added low power interface
## 1.2.0
### Features
- Added support for encoder (knob) as an input device
## 1.1.0
### Features
- Added support for navigation buttons as an input device

View File

@ -1,29 +1,65 @@
file(GLOB_RECURSE IMAGE_SOURCES images/*.c)
idf_component_register(SRCS "esp_lvgl_port.c" ${IMAGE_SOURCES} INCLUDE_DIRS "include" REQUIRES "esp_lcd" "lvgl" PRIV_REQUIRES "esp_timer")
#Get LVGL version
#idf_component_get_property(lvgl_ver lvgl__lvgl COMPONENT_VERSION)
#if(lvgl_ver EQUAL "")
# idf_component_get_property(lvgl_ver lvgl COMPONENT_VERSION)
#endif()
set(lvgl_ver "9.0.0")
message(STATUS "LVGL version: ${lvgl_ver}")
#Select folder by LVGL version
if(lvgl_ver VERSION_LESS "9.0.0")
message(VERBOSE "Compiling esp_lvgl_port for LVGL8")
set(PORT_FOLDER "lvgl8")
else()
message(VERBOSE "Compiling esp_lvgl_port for LVGL9")
set(PORT_FOLDER "lvgl9")
endif()
set(PORT_PATH "src/${PORT_FOLDER}")
idf_component_register(SRCS "${PORT_PATH}/esp_lvgl_port.c" "${PORT_PATH}/esp_lvgl_port_disp.c" INCLUDE_DIRS "include" REQUIRES "esp_lcd" "lvgl" PRIV_REQUIRES "esp_timer")
set(ADD_SRCS "")
set(ADD_LIBS "")
idf_build_get_property(build_components BUILD_COMPONENTS)
if("espressif__button" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::espressif__button)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_button.c")
list(APPEND ADD_LIBS idf::espressif__button)
endif()
if("button" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::button)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_button.c")
list(APPEND ADD_LIBS idf::button)
endif()
if("espressif__esp_lcd_touch" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::espressif__esp_lcd_touch)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_touch.c")
list(APPEND ADD_LIBS idf::espressif__esp_lcd_touch)
endif()
if("esp_lcd_touch" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::esp_lcd_touch)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_touch.c")
list(APPEND ADD_LIBS idf::esp_lcd_touch)
endif()
if("espressif__knob" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::espressif__knob)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_knob.c")
list(APPEND ADD_LIBS idf::espressif__knob)
endif()
if("knob" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::knob)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_knob.c")
list(APPEND ADD_LIBS idf::knob)
endif()
if("espressif__usb_host_hid" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::espressif__usb_host_hid)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
list(APPEND ADD_LIBS idf::espressif__usb_host_hid)
endif()
if("usb_host_hid" IN_LIST build_components)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::usb_host_hid)
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
list(APPEND ADD_LIBS idf::usb_host_hid)
endif()
if(ADD_SRCS)
target_sources(${COMPONENT_LIB} PRIVATE ${ADD_SRCS})
endif()
if(ADD_LIBS)
target_link_libraries(${COMPONENT_LIB} PRIVATE ${ADD_LIBS})
endif()

View File

@ -13,6 +13,20 @@ This component helps with using LVGL with Espressif's LCD and touch drivers. It
* Add/remove navigation buttons input (using [`button`](https://github.com/espressif/esp-iot-solution/tree/master/components/button))
* Add/remove encoder input (using [`knob`](https://github.com/espressif/esp-iot-solution/tree/master/components/knob))
## LVGL Version
This component supports **LVGL8** and **LVGL9**. By default, it selects the latest LVGL version. If you want to use a specific version (e.g. latest LVGL8), you can easily put into `idf_component.yml` in your project like this:
```
lvgl/lvgl:
version: "^8"
public: true
```
### LVGL Version Compatibility
This component is fully compatible with LVGL version 9. All types and functions are used from LVGL9. Some LVGL9 types are not supported in LVGL8 and there are retyping in [`esp_lvgl_port_compatibility.h`](include/esp_lvgl_port_compatibility.h) header file. **Please, be aware, that some draw and object functions are not compatible between LVGL8 and LVGL9.**
## Usage
### Initialization
@ -53,6 +67,7 @@ Add an LCD screen to the LVGL. It can be called multiple times for adding multip
},
.flags = {
.buff_dma = true,
.swap_bytes = false,
}
};
disp_handle = lvgl_port_add_disp(&disp_cfg);
@ -219,11 +234,43 @@ Every LVGL calls must be protected with these lock/unlock commands:
```
### Rotating screen
LVGL port supports rotation of the display. You can select whether you'd like software rotation or hardware rotation.
Software rotation requires no additional logic in your `flush_cb` callback.
Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure.
``` c
const lvgl_port_display_cfg_t disp_cfg = {
...
.flags = {
...
.sw_rotate = true / false, // true: software; false: hardware
}
}
```
Display rotation can be changed at runtime.
``` c
lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90);
```
**Note:** During the rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API.
**Note:** During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. When using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info.
### Using PSRAM canvas
If the SRAM is insufficient, you can use the PSRAM as a canvas and use a small trans_buffer to carry it, this makes drawing more efficient.
``` c
const lvgl_port_display_cfg_t disp_cfg = {
...
.buffer_size = DISP_WIDTH * DISP_HEIGHT, // in PSRAM, not DMA-capable
.trans_size = size, // in SRAM, DMA-capable
.flags = {
.buff_spiram = true,
.buff_dma = false,
...
}
}
```
## Performance

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -57,7 +57,7 @@ static esp_lcd_panel_handle_t lcd_panel = NULL;
static esp_lcd_touch_handle_t touch_handle = NULL;
/* LVGL display and touch */
static lv_disp_t *lvgl_disp = NULL;
static lv_display_t *lvgl_disp = NULL;
static lv_indev_t *lvgl_touch_indev = NULL;
static esp_err_t app_lcd_init(void)
@ -190,6 +190,7 @@ static esp_err_t app_lvgl_init(void)
},
.flags = {
.buff_dma = true,
.swap_bytes = true,
}
};
lvgl_disp = lvgl_port_add_disp(&disp_cfg);
@ -206,10 +207,10 @@ static esp_err_t app_lvgl_init(void)
static void _app_button_cb(lv_event_t *e)
{
lv_disp_rot_t rotation = lv_disp_get_rotation(lvgl_disp);
lv_disp_rotation_t rotation = lv_disp_get_rotation(lvgl_disp);
rotation++;
if (rotation > LV_DISP_ROT_270) {
rotation = LV_DISP_ROT_NONE;
if (rotation > LV_DISPLAY_ROTATION_270) {
rotation = LV_DISPLAY_ROTATION_0;
}
/* LCD HW rotation */
@ -227,10 +228,14 @@ static void app_main_display(void)
/* Label */
lv_obj_t *label = lv_label_create(scr);
lv_label_set_recolor(label, true);
lv_obj_set_width(label, EXAMPLE_LCD_H_RES);
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
#if LVGL_VERSION_MAJOR == 8
lv_label_set_recolor(label, true);
lv_label_set_text(label, "#FF0000 "LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"#\n#FF9400 "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING" #");
#else
lv_label_set_text(label, LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"\n "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING);
#endif
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
/* Button */

View File

@ -0,0 +1,8 @@
version: "1.5.0"
description: ESP LVGL port
url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port
dependencies:
idf: ">=4.4"
lvgl/lvgl:
version: ">=8,<10"
public: true

View File

@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMG_DUST
#define LV_ATTRIBUTE_IMG_DUST
#endif
static const
LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_DUST
uint8_t img_cursor_20px_map[] = {
0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xfc, 0x5b, 0x5b, 0x5b, 0xf1, 0x93, 0x93, 0x93, 0xfc, 0x41, 0x41, 0x41, 0xf9, 0x1e, 0x1e, 0x1e, 0xfe, 0x06, 0x06, 0x06, 0xf4, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xe4, 0x93, 0x93, 0x93, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xe3, 0xe3, 0xf9, 0xc8, 0xc8, 0xc8, 0xfe, 0x6c, 0x6c, 0x6c, 0xf3, 0x20, 0x20, 0x20, 0xfe, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xae, 0x41, 0x41, 0x41, 0xf9, 0xe3, 0xe3, 0xe3, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xfb, 0xfb, 0xfa, 0xac, 0xac, 0xac, 0xf0, 0x6f, 0x6f, 0x6f, 0xfb, 0x26, 0x26, 0x26, 0xf9, 0x0f, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x1e, 0x1e, 0x1e, 0xfe, 0xc8, 0xc8, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfb, 0xd4, 0xd4, 0xd4, 0xf9, 0xae, 0xae, 0xae, 0xf6, 0x48, 0x48, 0x48, 0xf5, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x06, 0x06, 0x06, 0xf4, 0x6c, 0x6c, 0x6c, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0xf5, 0x7e, 0x7e, 0x7e, 0xf5, 0x12, 0x12, 0x12, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x20, 0x20, 0x20, 0xfe, 0xfb, 0xfb, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xef, 0xf4, 0x73, 0x73, 0x73, 0xfc, 0x12, 0x12, 0x12, 0xfd, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xf8, 0xac, 0xac, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xf9, 0x2e, 0x2e, 0x2e, 0xfd, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0xd7, 0x6f, 0x6f, 0x6f, 0xfb, 0xfc, 0xfc, 0xfc, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xf9, 0x2e, 0x2e, 0x2e, 0xfd, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x9c, 0x26, 0x26, 0x26, 0xf9, 0xd4, 0xd4, 0xd4, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xca, 0xca, 0xca, 0xfa, 0x2b, 0x2b, 0x2b, 0xfc, 0x03, 0x03, 0x03, 0xdd, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x0f, 0x0f, 0x0f, 0xff, 0xae, 0xae, 0xae, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0xb0, 0xb0, 0xfa, 0x2b, 0x2b, 0x2b, 0xfc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe8, 0x48, 0x48, 0x48, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xf9, 0xc8, 0xc8, 0xc8, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xca, 0xca, 0xca, 0xfa, 0x2b, 0x2b, 0x2b, 0xfd, 0x03, 0x03, 0x03, 0xdd, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x1f, 0x1f, 0x1f, 0xff, 0xf2, 0xf2, 0xf2, 0xf5, 0xf0, 0xf0, 0xf0, 0xf4, 0x2e, 0x2e, 0x2e, 0xfd, 0x2e, 0x2e, 0x2e, 0xfd, 0xca, 0xca, 0xca, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0xb0, 0xb0, 0xfa, 0x2b, 0x2b, 0x2b, 0xfc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x2c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0xf0, 0x7e, 0x7e, 0x7e, 0xf5, 0x73, 0x73, 0x73, 0xfc, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0xdd, 0x2b, 0x2b, 0x2b, 0xfc, 0xb0, 0xb0, 0xb0, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0xb1, 0xb1, 0xef, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xd7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xcb, 0x12, 0x12, 0x12, 0xfd, 0x12, 0x12, 0x12, 0xfd, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x37, 0x03, 0x03, 0x03, 0xdd, 0x2b, 0x2b, 0x2b, 0xfd, 0xca, 0xca, 0xca, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0x86, 0x86, 0x86, 0xf2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xb6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xc2, 0x2b, 0x2b, 0x2b, 0xfc, 0xb0, 0xb0, 0xb0, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0x74, 0x74, 0x74, 0xf8, 0x06, 0x06, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x16,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x03, 0x03, 0x03, 0xdd, 0x2b, 0x2b, 0x2b, 0xfc, 0xb1, 0xb1, 0xb1, 0xef, 0x86, 0x86, 0x86, 0xf2, 0x06, 0x06, 0x06, 0xfe, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const lv_img_dsc_t img_cursor = {
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.cf = LV_COLOR_FORMAT_ARGB8888,
.header.flags = 0,
.header.w = 20,
.header.h = 20,
.header.stride = 80,
.data_size = 1600,
.data = img_cursor_20px_map,
};

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -12,28 +12,15 @@
#pragma once
#include "esp_err.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "lvgl.h"
#include "esp_lvgl_port_button.h"
#include "esp_lvgl_port_compatibility.h"
#include "esp_lvgl_port_disp.h"
#include "esp_lvgl_port_knob.h"
#include "esp_lvgl_port_touch.h"
#include "esp_lvgl_port_usbhid.h"
#if __has_include ("esp_lcd_touch.h")
#include "esp_lcd_touch.h"
#define ESP_LVGL_PORT_TOUCH_COMPONENT 1
#endif
#if __has_include ("iot_knob.h")
#include "iot_knob.h"
#include "iot_button.h"
#define ESP_LVGL_PORT_KNOB_COMPONENT 1
#endif
#if __has_include ("iot_button.h")
#include "iot_button.h"
#define ESP_LVGL_PORT_BUTTON_COMPONENT 1
#endif
#if __has_include ("usb/hid_host.h")
#define ESP_LVGL_PORT_USB_HOST_HID_COMPONENT 1
#if LVGL_VERSION_MAJOR == 8
#include "esp_lvgl_port_compatibility.h"
#endif
#ifdef __cplusplus
@ -51,85 +38,6 @@ typedef struct {
int timer_period_ms; /*!< LVGL timer tick period in ms */
} lvgl_port_cfg_t;
/**
* @brief Rotation configuration
*/
typedef struct {
bool swap_xy; /*!< LCD Screen swapped X and Y (in esp_lcd driver) */
bool mirror_x; /*!< LCD Screen mirrored X (in esp_lcd driver) */
bool mirror_y; /*!< LCD Screen mirrored Y (in esp_lcd driver) */
} lvgl_port_rotation_cfg_t;
/**
* @brief Configuration display structure
*/
typedef struct {
esp_lcd_panel_io_handle_t io_handle; /*!< LCD panel IO handle */
esp_lcd_panel_handle_t panel_handle; /*!< LCD panel handle */
uint32_t buffer_size; /*!< Size of the buffer for the screen in pixels */
bool double_buffer; /*!< True, if should be allocated two buffers */
uint32_t hres; /*!< LCD display horizontal resolution */
uint32_t vres; /*!< LCD display vertical resolution */
bool monochrome; /*!< True, if display is monochrome and using 1bit for 1px */
lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */
struct {
unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */
unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */
} flags;
} lvgl_port_display_cfg_t;
#ifdef ESP_LVGL_PORT_TOUCH_COMPONENT
/**
* @brief Configuration touch structure
*/
typedef struct {
lv_disp_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
esp_lcd_touch_handle_t handle; /*!< LCD touch IO handle */
} lvgl_port_touch_cfg_t;
#endif
#ifdef ESP_LVGL_PORT_KNOB_COMPONENT
/**
* @brief Configuration of the encoder structure
*/
typedef struct {
lv_disp_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
const knob_config_t *encoder_a_b;
const button_config_t *encoder_enter; /*!< Navigation button for enter */
} lvgl_port_encoder_cfg_t;
#endif
#ifdef ESP_LVGL_PORT_BUTTON_COMPONENT
/**
* @brief Configuration of the navigation buttons structure
*/
typedef struct {
lv_disp_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
const button_config_t *button_prev; /*!< Navigation button for previous */
const button_config_t *button_next; /*!< Navigation button for next */
const button_config_t *button_enter; /*!< Navigation button for enter */
} lvgl_port_nav_btns_cfg_t;
#endif
#ifdef ESP_LVGL_PORT_USB_HOST_HID_COMPONENT
/**
* @brief Configuration of the mouse input
*/
typedef struct {
lv_disp_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
uint8_t sensitivity; /*!< Mouse sensitivity (cannot be zero) */
lv_obj_t *cursor_img; /*!< Mouse cursor image, if NULL then used default */
} lvgl_port_hid_mouse_cfg_t;
/**
* @brief Configuration of the keyboard input
*/
typedef struct {
lv_disp_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
} lvgl_port_hid_keyboard_cfg_t;
#endif
/**
* @brief LVGL port configuration structure
*
@ -137,7 +45,7 @@ typedef struct {
#define ESP_LVGL_PORT_INIT_CONFIG() \
{ \
.task_priority = 4, \
.task_stack = 4096, \
.task_stack = 6144, \
.task_affinity = -1, \
.task_max_sleep_ms = 500, \
.timer_period_ms = 5, \
@ -167,124 +75,6 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg);
*/
esp_err_t lvgl_port_deinit(void);
/**
* @brief Add display handling to LVGL
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_disp for free all memory!
*
* @param disp_cfg Display configuration structure
* @return Pointer to LVGL display or NULL when error occured
*/
lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg);
/**
* @brief Remove display handling from LVGL
*
* @note Free all memory used for this display.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_disp(lv_disp_t *disp);
#ifdef ESP_LVGL_PORT_TOUCH_COMPONENT
/**
* @brief Add LCD touch as an input device
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_touch for free all memory!
*
* @param touch_cfg Touch configuration structure
* @return Pointer to LVGL touch input device or NULL when error occured
*/
lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg);
/**
* @brief Remove selected LCD touch from input devices
*
* @note Free all memory used for this display.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_touch(lv_indev_t *touch);
#endif
#ifdef ESP_LVGL_PORT_KNOB_COMPONENT
/**
* @brief Add encoder as an input device
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_encoder for free all memory!
*
* @param encoder_cfg Encoder configuration structure
* @return Pointer to LVGL encoder input device or NULL when error occured
*/
lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg);
/**
* @brief Remove encoder from input devices
*
* @note Free all memory used for this input device.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_encoder(lv_indev_t *encoder);
#endif
#ifdef ESP_LVGL_PORT_BUTTON_COMPONENT
/**
* @brief Add buttons as an input device
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_navigation_buttons for free all memory!
*
* @param buttons_cfg Buttons configuration structure
* @return Pointer to LVGL buttons input device or NULL when error occured
*/
lv_indev_t *lvgl_port_add_navigation_buttons(const lvgl_port_nav_btns_cfg_t *buttons_cfg);
/**
* @brief Remove selected buttons from input devices
*
* @note Free all memory used for this input device.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_navigation_buttons(lv_indev_t *buttons);
#endif
#ifdef ESP_LVGL_PORT_USB_HOST_HID_COMPONENT
/**
* @brief Add USB HID mouse as an input device
*
* @note The USB host must be initialized before. Use `usb_host_install` for host initialization.
*
* @param mouse_cfg mouse configuration structure
* @return Pointer to LVGL buttons input device or NULL when error occured
*/
lv_indev_t *lvgl_port_add_usb_hid_mouse_input(const lvgl_port_hid_mouse_cfg_t *mouse_cfg);
/**
* @brief Add USB HID keyboard as an input device
*
* @note The USB host must be initialized before. Use `usb_host_install` for host initialization.
*
* @param keyboard_cfg keyboard configuration structure
* @return Pointer to LVGL buttons input device or NULL when error occured
*/
lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cfg_t *keyboard_cfg);
/**
* @brief Remove selected USB HID from input devices
*
* @note Free all memory used for this input device. When removed all HID devices, the HID task will be freed.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_usb_hid_input(lv_indev_t *hid);
#endif
/**
* @brief Take LVGL mutex
*
@ -308,7 +98,7 @@ void lvgl_port_unlock(void);
*
* @param disp LVGL display handle (returned from lvgl_port_add_disp)
*/
void lvgl_port_flush_ready(lv_disp_t *disp);
void lvgl_port_flush_ready(lv_display_t *disp);
/**
* @brief Stop lvgl task

View File

@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LVGL port button
*/
#pragma once
#include "esp_err.h"
#include "lvgl.h"
#if __has_include ("iot_button.h")
#include "iot_button.h"
#define ESP_LVGL_PORT_BUTTON_COMPONENT 1
#endif
#if LVGL_VERSION_MAJOR == 8
#include "esp_lvgl_port_compatibility.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ESP_LVGL_PORT_BUTTON_COMPONENT
/**
* @brief Configuration of the navigation buttons structure
*/
typedef struct {
lv_display_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
const button_config_t *button_prev; /*!< Navigation button for previous */
const button_config_t *button_next; /*!< Navigation button for next */
const button_config_t *button_enter; /*!< Navigation button for enter */
} lvgl_port_nav_btns_cfg_t;
/**
* @brief Add buttons as an input device
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_navigation_buttons for free all memory!
*
* @param buttons_cfg Buttons configuration structure
* @return Pointer to LVGL buttons input device or NULL when error occurred
*/
lv_indev_t *lvgl_port_add_navigation_buttons(const lvgl_port_nav_btns_cfg_t *buttons_cfg);
/**
* @brief Remove selected buttons from input devices
*
* @note Free all memory used for this input device.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_navigation_buttons(lv_indev_t *buttons);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LVGL port compatibility
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Backward compatibility with LVGL 8
*/
typedef lv_disp_t lv_display_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LVGL port display
*/
#pragma once
#include "esp_err.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "lvgl.h"
#if LVGL_VERSION_MAJOR == 8
#include "esp_lvgl_port_compatibility.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Rotation configuration
*/
typedef struct {
bool swap_xy; /*!< LCD Screen swapped X and Y (in esp_lcd driver) */
bool mirror_x; /*!< LCD Screen mirrored X (in esp_lcd driver) */
bool mirror_y; /*!< LCD Screen mirrored Y (in esp_lcd driver) */
} lvgl_port_rotation_cfg_t;
/**
* @brief Configuration display structure
*/
typedef struct {
esp_lcd_panel_io_handle_t io_handle; /*!< LCD panel IO handle */
esp_lcd_panel_handle_t panel_handle; /*!< LCD panel handle */
uint32_t buffer_size; /*!< Size of the buffer for the screen in pixels */
bool double_buffer; /*!< True, if should be allocated two buffers */
uint32_t trans_size; /*!< Allocated buffer will be in SRAM to move framebuf */
uint32_t hres; /*!< LCD display horizontal resolution */
uint32_t vres; /*!< LCD display vertical resolution */
bool monochrome; /*!< True, if display is monochrome and using 1bit for 1px */
lvgl_port_rotation_cfg_t rotation; /*!< Default values of the screen rotation */
struct {
unsigned int buff_dma: 1; /*!< Allocated LVGL buffer will be DMA capable */
unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */
unsigned int sw_rotate: 1; /*!< Use software rotation (slower) */
unsigned int swap_bytes: 1; /*!< Swap bytes in RGB656 (16-bit) before send to LCD driver */
} flags;
} lvgl_port_display_cfg_t;
/**
* @brief Add display handling to LVGL
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_disp for free all memory!
*
* @param disp_cfg Display configuration structure
* @return Pointer to LVGL display or NULL when error occurred
*/
lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg);
/**
* @brief Remove display handling from LVGL
*
* @note Free all memory used for this display.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_disp(lv_display_t *disp);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LVGL port knob
*/
#pragma once
#include "esp_err.h"
#include "lvgl.h"
#if __has_include ("iot_knob.h")
#include "iot_knob.h"
#include "iot_button.h"
#define ESP_LVGL_PORT_KNOB_COMPONENT 1
#endif
#if LVGL_VERSION_MAJOR == 8
#include "esp_lvgl_port_compatibility.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ESP_LVGL_PORT_KNOB_COMPONENT
/**
* @brief Configuration of the encoder structure
*/
typedef struct {
lv_display_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
const knob_config_t *encoder_a_b;
const button_config_t *encoder_enter; /*!< Navigation button for enter */
} lvgl_port_encoder_cfg_t;
/**
* @brief Add encoder as an input device
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_encoder for free all memory!
*
* @param encoder_cfg Encoder configuration structure
* @return Pointer to LVGL encoder input device or NULL when error occurred
*/
lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg);
/**
* @brief Remove encoder from input devices
*
* @note Free all memory used for this input device.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_encoder(lv_indev_t *encoder);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LVGL port touch
*/
#pragma once
#include "esp_err.h"
#include "lvgl.h"
#if __has_include ("esp_lcd_touch.h")
#include "esp_lcd_touch.h"
#define ESP_LVGL_PORT_TOUCH_COMPONENT 1
#endif
#if LVGL_VERSION_MAJOR == 8
#include "esp_lvgl_port_compatibility.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ESP_LVGL_PORT_TOUCH_COMPONENT
/**
* @brief Configuration touch structure
*/
typedef struct {
lv_display_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
esp_lcd_touch_handle_t handle; /*!< LCD touch IO handle */
} lvgl_port_touch_cfg_t;
/**
* @brief Add LCD touch as an input device
*
* @note Allocated memory in this function is not free in deinit. You must call lvgl_port_remove_touch for free all memory!
*
* @param touch_cfg Touch configuration structure
* @return Pointer to LVGL touch input device or NULL when error occurred
*/
lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg);
/**
* @brief Remove selected LCD touch from input devices
*
* @note Free all memory used for this display.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_touch(lv_indev_t *touch);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LVGL port USB HID
*/
#pragma once
#include "esp_err.h"
#include "lvgl.h"
#if __has_include ("usb/hid_host.h")
#define ESP_LVGL_PORT_USB_HOST_HID_COMPONENT 1
#endif
#if LVGL_VERSION_MAJOR == 8
#include "esp_lvgl_port_compatibility.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ESP_LVGL_PORT_USB_HOST_HID_COMPONENT
/**
* @brief Configuration of the mouse input
*/
typedef struct {
lv_display_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
uint8_t sensitivity; /*!< Mouse sensitivity (cannot be zero) */
lv_obj_t *cursor_img; /*!< Mouse cursor image, if NULL then used default */
} lvgl_port_hid_mouse_cfg_t;
/**
* @brief Configuration of the keyboard input
*/
typedef struct {
lv_display_t *disp; /*!< LVGL display handle (returned from lvgl_port_add_disp) */
} lvgl_port_hid_keyboard_cfg_t;
/**
* @brief Add USB HID mouse as an input device
*
* @note The USB host must be initialized before. Use `usb_host_install` for host initialization.
*
* @param mouse_cfg mouse configuration structure
* @return Pointer to LVGL buttons input device or NULL when error occurred
*/
lv_indev_t *lvgl_port_add_usb_hid_mouse_input(const lvgl_port_hid_mouse_cfg_t *mouse_cfg);
/**
* @brief Add USB HID keyboard as an input device
*
* @note The USB host must be initialized before. Use `usb_host_install` for host initialization.
*
* @param keyboard_cfg keyboard configuration structure
* @return Pointer to LVGL buttons input device or NULL when error occurred
*/
lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cfg_t *keyboard_cfg);
/**
* @brief Remove selected USB HID from input devices
*
* @note Free all memory used for this input device. When removed all HID devices, the HID task will be freed.
*
* @return
* - ESP_OK on success
*/
esp_err_t lvgl_port_remove_usb_hid_input(lv_indev_t *hid);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,198 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_system.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_lvgl_port.h"
#include "lvgl.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct lvgl_port_ctx_s {
SemaphoreHandle_t lvgl_mux;
esp_timer_handle_t tick_timer;
bool running;
int task_max_sleep_ms;
int timer_period_ms;
} lvgl_port_ctx_t;
/*******************************************************************************
* Local variables
*******************************************************************************/
static lvgl_port_ctx_t lvgl_port_ctx;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_task(void *arg);
static esp_err_t lvgl_port_tick_init(void);
static void lvgl_port_task_deinit(void);
/*******************************************************************************
* Public API functions
*******************************************************************************/
esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(cfg->task_affinity < (configNUM_CORES), ESP_ERR_INVALID_ARG, err, TAG, "Bad core number for task! Maximum core number is %d", (configNUM_CORES - 1));
memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx));
/* LVGL init */
lv_init();
/* Tick init */
lvgl_port_ctx.timer_period_ms = cfg->timer_period_ms;
ESP_RETURN_ON_ERROR(lvgl_port_tick_init(), TAG, "");
/* Create task */
lvgl_port_ctx.task_max_sleep_ms = cfg->task_max_sleep_ms;
if (lvgl_port_ctx.task_max_sleep_ms == 0) {
lvgl_port_ctx.task_max_sleep_ms = 500;
}
lvgl_port_ctx.lvgl_mux = xSemaphoreCreateRecursiveMutex();
ESP_GOTO_ON_FALSE(lvgl_port_ctx.lvgl_mux, ESP_ERR_NO_MEM, err, TAG, "Create LVGL mutex fail!");
BaseType_t res;
if (cfg->task_affinity < 0) {
res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL);
} else {
res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL, cfg->task_affinity);
}
ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!");
err:
if (ret != ESP_OK) {
lvgl_port_deinit();
}
return ret;
}
esp_err_t lvgl_port_resume(void)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
if (lvgl_port_ctx.tick_timer != NULL) {
lv_timer_enable(true);
ret = esp_timer_start_periodic(lvgl_port_ctx.tick_timer, lvgl_port_ctx.timer_period_ms * 1000);
}
return ret;
}
esp_err_t lvgl_port_stop(void)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
if (lvgl_port_ctx.tick_timer != NULL) {
lv_timer_enable(false);
ret = esp_timer_stop(lvgl_port_ctx.tick_timer);
}
return ret;
}
esp_err_t lvgl_port_deinit(void)
{
/* Stop and delete timer */
if (lvgl_port_ctx.tick_timer != NULL) {
esp_timer_stop(lvgl_port_ctx.tick_timer);
esp_timer_delete(lvgl_port_ctx.tick_timer);
lvgl_port_ctx.tick_timer = NULL;
}
/* Stop running task */
if (lvgl_port_ctx.running) {
lvgl_port_ctx.running = false;
} else {
lvgl_port_task_deinit();
}
return ESP_OK;
}
bool lvgl_port_lock(uint32_t timeout_ms)
{
assert(lvgl_port_ctx.lvgl_mux && "lvgl_port_init must be called first");
const TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
return xSemaphoreTakeRecursive(lvgl_port_ctx.lvgl_mux, timeout_ticks) == pdTRUE;
}
void lvgl_port_unlock(void)
{
assert(lvgl_port_ctx.lvgl_mux && "lvgl_port_init must be called first");
xSemaphoreGiveRecursive(lvgl_port_ctx.lvgl_mux);
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_task(void *arg)
{
uint32_t task_delay_ms = lvgl_port_ctx.task_max_sleep_ms;
ESP_LOGI(TAG, "Starting LVGL task");
lvgl_port_ctx.running = true;
while (lvgl_port_ctx.running) {
if (lvgl_port_lock(0)) {
task_delay_ms = lv_timer_handler();
lvgl_port_unlock();
}
if ((task_delay_ms > lvgl_port_ctx.task_max_sleep_ms) || (1 == task_delay_ms)) {
task_delay_ms = lvgl_port_ctx.task_max_sleep_ms;
} else if (task_delay_ms < 1) {
task_delay_ms = 1;
}
vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
}
lvgl_port_task_deinit();
/* Close task */
vTaskDelete( NULL );
}
static void lvgl_port_task_deinit(void)
{
if (lvgl_port_ctx.lvgl_mux) {
vSemaphoreDelete(lvgl_port_ctx.lvgl_mux);
}
memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx));
#if LV_ENABLE_GC || !LV_MEM_CUSTOM
/* Deinitialize LVGL */
lv_deinit();
#endif
}
static void lvgl_port_tick_increment(void *arg)
{
/* Tell LVGL how many milliseconds have elapsed */
lv_tick_inc(lvgl_port_ctx.timer_period_ms);
}
static esp_err_t lvgl_port_tick_init(void)
{
// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_port_tick_increment,
.name = "LVGL tick",
};
ESP_RETURN_ON_ERROR(esp_timer_create(&lvgl_tick_timer_args, &lvgl_port_ctx.tick_timer), TAG, "Creating LVGL timer filed!");
return esp_timer_start_periodic(lvgl_port_ctx.tick_timer, lvgl_port_ctx.timer_period_ms * 1000);
}

View File

@ -0,0 +1,197 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lvgl_port.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef enum {
LVGL_PORT_NAV_BTN_PREV,
LVGL_PORT_NAV_BTN_NEXT,
LVGL_PORT_NAV_BTN_ENTER,
LVGL_PORT_NAV_BTN_CNT,
} lvgl_port_nav_btns_t;
typedef struct {
button_handle_t btn[LVGL_PORT_NAV_BTN_CNT]; /* Button handlers */
lv_indev_drv_t indev_drv; /* LVGL input device driver */
bool btn_prev; /* Button prev state */
bool btn_next; /* Button next state */
bool btn_enter; /* Button enter state */
} lvgl_port_nav_btns_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_navigation_buttons_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_btn_down_handler(void *arg, void *arg2);
static void lvgl_port_btn_up_handler(void *arg, void *arg2);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_navigation_buttons(const lvgl_port_nav_btns_cfg_t *buttons_cfg)
{
esp_err_t ret = ESP_OK;
lv_indev_t *indev = NULL;
assert(buttons_cfg != NULL);
assert(buttons_cfg->disp != NULL);
/* Touch context */
lvgl_port_nav_btns_ctx_t *buttons_ctx = malloc(sizeof(lvgl_port_nav_btns_ctx_t));
if (buttons_ctx == NULL) {
ESP_LOGE(TAG, "Not enough memory for buttons context allocation!");
return NULL;
}
/* Previous button */
if (buttons_cfg->button_prev != NULL) {
buttons_ctx->btn[LVGL_PORT_NAV_BTN_PREV] = iot_button_create(buttons_cfg->button_prev);
ESP_GOTO_ON_FALSE(buttons_ctx->btn[LVGL_PORT_NAV_BTN_PREV], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
/* Next button */
if (buttons_cfg->button_next != NULL) {
buttons_ctx->btn[LVGL_PORT_NAV_BTN_NEXT] = iot_button_create(buttons_cfg->button_next);
ESP_GOTO_ON_FALSE(buttons_ctx->btn[LVGL_PORT_NAV_BTN_NEXT], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
/* Enter button */
if (buttons_cfg->button_enter != NULL) {
buttons_ctx->btn[LVGL_PORT_NAV_BTN_ENTER] = iot_button_create(buttons_cfg->button_enter);
ESP_GOTO_ON_FALSE(buttons_ctx->btn[LVGL_PORT_NAV_BTN_ENTER], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
/* Button handlers */
for (int i = 0; i < LVGL_PORT_NAV_BTN_CNT; i++) {
ESP_ERROR_CHECK(iot_button_register_cb(buttons_ctx->btn[i], BUTTON_PRESS_DOWN, lvgl_port_btn_down_handler, buttons_ctx));
ESP_ERROR_CHECK(iot_button_register_cb(buttons_ctx->btn[i], BUTTON_PRESS_UP, lvgl_port_btn_up_handler, buttons_ctx));
}
buttons_ctx->btn_prev = false;
buttons_ctx->btn_next = false;
buttons_ctx->btn_enter = false;
/* Register a touchpad input device */
lv_indev_drv_init(&buttons_ctx->indev_drv);
buttons_ctx->indev_drv.type = LV_INDEV_TYPE_ENCODER;
buttons_ctx->indev_drv.disp = buttons_cfg->disp;
buttons_ctx->indev_drv.read_cb = lvgl_port_navigation_buttons_read;
buttons_ctx->indev_drv.user_data = buttons_ctx;
buttons_ctx->indev_drv.long_press_repeat_time = 300;
indev = lv_indev_drv_register(&buttons_ctx->indev_drv);
err:
if (ret != ESP_OK) {
for (int i = 0; i < LVGL_PORT_NAV_BTN_CNT; i++) {
if (buttons_ctx->btn[i] != NULL) {
iot_button_delete(buttons_ctx->btn[i]);
}
}
if (buttons_ctx != NULL) {
free(buttons_ctx);
}
}
return indev;
}
esp_err_t lvgl_port_remove_navigation_buttons(lv_indev_t *buttons)
{
assert(buttons);
lv_indev_drv_t *indev_drv = buttons->driver;
assert(indev_drv);
lvgl_port_nav_btns_ctx_t *buttons_ctx = (lvgl_port_nav_btns_ctx_t *)indev_drv->user_data;
/* Remove input device driver */
lv_indev_delete(buttons);
if (buttons_ctx) {
free(buttons_ctx);
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_navigation_buttons_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
static uint32_t last_key = 0;
assert(indev_drv);
lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *)indev_drv->user_data;
assert(ctx);
/* Buttons */
if (ctx->btn_prev) {
data->key = LV_KEY_LEFT;
last_key = LV_KEY_LEFT;
data->state = LV_INDEV_STATE_PRESSED;
} else if (ctx->btn_next) {
data->key = LV_KEY_RIGHT;
last_key = LV_KEY_RIGHT;
data->state = LV_INDEV_STATE_PRESSED;
} else if (ctx->btn_enter) {
data->key = LV_KEY_ENTER;
last_key = LV_KEY_ENTER;
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->key = last_key;
data->state = LV_INDEV_STATE_RELEASED;
}
}
static void lvgl_port_btn_down_handler(void *arg, void *arg2)
{
lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* PREV */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_PREV]) {
ctx->btn_prev = true;
}
/* NEXT */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_NEXT]) {
ctx->btn_next = true;
}
/* ENTER */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_ENTER]) {
ctx->btn_enter = true;
}
}
}
static void lvgl_port_btn_up_handler(void *arg, void *arg2)
{
lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* PREV */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_PREV]) {
ctx->btn_prev = false;
}
/* NEXT */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_NEXT]) {
ctx->btn_next = false;
}
/* ENTER */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_ENTER]) {
ctx->btn_enter = false;
}
}
}

View File

@ -0,0 +1,337 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lvgl_port.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 4)) || (ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 0, 0))
#define LVGL_PORT_HANDLE_FLUSH_READY 0
#else
#define LVGL_PORT_HANDLE_FLUSH_READY 1
#endif
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */
esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */
lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */
lv_disp_drv_t disp_drv; /* LVGL display driver */
lv_color_t *trans_buf; /* Buffer send to driver */
uint32_t trans_size; /* Maximum size for one transport */
SemaphoreHandle_t trans_sem; /* Idle transfer mutex */
} lvgl_port_display_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
#if LVGL_PORT_HANDLE_FLUSH_READY
static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx);
#endif
static void lvgl_port_flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map);
static void lvgl_port_update_callback(lv_disp_drv_t *drv);
static void lvgl_port_pix_monochrome_callback(lv_disp_drv_t *drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg)
{
esp_err_t ret = ESP_OK;
lv_disp_t *disp = NULL;
lv_color_t *buf1 = NULL;
lv_color_t *buf2 = NULL;
lv_color_t *buf3 = NULL;
SemaphoreHandle_t trans_sem = NULL;
assert(disp_cfg != NULL);
assert(disp_cfg->io_handle != NULL);
assert(disp_cfg->panel_handle != NULL);
assert(disp_cfg->buffer_size > 0);
assert(disp_cfg->hres > 0);
assert(disp_cfg->vres > 0);
/* Display context */
lvgl_port_display_ctx_t *disp_ctx = malloc(sizeof(lvgl_port_display_ctx_t));
ESP_GOTO_ON_FALSE(disp_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for display context allocation!");
disp_ctx->io_handle = disp_cfg->io_handle;
disp_ctx->panel_handle = disp_cfg->panel_handle;
disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy;
disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x;
disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y;
disp_ctx->trans_size = disp_cfg->trans_size;
uint32_t buff_caps = MALLOC_CAP_DEFAULT;
if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram && (0 == disp_cfg->trans_size)) {
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!");
} else if (disp_cfg->flags.buff_dma) {
buff_caps = MALLOC_CAP_DMA;
} else if (disp_cfg->flags.buff_spiram) {
buff_caps = MALLOC_CAP_SPIRAM;
}
if (disp_cfg->trans_size) {
buf3 = heap_caps_malloc(disp_cfg->trans_size * sizeof(lv_color_t), MALLOC_CAP_DMA);
ESP_GOTO_ON_FALSE(buf3, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for buffer(transport) allocation!");
disp_ctx->trans_buf = buf3;
trans_sem = xSemaphoreCreateCounting(1, 0);
ESP_GOTO_ON_FALSE(trans_sem, ESP_ERR_NO_MEM, err, TAG, "Failed to create transport counting Semaphore");
disp_ctx->trans_sem = trans_sem;
}
/* alloc draw buffers used by LVGL */
/* it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized */
buf1 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color_t), buff_caps);
ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!");
if (disp_cfg->double_buffer) {
buf2 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color_t), buff_caps);
ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!");
}
lv_disp_draw_buf_t *disp_buf = malloc(sizeof(lv_disp_draw_buf_t));
ESP_GOTO_ON_FALSE(disp_buf, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL display buffer allocation!");
/* initialize LVGL draw buffers */
lv_disp_draw_buf_init(disp_buf, buf1, buf2, disp_cfg->buffer_size);
ESP_LOGD(TAG, "Register display driver to LVGL");
lv_disp_drv_init(&disp_ctx->disp_drv);
disp_ctx->disp_drv.hor_res = disp_cfg->hres;
disp_ctx->disp_drv.ver_res = disp_cfg->vres;
disp_ctx->disp_drv.flush_cb = lvgl_port_flush_callback;
disp_ctx->disp_drv.draw_buf = disp_buf;
disp_ctx->disp_drv.user_data = disp_ctx;
disp_ctx->disp_drv.sw_rotate = disp_cfg->flags.sw_rotate;
if (disp_ctx->disp_drv.sw_rotate == false) {
disp_ctx->disp_drv.drv_update_cb = lvgl_port_update_callback;
}
#if LVGL_PORT_HANDLE_FLUSH_READY
/* Register done callback */
const esp_lcd_panel_io_callbacks_t cbs = {
.on_color_trans_done = lvgl_port_flush_ready_callback,
};
esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, &disp_ctx->disp_drv);
#endif
/* Monochrome display settings */
if (disp_cfg->monochrome) {
/* When using monochromatic display, there must be used full bufer! */
ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == disp_cfg->buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!");
disp_ctx->disp_drv.full_refresh = 1;
disp_ctx->disp_drv.set_px_cb = lvgl_port_pix_monochrome_callback;
}
disp = lv_disp_drv_register(&disp_ctx->disp_drv);
err:
if (ret != ESP_OK) {
if (buf1) {
free(buf1);
}
if (buf2) {
free(buf2);
}
if (buf3) {
free(buf3);
}
if (trans_sem) {
vSemaphoreDelete(trans_sem);
}
if (disp_ctx) {
free(disp_ctx);
}
}
return disp;
}
esp_err_t lvgl_port_remove_disp(lv_disp_t *disp)
{
assert(disp);
lv_disp_drv_t *disp_drv = disp->driver;
assert(disp_drv);
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)disp_drv->user_data;
lv_disp_remove(disp);
if (disp_drv) {
if (disp_drv->draw_buf && disp_drv->draw_buf->buf1) {
free(disp_drv->draw_buf->buf1);
disp_drv->draw_buf->buf1 = NULL;
}
if (disp_drv->draw_buf && disp_drv->draw_buf->buf2) {
free(disp_drv->draw_buf->buf2);
disp_drv->draw_buf->buf2 = NULL;
}
if (disp_drv->draw_buf) {
free(disp_drv->draw_buf);
disp_drv->draw_buf = NULL;
}
}
free(disp_ctx);
return ESP_OK;
}
void lvgl_port_flush_ready(lv_disp_t *disp)
{
assert(disp);
assert(disp->driver);
lv_disp_flush_ready(disp->driver);
}
/*******************************************************************************
* Private functions
*******************************************************************************/
#if LVGL_PORT_HANDLE_FLUSH_READY
static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
BaseType_t taskAwake = pdFALSE;
lv_disp_drv_t *disp_drv = (lv_disp_drv_t *)user_ctx;
assert(disp_drv != NULL);
lvgl_port_display_ctx_t *disp_ctx = disp_drv->user_data;
assert(disp_ctx != NULL);
lv_disp_flush_ready(disp_drv);
if (disp_ctx->trans_size && disp_ctx->trans_sem) {
xSemaphoreGiveFromISR(disp_ctx->trans_sem, &taskAwake);
}
return false;
}
#endif
static void lvgl_port_flush_callback(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
assert(drv != NULL);
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data;
assert(disp_ctx != NULL);
int x_draw_start;
int x_draw_end;
int y_draw_start;
int y_draw_end;
int y_start_tmp;
int y_end_tmp;
int trans_count;
int trans_line;
int max_line;
const int x_start = area->x1;
const int x_end = area->x2;
const int y_start = area->y1;
const int y_end = area->y2;
const int width = x_end - x_start + 1;
const int height = y_end - y_start + 1;
lv_color_t *from = color_map;
lv_color_t *to = NULL;
if (0 == disp_ctx->trans_size) {
esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_start, y_start, x_end + 1, y_end + 1, color_map);
} else {
y_start_tmp = y_start;
max_line = ((disp_ctx->trans_size / width) > height) ? (height) : (disp_ctx->trans_size / width);
trans_count = height / max_line + (height % max_line ? (1) : (0));
for (int i = 0; i < trans_count; i++) {
trans_line = (y_end - y_start_tmp + 1) > max_line ? max_line : (y_end - y_start_tmp + 1);
y_end_tmp = (y_end - y_start_tmp + 1) > max_line ? (y_start_tmp + max_line - 1) : y_end;
to = disp_ctx->trans_buf;
for (int y = 0; y < trans_line; y++) {
for (int x = 0; x < width; x++) {
*(to + y * (width) + x) = *(from + y * (width) + x);
}
}
x_draw_start = x_start;
x_draw_end = x_end;
y_draw_start = y_start_tmp;
y_draw_end = y_end_tmp;
esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, x_draw_start, y_draw_start, x_draw_end + 1, y_draw_end + 1, to);
from += max_line * width;
y_start_tmp += max_line;
xSemaphoreTake(disp_ctx->trans_sem, portMAX_DELAY);
}
}
}
static void lvgl_port_update_callback(lv_disp_drv_t *drv)
{
assert(drv);
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)drv->user_data;
assert(disp_ctx != NULL);
esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle;
/* Solve rotation screen and touch */
switch (drv->rotated) {
case LV_DISP_ROT_NONE:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy);
esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y);
break;
case LV_DISP_ROT_90:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy);
if (disp_ctx->rotation.swap_xy) {
esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y);
} else {
esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y);
}
break;
case LV_DISP_ROT_180:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy);
esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y);
break;
case LV_DISP_ROT_270:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy);
if (disp_ctx->rotation.swap_xy) {
esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y);
} else {
esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y);
}
break;
}
}
static void lvgl_port_pix_monochrome_callback(lv_disp_drv_t *drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
{
if (drv->rotated == LV_DISP_ROT_90 || drv->rotated == LV_DISP_ROT_270) {
lv_coord_t tmp_x = x;
x = y;
y = tmp_x;
}
/* Write to the buffer as required for the display.
* It writes only 1-bit for monochrome displays mapped vertically.*/
buf += drv->hor_res * (y >> 3) + x;
if (lv_color_to1(color)) {
(*buf) &= ~(1 << (y % 8));
} else {
(*buf) |= (1 << (y % 8));
}
}

View File

@ -0,0 +1,161 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lvgl_port.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
knob_handle_t knob_handle; /* Encoder knob handlers */
button_handle_t btn_handle; /* Encoder button handlers */
lv_indev_drv_t indev_drv; /* LVGL input device driver */
bool btn_enter; /* Encoder button enter state */
} lvgl_port_encoder_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_encoder_btn_down_handler(void *arg, void *arg2);
static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg)
{
esp_err_t ret = ESP_OK;
lv_indev_t *indev = NULL;
assert(encoder_cfg != NULL);
assert(encoder_cfg->disp != NULL);
/* Encoder context */
lvgl_port_encoder_ctx_t *encoder_ctx = malloc(sizeof(lvgl_port_encoder_ctx_t));
if (encoder_ctx == NULL) {
ESP_LOGE(TAG, "Not enough memory for encoder context allocation!");
return NULL;
}
/* Encoder_a/b */
if (encoder_cfg->encoder_a_b != NULL) {
encoder_ctx->knob_handle = iot_knob_create(encoder_cfg->encoder_a_b);
ESP_GOTO_ON_FALSE(encoder_ctx->knob_handle, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for knob create!");
}
/* Encoder Enter */
if (encoder_cfg->encoder_enter != NULL) {
encoder_ctx->btn_handle = iot_button_create(encoder_cfg->encoder_enter);
ESP_GOTO_ON_FALSE(encoder_ctx->btn_handle, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
ESP_ERROR_CHECK(iot_button_register_cb(encoder_ctx->btn_handle, BUTTON_PRESS_DOWN, lvgl_port_encoder_btn_down_handler, encoder_ctx));
ESP_ERROR_CHECK(iot_button_register_cb(encoder_ctx->btn_handle, BUTTON_PRESS_UP, lvgl_port_encoder_btn_up_handler, encoder_ctx));
encoder_ctx->btn_enter = false;
/* Register a encoder input device */
lv_indev_drv_init(&encoder_ctx->indev_drv);
encoder_ctx->indev_drv.type = LV_INDEV_TYPE_ENCODER;
encoder_ctx->indev_drv.disp = encoder_cfg->disp;
encoder_ctx->indev_drv.read_cb = lvgl_port_encoder_read;
encoder_ctx->indev_drv.user_data = encoder_ctx;
indev = lv_indev_drv_register(&encoder_ctx->indev_drv);
err:
if (ret != ESP_OK) {
if (encoder_ctx->knob_handle != NULL) {
iot_knob_delete(encoder_ctx->knob_handle);
}
if (encoder_ctx->btn_handle != NULL) {
iot_button_delete(encoder_ctx->btn_handle);
}
if (encoder_ctx != NULL) {
free(encoder_ctx);
}
}
return indev;
}
esp_err_t lvgl_port_remove_encoder(lv_indev_t *encoder)
{
assert(encoder);
lv_indev_drv_t *indev_drv = encoder->driver;
assert(indev_drv);
lvgl_port_encoder_ctx_t *encoder_ctx = (lvgl_port_encoder_ctx_t *)indev_drv->user_data;
if (encoder_ctx->knob_handle != NULL) {
iot_knob_delete(encoder_ctx->knob_handle);
}
if (encoder_ctx->btn_handle != NULL) {
iot_button_delete(encoder_ctx->btn_handle);
}
if (encoder_ctx != NULL) {
free(encoder_ctx);
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
static int32_t last_v = 0;
assert(indev_drv);
lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *)indev_drv->user_data;
assert(ctx);
int32_t invd = iot_knob_get_count_value(ctx->knob_handle);
knob_event_t event = iot_knob_get_event(ctx->knob_handle);
if (last_v ^ invd) {
last_v = invd;
data->enc_diff = (KNOB_LEFT == event) ? (-1) : ((KNOB_RIGHT == event) ? (1) : (0));
} else {
data->enc_diff = 0;
}
data->state = (true == ctx->btn_enter) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
static void lvgl_port_encoder_btn_down_handler(void *arg, void *arg2)
{
lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* ENTER */
if (button == ctx->btn_handle) {
ctx->btn_enter = true;
}
}
}
static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2)
{
lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* ENTER */
if (button == ctx->btn_handle) {
ctx->btn_enter = false;
}
}
}

View File

@ -0,0 +1,101 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lcd_touch.h"
#include "esp_lvgl_port.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
esp_lcd_touch_handle_t handle; /* LCD touch IO handle */
lv_indev_drv_t indev_drv; /* LVGL input device driver */
} lvgl_port_touch_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg)
{
assert(touch_cfg != NULL);
assert(touch_cfg->disp != NULL);
assert(touch_cfg->handle != NULL);
/* Touch context */
lvgl_port_touch_ctx_t *touch_ctx = malloc(sizeof(lvgl_port_touch_ctx_t));
if (touch_ctx == NULL) {
ESP_LOGE(TAG, "Not enough memory for touch context allocation!");
return NULL;
}
touch_ctx->handle = touch_cfg->handle;
/* Register a touchpad input device */
lv_indev_drv_init(&touch_ctx->indev_drv);
touch_ctx->indev_drv.type = LV_INDEV_TYPE_POINTER;
touch_ctx->indev_drv.disp = touch_cfg->disp;
touch_ctx->indev_drv.read_cb = lvgl_port_touchpad_read;
touch_ctx->indev_drv.user_data = touch_ctx;
return lv_indev_drv_register(&touch_ctx->indev_drv);
}
esp_err_t lvgl_port_remove_touch(lv_indev_t *touch)
{
assert(touch);
lv_indev_drv_t *indev_drv = touch->driver;
assert(indev_drv);
lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)indev_drv->user_data;
/* Remove input device driver */
lv_indev_delete(touch);
if (touch_ctx) {
free(touch_ctx);
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
assert(indev_drv);
lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)indev_drv->user_data;
assert(touch_ctx->handle);
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
/* Read data from touch controller into memory */
esp_lcd_touch_read_data(touch_ctx->handle);
/* Read data from touch controller */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_ctx->handle, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
data->point.y = touchpad_y[0];
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}

View File

@ -0,0 +1,465 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lvgl_port.h"
#include "usb/hid_host.h"
#include "usb/hid_usage_keyboard.h"
#include "usb/hid_usage_mouse.h"
/* LVGL image of cursor */
LV_IMG_DECLARE(img_cursor)
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
QueueHandle_t queue; /* USB HID queue */
TaskHandle_t task; /* USB HID task */
bool running; /* USB HID task running */
struct {
lv_indev_drv_t drv; /* LVGL mouse input device driver */
uint8_t sensitivity; /* Mouse sensitivity (cannot be zero) */
int16_t x; /* Mouse X coordinate */
int16_t y; /* Mouse Y coordinate */
bool left_button; /* Mouse left button state */
} mouse;
struct {
lv_indev_drv_t drv; /* LVGL keyboard input device driver */
uint32_t last_key;
bool pressed;
} kb;
} lvgl_port_usb_hid_ctx_t;
typedef struct {
hid_host_device_handle_t hid_device_handle;
hid_host_driver_event_t event;
void *arg;
} lvgl_port_usb_hid_event_t;
/*******************************************************************************
* Local variables
*******************************************************************************/
static lvgl_port_usb_hid_ctx_t lvgl_hid_ctx;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static lvgl_port_usb_hid_ctx_t *lvgl_port_hid_init(void);
static void lvgl_port_usb_hid_task(void *arg);
static void lvgl_port_usb_hid_read_mouse(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_usb_hid_read_kb(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_usb_hid_callback(hid_host_device_handle_t hid_device_handle, const hid_host_driver_event_t event, void *arg);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_usb_hid_mouse_input(const lvgl_port_hid_mouse_cfg_t *mouse_cfg)
{
lv_indev_t *indev;
assert(mouse_cfg);
assert(mouse_cfg->disp);
assert(mouse_cfg->disp->driver);
/* Initialize USB HID */
lvgl_port_usb_hid_ctx_t *hid_ctx = lvgl_port_hid_init();
if (hid_ctx == NULL) {
return NULL;
}
/* Mouse sensitivity cannot be zero */
hid_ctx->mouse.sensitivity = (mouse_cfg->sensitivity == 0 ? 1 : mouse_cfg->sensitivity);
/* Default coordinates to screen center */
hid_ctx->mouse.x = (mouse_cfg->disp->driver->hor_res * hid_ctx->mouse.sensitivity) / 2;
hid_ctx->mouse.y = (mouse_cfg->disp->driver->ver_res * hid_ctx->mouse.sensitivity) / 2;
/* Register a mouse input device */
lv_indev_drv_init(&hid_ctx->mouse.drv);
hid_ctx->mouse.drv.type = LV_INDEV_TYPE_POINTER;
hid_ctx->mouse.drv.disp = mouse_cfg->disp;
hid_ctx->mouse.drv.read_cb = lvgl_port_usb_hid_read_mouse;
hid_ctx->mouse.drv.user_data = hid_ctx;
indev = lv_indev_drv_register(&hid_ctx->mouse.drv);
/* Set image of cursor */
lv_obj_t *cursor = mouse_cfg->cursor_img;
if (cursor == NULL) {
cursor = lv_img_create(lv_scr_act());
lv_img_set_src(cursor, &img_cursor);
}
lv_indev_set_cursor(indev, cursor);
return indev;
}
lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cfg_t *keyboard_cfg)
{
lv_indev_t *indev;
assert(keyboard_cfg);
assert(keyboard_cfg->disp);
/* Initialize USB HID */
lvgl_port_usb_hid_ctx_t *hid_ctx = lvgl_port_hid_init();
if (hid_ctx == NULL) {
return NULL;
}
/* Register a keyboard input device */
lv_indev_drv_init(&hid_ctx->kb.drv);
hid_ctx->kb.drv.type = LV_INDEV_TYPE_KEYPAD;
hid_ctx->kb.drv.disp = keyboard_cfg->disp;
hid_ctx->kb.drv.read_cb = lvgl_port_usb_hid_read_kb;
hid_ctx->kb.drv.user_data = hid_ctx;
indev = lv_indev_drv_register(&hid_ctx->kb.drv);
return indev;
}
esp_err_t lvgl_port_remove_usb_hid_input(lv_indev_t *hid)
{
assert(hid);
lv_indev_drv_t *indev_drv = hid->driver;
assert(indev_drv);
lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)indev_drv->user_data;
/* Remove input device driver */
lv_indev_delete(hid);
/* If all hid input devices are removed, stop task and clean all */
if (lvgl_hid_ctx.mouse.drv.disp == NULL && lvgl_hid_ctx.kb.drv.disp) {
hid_ctx->running = false;
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static lvgl_port_usb_hid_ctx_t *lvgl_port_hid_init(void)
{
esp_err_t ret;
/* USB HID is already initialized */
if (lvgl_hid_ctx.task) {
return &lvgl_hid_ctx;
}
/* USB HID host driver config */
const hid_host_driver_config_t hid_host_driver_config = {
.create_background_task = true,
.task_priority = 5,
.stack_size = 4096,
.core_id = 0,
.callback = lvgl_port_usb_hid_callback,
.callback_arg = &lvgl_hid_ctx,
};
ret = hid_host_install(&hid_host_driver_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "USB HID install failed!");
return NULL;
}
lvgl_hid_ctx.queue = xQueueCreate(10, sizeof(lvgl_port_usb_hid_event_t));
xTaskCreate(&lvgl_port_usb_hid_task, "hid_task", 4 * 1024, &lvgl_hid_ctx, 2, &lvgl_hid_ctx.task);
return &lvgl_hid_ctx;
}
static char usb_hid_get_keyboard_char(uint8_t key, uint8_t shift)
{
char ret_key = 0;
const uint8_t keycode2ascii [57][2] = {
{0, 0}, /* HID_KEY_NO_PRESS */
{0, 0}, /* HID_KEY_ROLLOVER */
{0, 0}, /* HID_KEY_POST_FAIL */
{0, 0}, /* HID_KEY_ERROR_UNDEFINED */
{'a', 'A'}, /* HID_KEY_A */
{'b', 'B'}, /* HID_KEY_B */
{'c', 'C'}, /* HID_KEY_C */
{'d', 'D'}, /* HID_KEY_D */
{'e', 'E'}, /* HID_KEY_E */
{'f', 'F'}, /* HID_KEY_F */
{'g', 'G'}, /* HID_KEY_G */
{'h', 'H'}, /* HID_KEY_H */
{'i', 'I'}, /* HID_KEY_I */
{'j', 'J'}, /* HID_KEY_J */
{'k', 'K'}, /* HID_KEY_K */
{'l', 'L'}, /* HID_KEY_L */
{'m', 'M'}, /* HID_KEY_M */
{'n', 'N'}, /* HID_KEY_N */
{'o', 'O'}, /* HID_KEY_O */
{'p', 'P'}, /* HID_KEY_P */
{'q', 'Q'}, /* HID_KEY_Q */
{'r', 'R'}, /* HID_KEY_R */
{'s', 'S'}, /* HID_KEY_S */
{'t', 'T'}, /* HID_KEY_T */
{'u', 'U'}, /* HID_KEY_U */
{'v', 'V'}, /* HID_KEY_V */
{'w', 'W'}, /* HID_KEY_W */
{'x', 'X'}, /* HID_KEY_X */
{'y', 'Y'}, /* HID_KEY_Y */
{'z', 'Z'}, /* HID_KEY_Z */
{'1', '!'}, /* HID_KEY_1 */
{'2', '@'}, /* HID_KEY_2 */
{'3', '#'}, /* HID_KEY_3 */
{'4', '$'}, /* HID_KEY_4 */
{'5', '%'}, /* HID_KEY_5 */
{'6', '^'}, /* HID_KEY_6 */
{'7', '&'}, /* HID_KEY_7 */
{'8', '*'}, /* HID_KEY_8 */
{'9', '('}, /* HID_KEY_9 */
{'0', ')'}, /* HID_KEY_0 */
{'\r', '\r'}, /* HID_KEY_ENTER */
{0, 0}, /* HID_KEY_ESC */
{'\b', 0}, /* HID_KEY_DEL */
{0, 0}, /* HID_KEY_TAB */
{' ', ' '}, /* HID_KEY_SPACE */
{'-', '_'}, /* HID_KEY_MINUS */
{'=', '+'}, /* HID_KEY_EQUAL */
{'[', '{'}, /* HID_KEY_OPEN_BRACKET */
{']', '}'}, /* HID_KEY_CLOSE_BRACKET */
{'\\', '|'}, /* HID_KEY_BACK_SLASH */
{'\\', '|'}, /* HID_KEY_SHARP */ // HOTFIX: for NonUS Keyboards repeat HID_KEY_BACK_SLASH
{';', ':'}, /* HID_KEY_COLON */
{'\'', '"'}, /* HID_KEY_QUOTE */
{'`', '~'}, /* HID_KEY_TILDE */
{',', '<'}, /* HID_KEY_LESS */
{'.', '>'}, /* HID_KEY_GREATER */
{'/', '?'} /* HID_KEY_SLASH */
};
if (shift > 1) {
shift = 1;
}
if ((key >= HID_KEY_A) && (key <= HID_KEY_SLASH)) {
ret_key = keycode2ascii[key][shift];
}
return ret_key;
}
static void lvgl_port_usb_hid_host_interface_callback(hid_host_device_handle_t hid_device_handle, const hid_host_interface_event_t event, void *arg)
{
hid_host_dev_params_t dev;
hid_host_device_get_params(hid_device_handle, &dev);
lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)arg;
uint8_t data[10];
unsigned int data_length = 0;
assert(hid_ctx != NULL);
switch (event) {
case HID_HOST_INTERFACE_EVENT_INPUT_REPORT:
hid_host_device_get_raw_input_report_data(hid_device_handle, data, sizeof(data), &data_length);
if (dev.proto == HID_PROTOCOL_KEYBOARD) {
hid_keyboard_input_report_boot_t *keyboard = (hid_keyboard_input_report_boot_t *)data;
if (data_length < sizeof(hid_keyboard_input_report_boot_t)) {
return;
}
for (int i = 0; i < HID_KEYBOARD_KEY_MAX; i++) {
if (keyboard->key[i] > HID_KEY_ERROR_UNDEFINED) {
char key = 0;
/* LVGL special keys */
if (keyboard->key[i] == HID_KEY_TAB) {
if ((keyboard->modifier.left_shift || keyboard->modifier.right_shift)) {
key = LV_KEY_PREV;
} else {
key = LV_KEY_NEXT;
}
} else if (keyboard->key[i] == HID_KEY_RIGHT) {
key = LV_KEY_RIGHT;
} else if (keyboard->key[i] == HID_KEY_LEFT) {
key = LV_KEY_LEFT;
} else if (keyboard->key[i] == HID_KEY_DOWN) {
key = LV_KEY_DOWN;
} else if (keyboard->key[i] == HID_KEY_UP) {
key = LV_KEY_UP;
} else if (keyboard->key[i] == HID_KEY_ENTER || keyboard->key[i] == HID_KEY_KEYPAD_ENTER) {
key = LV_KEY_ENTER;
} else if (keyboard->key[i] == HID_KEY_DELETE) {
key = LV_KEY_DEL;
} else if (keyboard->key[i] == HID_KEY_HOME) {
key = LV_KEY_HOME;
} else if (keyboard->key[i] == HID_KEY_END) {
key = LV_KEY_END;
} else {
/* Get ASCII char */
key = usb_hid_get_keyboard_char(keyboard->key[i], (keyboard->modifier.left_shift || keyboard->modifier.right_shift));
}
if (key == 0) {
ESP_LOGI(TAG, "Not recognized key: %c (%d)", keyboard->key[i], keyboard->key[i]);
}
hid_ctx->kb.last_key = key;
hid_ctx->kb.pressed = true;
}
}
} else if (dev.proto == HID_PROTOCOL_MOUSE) {
hid_mouse_input_report_boot_t *mouse = (hid_mouse_input_report_boot_t *)data;
if (data_length < sizeof(hid_mouse_input_report_boot_t)) {
break;
}
hid_ctx->mouse.left_button = mouse->buttons.button1;
hid_ctx->mouse.x += mouse->x_displacement;
hid_ctx->mouse.y += mouse->y_displacement;
}
break;
case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR:
break;
case HID_HOST_INTERFACE_EVENT_DISCONNECTED:
hid_host_device_close(hid_device_handle);
break;
default:
break;
}
}
static void lvgl_port_usb_hid_task(void *arg)
{
hid_host_dev_params_t dev;
lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)arg;
hid_host_device_handle_t hid_device_handle = NULL;
lvgl_port_usb_hid_event_t msg;
assert(ctx);
ctx->running = true;
while (ctx->running) {
if (xQueueReceive(ctx->queue, &msg, pdMS_TO_TICKS(50))) {
hid_device_handle = msg.hid_device_handle;
hid_host_device_get_params(hid_device_handle, &dev);
switch (msg.event) {
case HID_HOST_DRIVER_EVENT_CONNECTED:
/* Handle mouse or keyboard */
if (dev.proto == HID_PROTOCOL_KEYBOARD || dev.proto == HID_PROTOCOL_MOUSE) {
const hid_host_device_config_t dev_config = {
.callback = lvgl_port_usb_hid_host_interface_callback,
.callback_arg = ctx
};
ESP_ERROR_CHECK( hid_host_device_open(hid_device_handle, &dev_config) );
ESP_ERROR_CHECK( hid_class_request_set_idle(hid_device_handle, 0, 0) );
ESP_ERROR_CHECK( hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT) );
ESP_ERROR_CHECK( hid_host_device_start(hid_device_handle) );
}
break;
default:
break;
}
}
}
xQueueReset(ctx->queue);
vQueueDelete(ctx->queue);
hid_host_uninstall();
memset(&lvgl_hid_ctx, 0, sizeof(lvgl_port_usb_hid_ctx_t));
vTaskDelete(NULL);
}
static void lvgl_port_usb_hid_read_mouse(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
int16_t width = 0;
int16_t height = 0;
assert(indev_drv);
lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)indev_drv->user_data;
assert(ctx);
if (indev_drv->disp->driver->rotated == LV_DISP_ROT_NONE || indev_drv->disp->driver->rotated == LV_DISP_ROT_180) {
width = indev_drv->disp->driver->hor_res;
height = indev_drv->disp->driver->ver_res;
} else {
width = indev_drv->disp->driver->ver_res;
height = indev_drv->disp->driver->hor_res;
}
/* Screen borders */
if (ctx->mouse.x < 0) {
ctx->mouse.x = 0;
} else if (ctx->mouse.x > width * ctx->mouse.sensitivity) {
ctx->mouse.x = width * ctx->mouse.sensitivity;
}
if (ctx->mouse.y < 0) {
ctx->mouse.y = 0;
} else if (ctx->mouse.y > height * ctx->mouse.sensitivity) {
ctx->mouse.y = height * ctx->mouse.sensitivity;
}
/* Get coordinates by rotation with sensitivity */
switch (indev_drv->disp->driver->rotated) {
case LV_DISP_ROT_NONE:
data->point.x = ctx->mouse.x / ctx->mouse.sensitivity;
data->point.y = ctx->mouse.y / ctx->mouse.sensitivity;
break;
case LV_DISP_ROT_90:
data->point.y = width - ctx->mouse.x / ctx->mouse.sensitivity;
data->point.x = ctx->mouse.y / ctx->mouse.sensitivity;
break;
case LV_DISP_ROT_180:
data->point.x = width - ctx->mouse.x / ctx->mouse.sensitivity;
data->point.y = height - ctx->mouse.y / ctx->mouse.sensitivity;
break;
case LV_DISP_ROT_270:
data->point.y = ctx->mouse.x / ctx->mouse.sensitivity;
data->point.x = height - ctx->mouse.y / ctx->mouse.sensitivity;
break;
}
if (ctx->mouse.left_button) {
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
static void lvgl_port_usb_hid_read_kb(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
assert(indev_drv);
lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)indev_drv->user_data;
assert(ctx);
data->key = ctx->kb.last_key;
if (ctx->kb.pressed) {
data->state = LV_INDEV_STATE_PRESSED;
ctx->kb.pressed = false;
} else {
data->state = LV_INDEV_STATE_RELEASED;
ctx->kb.last_key = 0;
}
}
static void lvgl_port_usb_hid_callback(hid_host_device_handle_t hid_device_handle, const hid_host_driver_event_t event, void *arg)
{
lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)arg;
const lvgl_port_usb_hid_event_t msg = {
.hid_device_handle = hid_device_handle,
.event = event,
.arg = arg
};
xQueueSend(hid_ctx->queue, &msg, 0);
}

View File

@ -0,0 +1,198 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_system.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_lvgl_port.h"
#include "lvgl.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct lvgl_port_ctx_s {
SemaphoreHandle_t lvgl_mux;
esp_timer_handle_t tick_timer;
bool running;
int task_max_sleep_ms;
int timer_period_ms;
} lvgl_port_ctx_t;
/*******************************************************************************
* Local variables
*******************************************************************************/
static lvgl_port_ctx_t lvgl_port_ctx;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_task(void *arg);
static esp_err_t lvgl_port_tick_init(void);
static void lvgl_port_task_deinit(void);
/*******************************************************************************
* Public API functions
*******************************************************************************/
esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(cfg->task_affinity < (configNUM_CORES), ESP_ERR_INVALID_ARG, err, TAG, "Bad core number for task! Maximum core number is %d", (configNUM_CORES - 1));
memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx));
/* LVGL init */
lv_init();
/* Tick init */
lvgl_port_ctx.timer_period_ms = cfg->timer_period_ms;
ESP_RETURN_ON_ERROR(lvgl_port_tick_init(), TAG, "");
/* Create task */
lvgl_port_ctx.task_max_sleep_ms = cfg->task_max_sleep_ms;
if (lvgl_port_ctx.task_max_sleep_ms == 0) {
lvgl_port_ctx.task_max_sleep_ms = 500;
}
lvgl_port_ctx.lvgl_mux = xSemaphoreCreateRecursiveMutex();
ESP_GOTO_ON_FALSE(lvgl_port_ctx.lvgl_mux, ESP_ERR_NO_MEM, err, TAG, "Create LVGL mutex fail!");
BaseType_t res;
if (cfg->task_affinity < 0) {
res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL);
} else {
res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, NULL, cfg->task_affinity);
}
ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!");
err:
if (ret != ESP_OK) {
lvgl_port_deinit();
}
return ret;
}
esp_err_t lvgl_port_resume(void)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
if (lvgl_port_ctx.tick_timer != NULL) {
lv_timer_enable(true);
ret = esp_timer_start_periodic(lvgl_port_ctx.tick_timer, lvgl_port_ctx.timer_period_ms * 1000);
}
return ret;
}
esp_err_t lvgl_port_stop(void)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
if (lvgl_port_ctx.tick_timer != NULL) {
lv_timer_enable(false);
ret = esp_timer_stop(lvgl_port_ctx.tick_timer);
}
return ret;
}
esp_err_t lvgl_port_deinit(void)
{
/* Stop and delete timer */
if (lvgl_port_ctx.tick_timer != NULL) {
esp_timer_stop(lvgl_port_ctx.tick_timer);
esp_timer_delete(lvgl_port_ctx.tick_timer);
lvgl_port_ctx.tick_timer = NULL;
}
/* Stop running task */
if (lvgl_port_ctx.running) {
lvgl_port_ctx.running = false;
} else {
lvgl_port_task_deinit();
}
return ESP_OK;
}
bool lvgl_port_lock(uint32_t timeout_ms)
{
assert(lvgl_port_ctx.lvgl_mux && "lvgl_port_init must be called first");
const TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
return xSemaphoreTakeRecursive(lvgl_port_ctx.lvgl_mux, timeout_ticks) == pdTRUE;
}
void lvgl_port_unlock(void)
{
assert(lvgl_port_ctx.lvgl_mux && "lvgl_port_init must be called first");
xSemaphoreGiveRecursive(lvgl_port_ctx.lvgl_mux);
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_task(void *arg)
{
uint32_t task_delay_ms = lvgl_port_ctx.task_max_sleep_ms;
ESP_LOGI(TAG, "Starting LVGL task");
lvgl_port_ctx.running = true;
while (lvgl_port_ctx.running) {
if (lv_display_get_default() && lvgl_port_lock(0)) {
task_delay_ms = lv_timer_handler();
lvgl_port_unlock();
}
if ((task_delay_ms > lvgl_port_ctx.task_max_sleep_ms) || (1 == task_delay_ms)) {
task_delay_ms = lvgl_port_ctx.task_max_sleep_ms;
} else if (task_delay_ms < 1) {
task_delay_ms = 1;
}
vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
}
lvgl_port_task_deinit();
/* Close task */
vTaskDelete( NULL );
}
static void lvgl_port_task_deinit(void)
{
if (lvgl_port_ctx.lvgl_mux) {
vSemaphoreDelete(lvgl_port_ctx.lvgl_mux);
}
memset(&lvgl_port_ctx, 0, sizeof(lvgl_port_ctx));
#if LV_ENABLE_GC || !LV_MEM_CUSTOM
/* Deinitialize LVGL */
lv_deinit();
#endif
}
static void lvgl_port_tick_increment(void *arg)
{
/* Tell LVGL how many milliseconds have elapsed */
lv_tick_inc(lvgl_port_ctx.timer_period_ms);
}
static esp_err_t lvgl_port_tick_init(void)
{
// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_port_tick_increment,
.name = "LVGL tick",
};
ESP_RETURN_ON_ERROR(esp_timer_create(&lvgl_tick_timer_args, &lvgl_port_ctx.tick_timer), TAG, "Creating LVGL timer filed!");
return esp_timer_start_periodic(lvgl_port_ctx.tick_timer, lvgl_port_ctx.timer_period_ms * 1000);
}

View File

@ -0,0 +1,203 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lvgl_port.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef enum {
LVGL_PORT_NAV_BTN_PREV,
LVGL_PORT_NAV_BTN_NEXT,
LVGL_PORT_NAV_BTN_ENTER,
LVGL_PORT_NAV_BTN_CNT,
} lvgl_port_nav_btns_t;
typedef struct {
button_handle_t btn[LVGL_PORT_NAV_BTN_CNT]; /* Button handlers */
lv_indev_t *indev; /* LVGL input device driver */
bool btn_prev; /* Button prev state */
bool btn_next; /* Button next state */
bool btn_enter; /* Button enter state */
} lvgl_port_nav_btns_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_navigation_buttons_read(lv_indev_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_btn_down_handler(void *arg, void *arg2);
static void lvgl_port_btn_up_handler(void *arg, void *arg2);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_navigation_buttons(const lvgl_port_nav_btns_cfg_t *buttons_cfg)
{
lv_indev_t *indev;
esp_err_t ret = ESP_OK;
assert(buttons_cfg != NULL);
assert(buttons_cfg->disp != NULL);
/* Touch context */
lvgl_port_nav_btns_ctx_t *buttons_ctx = malloc(sizeof(lvgl_port_nav_btns_ctx_t));
if (buttons_ctx == NULL) {
ESP_LOGE(TAG, "Not enough memory for buttons context allocation!");
return NULL;
}
/* Previous button */
if (buttons_cfg->button_prev != NULL) {
buttons_ctx->btn[LVGL_PORT_NAV_BTN_PREV] = iot_button_create(buttons_cfg->button_prev);
ESP_GOTO_ON_FALSE(buttons_ctx->btn[LVGL_PORT_NAV_BTN_PREV], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
/* Next button */
if (buttons_cfg->button_next != NULL) {
buttons_ctx->btn[LVGL_PORT_NAV_BTN_NEXT] = iot_button_create(buttons_cfg->button_next);
ESP_GOTO_ON_FALSE(buttons_ctx->btn[LVGL_PORT_NAV_BTN_NEXT], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
/* Enter button */
if (buttons_cfg->button_enter != NULL) {
buttons_ctx->btn[LVGL_PORT_NAV_BTN_ENTER] = iot_button_create(buttons_cfg->button_enter);
ESP_GOTO_ON_FALSE(buttons_ctx->btn[LVGL_PORT_NAV_BTN_ENTER], ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
/* Button handlers */
for (int i = 0; i < LVGL_PORT_NAV_BTN_CNT; i++) {
ESP_ERROR_CHECK(iot_button_register_cb(buttons_ctx->btn[i], BUTTON_PRESS_DOWN, lvgl_port_btn_down_handler, buttons_ctx));
ESP_ERROR_CHECK(iot_button_register_cb(buttons_ctx->btn[i], BUTTON_PRESS_UP, lvgl_port_btn_up_handler, buttons_ctx));
}
buttons_ctx->btn_prev = false;
buttons_ctx->btn_next = false;
buttons_ctx->btn_enter = false;
lvgl_port_lock(0);
/* Register a touchpad input device */
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER);
lv_indev_set_read_cb(indev, lvgl_port_navigation_buttons_read);
lv_indev_set_disp(indev, buttons_cfg->disp);
lv_indev_set_user_data(indev, buttons_ctx);
//buttons_ctx->indev->long_press_repeat_time = 300;
buttons_ctx->indev = indev;
lvgl_port_unlock();
return indev;
err:
if (ret != ESP_OK) {
for (int i = 0; i < LVGL_PORT_NAV_BTN_CNT; i++) {
if (buttons_ctx->btn[i] != NULL) {
iot_button_delete(buttons_ctx->btn[i]);
}
}
if (buttons_ctx != NULL) {
free(buttons_ctx);
}
}
return buttons_ctx->indev;
}
esp_err_t lvgl_port_remove_navigation_buttons(lv_indev_t *buttons)
{
assert(buttons);
lvgl_port_nav_btns_ctx_t *buttons_ctx = (lvgl_port_nav_btns_ctx_t *)lv_indev_get_user_data(buttons);
lvgl_port_lock(0);
/* Remove input device driver */
lv_indev_delete(buttons);
lvgl_port_unlock();
if (buttons_ctx) {
free(buttons_ctx);
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_navigation_buttons_read(lv_indev_t *indev_drv, lv_indev_data_t *data)
{
static uint32_t last_key = 0;
assert(indev_drv);
lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *)lv_indev_get_user_data(indev_drv);
assert(ctx);
/* Buttons */
if (ctx->btn_prev) {
data->key = LV_KEY_LEFT;
last_key = LV_KEY_LEFT;
data->state = LV_INDEV_STATE_PRESSED;
} else if (ctx->btn_next) {
data->key = LV_KEY_RIGHT;
last_key = LV_KEY_RIGHT;
data->state = LV_INDEV_STATE_PRESSED;
} else if (ctx->btn_enter) {
data->key = LV_KEY_ENTER;
last_key = LV_KEY_ENTER;
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->key = last_key;
data->state = LV_INDEV_STATE_RELEASED;
}
}
static void lvgl_port_btn_down_handler(void *arg, void *arg2)
{
lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* PREV */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_PREV]) {
ctx->btn_prev = true;
}
/* NEXT */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_NEXT]) {
ctx->btn_next = true;
}
/* ENTER */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_ENTER]) {
ctx->btn_enter = true;
}
}
}
static void lvgl_port_btn_up_handler(void *arg, void *arg2)
{
lvgl_port_nav_btns_ctx_t *ctx = (lvgl_port_nav_btns_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* PREV */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_PREV]) {
ctx->btn_prev = false;
}
/* NEXT */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_NEXT]) {
ctx->btn_next = false;
}
/* ENTER */
if (button == ctx->btn[LVGL_PORT_NAV_BTN_ENTER]) {
ctx->btn_enter = false;
}
}
}

View File

@ -0,0 +1,292 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lvgl_port.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 4)) || (ESP_IDF_VERSION == ESP_IDF_VERSION_VAL(5, 0, 0))
#define LVGL_PORT_HANDLE_FLUSH_READY 0
#else
#define LVGL_PORT_HANDLE_FLUSH_READY 1
#endif
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */
esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */
lvgl_port_rotation_cfg_t rotation; /* Default values of the screen rotation */
lv_color16_t *draw_buffs[2]; /* Display draw buffers */
lv_display_t *disp_drv; /* LVGL display driver */
struct {
unsigned int monochrome: 1; /* True, if display is monochrome and using 1bit for 1px */
unsigned int swap_bytes: 1; /* Swap bytes in RGB656 (16-bit) before send to LCD driver */
} flags;
} lvgl_port_display_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
#if LVGL_PORT_HANDLE_FLUSH_READY
static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx);
#endif
static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map);
static void lvgl_port_disp_size_update_callback(lv_event_t *e);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_display_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg)
{
esp_err_t ret = ESP_OK;
lv_display_t *disp = NULL;
lv_color16_t *buf1 = NULL;
lv_color16_t *buf2 = NULL;
assert(disp_cfg != NULL);
assert(disp_cfg->io_handle != NULL);
assert(disp_cfg->panel_handle != NULL);
assert(disp_cfg->buffer_size > 0);
assert(disp_cfg->hres > 0);
assert(disp_cfg->vres > 0);
/* Display context */
lvgl_port_display_ctx_t *disp_ctx = malloc(sizeof(lvgl_port_display_ctx_t));
ESP_GOTO_ON_FALSE(disp_ctx, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for display context allocation!");
disp_ctx->io_handle = disp_cfg->io_handle;
disp_ctx->panel_handle = disp_cfg->panel_handle;
disp_ctx->rotation.swap_xy = disp_cfg->rotation.swap_xy;
disp_ctx->rotation.mirror_x = disp_cfg->rotation.mirror_x;
disp_ctx->rotation.mirror_y = disp_cfg->rotation.mirror_y;
disp_ctx->flags.swap_bytes = disp_cfg->flags.swap_bytes;
uint32_t buff_caps = MALLOC_CAP_DEFAULT;
if (disp_cfg->flags.buff_dma && disp_cfg->flags.buff_spiram) {
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "Alloc DMA capable buffer in SPIRAM is not supported!");
} else if (disp_cfg->flags.buff_dma) {
buff_caps = MALLOC_CAP_DMA;
} else if (disp_cfg->flags.buff_spiram) {
buff_caps = MALLOC_CAP_SPIRAM;
}
/* alloc draw buffers used by LVGL */
/* it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized */
buf1 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color16_t), buff_caps);
ESP_GOTO_ON_FALSE(buf1, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf1) allocation!");
if (disp_cfg->double_buffer) {
buf2 = heap_caps_malloc(disp_cfg->buffer_size * sizeof(lv_color16_t), buff_caps);
ESP_GOTO_ON_FALSE(buf2, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for LVGL buffer (buf2) allocation!");
}
disp_ctx->draw_buffs[0] = buf1;
disp_ctx->draw_buffs[1] = buf2;
lvgl_port_lock(0);
disp = lv_display_create(disp_cfg->hres, disp_cfg->vres);
/* Monochrome display settings */
if (disp_cfg->monochrome) {
/* When using monochromatic display, there must be used full bufer! */
ESP_GOTO_ON_FALSE((disp_cfg->hres * disp_cfg->vres == disp_cfg->buffer_size), ESP_ERR_INVALID_ARG, err, TAG, "Monochromatic display must using full buffer!");
disp_ctx->flags.monochrome = 1;
//lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
lv_display_set_buffers(disp, buf1, buf2, disp_cfg->buffer_size * sizeof(lv_color16_t), LV_DISPLAY_RENDER_MODE_FULL);
} else {
lv_display_set_buffers(disp, buf1, buf2, disp_cfg->buffer_size * sizeof(lv_color16_t), LV_DISPLAY_RENDER_MODE_PARTIAL);
}
lv_display_set_flush_cb(disp, lvgl_port_flush_callback);
lv_display_add_event_cb(disp, lvgl_port_disp_size_update_callback, LV_EVENT_RESOLUTION_CHANGED, disp_ctx);
lv_display_set_user_data(disp, disp_ctx);
disp_ctx->disp_drv = disp;
#if LVGL_PORT_HANDLE_FLUSH_READY
/* Register done callback */
const esp_lcd_panel_io_callbacks_t cbs = {
.on_color_trans_done = lvgl_port_flush_ready_callback,
};
esp_lcd_panel_io_register_event_callbacks(disp_ctx->io_handle, &cbs, disp_ctx->disp_drv);
#endif
lvgl_port_unlock();
err:
if (ret != ESP_OK) {
if (buf1) {
free(buf1);
}
if (buf2) {
free(buf2);
}
if (disp_ctx) {
free(disp_ctx);
}
}
return disp;
}
esp_err_t lvgl_port_remove_disp(lv_display_t *disp)
{
assert(disp);
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(disp);
lvgl_port_lock(0);
lv_disp_remove(disp);
lvgl_port_unlock();
if (disp_ctx->draw_buffs[0]) {
free(disp_ctx->draw_buffs[0]);
}
if (disp_ctx->draw_buffs[1]) {
free(disp_ctx->draw_buffs[1]);
}
free(disp_ctx);
return ESP_OK;
}
void lvgl_port_flush_ready(lv_display_t *disp)
{
assert(disp);
lv_disp_flush_ready(disp);
}
/*******************************************************************************
* Private functions
*******************************************************************************/
#if LVGL_PORT_HANDLE_FLUSH_READY
static bool lvgl_port_flush_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
lv_display_t *disp_drv = (lv_display_t *)user_ctx;
assert(disp_drv != NULL);
lv_disp_flush_ready(disp_drv);
return false;
}
#endif
static void _lvgl_port_transform_monochrome(lv_display_t *display, const lv_area_t *area, uint8_t *color_map)
{
uint8_t *buf = color_map;
lv_color16_t *color = (lv_color16_t *)color_map;
uint16_t hor_res = lv_display_get_physical_horizontal_resolution(display);
uint16_t ver_res = lv_display_get_physical_vertical_resolution(display);
uint16_t res = hor_res;
bool swap_xy = (lv_display_get_rotation(display) == LV_DISPLAY_ROTATION_90 || lv_display_get_rotation(display) == LV_DISPLAY_ROTATION_270);
int x1 = area->x1;
int x2 = area->x2;
int y1 = area->y1;
int y2 = area->y2;
int out_x, out_y;
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
bool chroma_color = (color[hor_res * y + x].blue > 16);
if (swap_xy) {
out_x = y;
out_y = x;
res = ver_res;
} else {
out_x = x;
out_y = y;
res = hor_res;
}
/* Write to the buffer as required for the display.
* It writes only 1-bit for monochrome displays mapped vertically.*/
buf = color_map + res * (out_y >> 3) + (out_x);
if (chroma_color) {
(*buf) &= ~(1 << (out_y % 8));
} else {
(*buf) |= (1 << (out_y % 8));
}
}
}
}
static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map)
{
assert(drv != NULL);
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)lv_display_get_user_data(drv);
assert(disp_ctx != NULL);
//TODO: try to use SPI_SWAP_DATA_RX from https://docs.espressif.com/projects/esp-idf/en/v5.1/esp32s3/api-reference/peripherals/spi_master.html#c.SPI_SWAP_DATA_TX
if (disp_ctx->flags.swap_bytes) {
size_t len = lv_area_get_size(area);
lv_draw_sw_rgb565_swap(color_map, len);
}
/* Transfor data in buffer for monochromatic screen */
if (disp_ctx->flags.monochrome) {
_lvgl_port_transform_monochrome(drv, area, color_map);
}
const int offsetx1 = area->x1;
const int offsetx2 = area->x2;
const int offsety1 = area->y1;
const int offsety2 = area->y2;
// copy a buffer's content to a specific area of the display
esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
}
static void lvgl_port_disp_size_update_callback(lv_event_t *e)
{
assert(e);
lvgl_port_display_ctx_t *disp_ctx = (lvgl_port_display_ctx_t *)e->user_data;
assert(disp_ctx != NULL);
esp_lcd_panel_handle_t panel_handle = disp_ctx->panel_handle;
/* Solve rotation screen and touch */
switch (lv_display_get_rotation(disp_ctx->disp_drv)) {
case LV_DISPLAY_ROTATION_0:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy);
esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y);
break;
case LV_DISPLAY_ROTATION_90:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy);
if (disp_ctx->rotation.swap_xy) {
esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y);
} else {
esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y);
}
break;
case LV_DISPLAY_ROTATION_180:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, disp_ctx->rotation.swap_xy);
esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y);
break;
case LV_DISPLAY_ROTATION_270:
/* Rotate LCD display */
esp_lcd_panel_swap_xy(panel_handle, !disp_ctx->rotation.swap_xy);
if (disp_ctx->rotation.swap_xy) {
esp_lcd_panel_mirror(panel_handle, disp_ctx->rotation.mirror_x, !disp_ctx->rotation.mirror_y);
} else {
esp_lcd_panel_mirror(panel_handle, !disp_ctx->rotation.mirror_x, disp_ctx->rotation.mirror_y);
}
break;
}
}

View File

@ -0,0 +1,165 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lvgl_port.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
knob_handle_t knob_handle; /* Encoder knob handlers */
button_handle_t btn_handle; /* Encoder button handlers */
lv_indev_t *indev; /* LVGL input device driver */
bool btn_enter; /* Encoder button enter state */
} lvgl_port_encoder_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_encoder_read(lv_indev_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_encoder_btn_down_handler(void *arg, void *arg2);
static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_encoder(const lvgl_port_encoder_cfg_t *encoder_cfg)
{
lv_indev_t *indev;
esp_err_t ret = ESP_OK;
assert(encoder_cfg != NULL);
assert(encoder_cfg->disp != NULL);
/* Encoder context */
lvgl_port_encoder_ctx_t *encoder_ctx = malloc(sizeof(lvgl_port_encoder_ctx_t));
if (encoder_ctx == NULL) {
ESP_LOGE(TAG, "Not enough memory for encoder context allocation!");
return NULL;
}
/* Encoder_a/b */
if (encoder_cfg->encoder_a_b != NULL) {
encoder_ctx->knob_handle = iot_knob_create(encoder_cfg->encoder_a_b);
ESP_GOTO_ON_FALSE(encoder_ctx->knob_handle, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for knob create!");
}
/* Encoder Enter */
if (encoder_cfg->encoder_enter != NULL) {
encoder_ctx->btn_handle = iot_button_create(encoder_cfg->encoder_enter);
ESP_GOTO_ON_FALSE(encoder_ctx->btn_handle, ESP_ERR_NO_MEM, err, TAG, "Not enough memory for button create!");
}
ESP_ERROR_CHECK(iot_button_register_cb(encoder_ctx->btn_handle, BUTTON_PRESS_DOWN, lvgl_port_encoder_btn_down_handler, encoder_ctx));
ESP_ERROR_CHECK(iot_button_register_cb(encoder_ctx->btn_handle, BUTTON_PRESS_UP, lvgl_port_encoder_btn_up_handler, encoder_ctx));
encoder_ctx->btn_enter = false;
lvgl_port_lock(0);
/* Register a encoder input device */
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER);
lv_indev_set_read_cb(indev, lvgl_port_encoder_read);
lv_indev_set_disp(indev, encoder_cfg->disp);
lv_indev_set_user_data(indev, encoder_ctx);
encoder_ctx->indev = indev;
lvgl_port_unlock();
err:
if (ret != ESP_OK) {
if (encoder_ctx->knob_handle != NULL) {
iot_knob_delete(encoder_ctx->knob_handle);
}
if (encoder_ctx->btn_handle != NULL) {
iot_button_delete(encoder_ctx->btn_handle);
}
if (encoder_ctx != NULL) {
free(encoder_ctx);
}
}
return encoder_ctx->indev;
}
esp_err_t lvgl_port_remove_encoder(lv_indev_t *encoder)
{
assert(encoder);
lvgl_port_encoder_ctx_t *encoder_ctx = (lvgl_port_encoder_ctx_t *)lv_indev_get_user_data(encoder);
if (encoder_ctx->knob_handle != NULL) {
iot_knob_delete(encoder_ctx->knob_handle);
}
if (encoder_ctx->btn_handle != NULL) {
iot_button_delete(encoder_ctx->btn_handle);
}
lvgl_port_lock(0);
/* Remove input device driver */
lv_indev_delete(encoder);
lvgl_port_unlock();
if (encoder_ctx != NULL) {
free(encoder_ctx);
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_encoder_read(lv_indev_t *indev_drv, lv_indev_data_t *data)
{
static int32_t last_v = 0;
assert(indev_drv);
lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *)lv_indev_get_user_data(indev_drv);
assert(ctx);
int32_t invd = iot_knob_get_count_value(ctx->knob_handle);
knob_event_t event = iot_knob_get_event(ctx->knob_handle);
if (last_v ^ invd) {
last_v = invd;
data->enc_diff = (KNOB_LEFT == event) ? (-1) : ((KNOB_RIGHT == event) ? (1) : (0));
} else {
data->enc_diff = 0;
}
data->state = (true == ctx->btn_enter) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
static void lvgl_port_encoder_btn_down_handler(void *arg, void *arg2)
{
lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* ENTER */
if (button == ctx->btn_handle) {
ctx->btn_enter = true;
}
}
}
static void lvgl_port_encoder_btn_up_handler(void *arg, void *arg2)
{
lvgl_port_encoder_ctx_t *ctx = (lvgl_port_encoder_ctx_t *) arg2;
button_handle_t button = (button_handle_t)arg;
if (ctx && button) {
/* ENTER */
if (button == ctx->btn_handle) {
ctx->btn_enter = false;
}
}
}

View File

@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lcd_touch.h"
#include "esp_lvgl_port.h"
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
esp_lcd_touch_handle_t handle; /* LCD touch IO handle */
lv_indev_t *indev; /* LVGL input device driver */
} lvgl_port_touch_ctx_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static void lvgl_port_touchpad_read(lv_indev_t *indev_drv, lv_indev_data_t *data);
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg)
{
lv_indev_t *indev;
assert(touch_cfg != NULL);
assert(touch_cfg->disp != NULL);
assert(touch_cfg->handle != NULL);
/* Touch context */
lvgl_port_touch_ctx_t *touch_ctx = malloc(sizeof(lvgl_port_touch_ctx_t));
if (touch_ctx == NULL) {
ESP_LOGE(TAG, "Not enough memory for touch context allocation!");
return NULL;
}
touch_ctx->handle = touch_cfg->handle;
lvgl_port_lock(0);
/* Register a touchpad input device */
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, lvgl_port_touchpad_read);
lv_indev_set_disp(indev, touch_cfg->disp);
lv_indev_set_user_data(indev, touch_ctx);
touch_ctx->indev = indev;
lvgl_port_unlock();
return indev;
}
esp_err_t lvgl_port_remove_touch(lv_indev_t *touch)
{
assert(touch);
lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)lv_indev_get_user_data(touch);
lvgl_port_lock(0);
/* Remove input device driver */
lv_indev_delete(touch);
lvgl_port_unlock();
if (touch_ctx) {
free(touch_ctx);
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static void lvgl_port_touchpad_read(lv_indev_t *indev_drv, lv_indev_data_t *data)
{
assert(indev_drv);
lvgl_port_touch_ctx_t *touch_ctx = (lvgl_port_touch_ctx_t *)lv_indev_get_user_data(indev_drv);
assert(touch_ctx);
assert(touch_ctx->handle);
uint16_t touchpad_x[1] = {0};
uint16_t touchpad_y[1] = {0};
uint8_t touchpad_cnt = 0;
/* Read data from touch controller into memory */
esp_lcd_touch_read_data(touch_ctx->handle);
/* Read data from touch controller */
bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_ctx->handle, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
if (touchpad_pressed && touchpad_cnt > 0) {
data->point.x = touchpad_x[0];
data->point.y = touchpad_y[0];
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}

View File

@ -0,0 +1,479 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lvgl_port.h"
#include "usb/hid_host.h"
#include "usb/hid_usage_keyboard.h"
#include "usb/hid_usage_mouse.h"
/* LVGL image of cursor */
LV_IMG_DECLARE(img_cursor)
static const char *TAG = "LVGL";
/*******************************************************************************
* Types definitions
*******************************************************************************/
typedef struct {
QueueHandle_t queue; /* USB HID queue */
TaskHandle_t task; /* USB HID task */
bool running; /* USB HID task running */
struct {
lv_indev_t *indev; /* LVGL mouse input device driver */
uint8_t sensitivity; /* Mouse sensitivity (cannot be zero) */
int16_t x; /* Mouse X coordinate */
int16_t y; /* Mouse Y coordinate */
bool left_button; /* Mouse left button state */
} mouse;
struct {
lv_indev_t *indev; /* LVGL keyboard input device driver */
uint32_t last_key;
bool pressed;
} kb;
} lvgl_port_usb_hid_ctx_t;
typedef struct {
hid_host_device_handle_t hid_device_handle;
hid_host_driver_event_t event;
void *arg;
} lvgl_port_usb_hid_event_t;
/*******************************************************************************
* Function definitions
*******************************************************************************/
static lvgl_port_usb_hid_ctx_t *lvgl_port_hid_init(void);
static void lvgl_port_usb_hid_task(void *arg);
static void lvgl_port_usb_hid_read_mouse(lv_indev_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_usb_hid_read_kb(lv_indev_t *indev_drv, lv_indev_data_t *data);
static void lvgl_port_usb_hid_callback(hid_host_device_handle_t hid_device_handle, const hid_host_driver_event_t event, void *arg);
/*******************************************************************************
* Local variables
*******************************************************************************/
static lvgl_port_usb_hid_ctx_t lvgl_hid_ctx;
/*******************************************************************************
* Public API functions
*******************************************************************************/
lv_indev_t *lvgl_port_add_usb_hid_mouse_input(const lvgl_port_hid_mouse_cfg_t *mouse_cfg)
{
lv_indev_t *indev;
assert(mouse_cfg);
assert(mouse_cfg->disp);
/* Initialize USB HID */
lvgl_port_usb_hid_ctx_t *hid_ctx = lvgl_port_hid_init();
if (hid_ctx == NULL) {
return NULL;
}
/* Mouse sensitivity cannot be zero */
hid_ctx->mouse.sensitivity = (mouse_cfg->sensitivity == 0 ? 1 : mouse_cfg->sensitivity);
int32_t ver_res = lv_display_get_vertical_resolution(mouse_cfg->disp);
int32_t hor_res = lv_display_get_physical_horizontal_resolution(mouse_cfg->disp);
/* Default coordinates to screen center */
hid_ctx->mouse.x = (hor_res * hid_ctx->mouse.sensitivity) / 2;
hid_ctx->mouse.y = (ver_res * hid_ctx->mouse.sensitivity) / 2;
lvgl_port_lock(0);
/* Register a mouse input device */
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, lvgl_port_usb_hid_read_mouse);
lv_indev_set_disp(indev, mouse_cfg->disp);
lv_indev_set_user_data(indev, hid_ctx);
hid_ctx->mouse.indev = indev;
lvgl_port_unlock();
/* Set image of cursor */
lv_obj_t *cursor = mouse_cfg->cursor_img;
if (cursor == NULL) {
cursor = lv_img_create(lv_scr_act());
lv_img_set_src(cursor, &img_cursor);
}
lv_indev_set_cursor(indev, cursor);
return indev;
}
lv_indev_t *lvgl_port_add_usb_hid_keyboard_input(const lvgl_port_hid_keyboard_cfg_t *keyboard_cfg)
{
lv_indev_t *indev;
assert(keyboard_cfg);
assert(keyboard_cfg->disp);
/* Initialize USB HID */
lvgl_port_usb_hid_ctx_t *hid_ctx = lvgl_port_hid_init();
if (hid_ctx == NULL) {
return NULL;
}
lvgl_port_lock(0);
/* Register a mouse input device */
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(indev, lvgl_port_usb_hid_read_kb);
lv_indev_set_disp(indev, keyboard_cfg->disp);
lv_indev_set_user_data(indev, hid_ctx);
hid_ctx->kb.indev = indev;
lvgl_port_unlock();
return indev;
}
esp_err_t lvgl_port_remove_usb_hid_input(lv_indev_t *hid)
{
assert(hid);
lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_user_data(hid);
lvgl_port_lock(0);
/* Remove input device driver */
lv_indev_delete(hid);
lvgl_port_unlock();
if (lvgl_hid_ctx.mouse.indev == hid) {
lvgl_hid_ctx.mouse.indev = NULL;
} else if (lvgl_hid_ctx.kb.indev == hid) {
lvgl_hid_ctx.kb.indev = NULL;
}
/* If all hid input devices are removed, stop task and clean all */
if (lvgl_hid_ctx.mouse.indev == NULL && lvgl_hid_ctx.kb.indev) {
hid_ctx->running = false;
}
return ESP_OK;
}
/*******************************************************************************
* Private functions
*******************************************************************************/
static lvgl_port_usb_hid_ctx_t *lvgl_port_hid_init(void)
{
esp_err_t ret;
/* USB HID is already initialized */
if (lvgl_hid_ctx.task) {
return &lvgl_hid_ctx;
}
/* USB HID host driver config */
const hid_host_driver_config_t hid_host_driver_config = {
.create_background_task = true,
.task_priority = 5,
.stack_size = 4096,
.core_id = 0,
.callback = lvgl_port_usb_hid_callback,
.callback_arg = &lvgl_hid_ctx,
};
ret = hid_host_install(&hid_host_driver_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "USB HID install failed!");
return NULL;
}
lvgl_hid_ctx.queue = xQueueCreate(10, sizeof(lvgl_port_usb_hid_event_t));
xTaskCreate(&lvgl_port_usb_hid_task, "hid_task", 4 * 1024, &lvgl_hid_ctx, 2, &lvgl_hid_ctx.task);
return &lvgl_hid_ctx;
}
static char usb_hid_get_keyboard_char(uint8_t key, uint8_t shift)
{
char ret_key = 0;
const uint8_t keycode2ascii [57][2] = {
{0, 0}, /* HID_KEY_NO_PRESS */
{0, 0}, /* HID_KEY_ROLLOVER */
{0, 0}, /* HID_KEY_POST_FAIL */
{0, 0}, /* HID_KEY_ERROR_UNDEFINED */
{'a', 'A'}, /* HID_KEY_A */
{'b', 'B'}, /* HID_KEY_B */
{'c', 'C'}, /* HID_KEY_C */
{'d', 'D'}, /* HID_KEY_D */
{'e', 'E'}, /* HID_KEY_E */
{'f', 'F'}, /* HID_KEY_F */
{'g', 'G'}, /* HID_KEY_G */
{'h', 'H'}, /* HID_KEY_H */
{'i', 'I'}, /* HID_KEY_I */
{'j', 'J'}, /* HID_KEY_J */
{'k', 'K'}, /* HID_KEY_K */
{'l', 'L'}, /* HID_KEY_L */
{'m', 'M'}, /* HID_KEY_M */
{'n', 'N'}, /* HID_KEY_N */
{'o', 'O'}, /* HID_KEY_O */
{'p', 'P'}, /* HID_KEY_P */
{'q', 'Q'}, /* HID_KEY_Q */
{'r', 'R'}, /* HID_KEY_R */
{'s', 'S'}, /* HID_KEY_S */
{'t', 'T'}, /* HID_KEY_T */
{'u', 'U'}, /* HID_KEY_U */
{'v', 'V'}, /* HID_KEY_V */
{'w', 'W'}, /* HID_KEY_W */
{'x', 'X'}, /* HID_KEY_X */
{'y', 'Y'}, /* HID_KEY_Y */
{'z', 'Z'}, /* HID_KEY_Z */
{'1', '!'}, /* HID_KEY_1 */
{'2', '@'}, /* HID_KEY_2 */
{'3', '#'}, /* HID_KEY_3 */
{'4', '$'}, /* HID_KEY_4 */
{'5', '%'}, /* HID_KEY_5 */
{'6', '^'}, /* HID_KEY_6 */
{'7', '&'}, /* HID_KEY_7 */
{'8', '*'}, /* HID_KEY_8 */
{'9', '('}, /* HID_KEY_9 */
{'0', ')'}, /* HID_KEY_0 */
{'\r', '\r'}, /* HID_KEY_ENTER */
{0, 0}, /* HID_KEY_ESC */
{'\b', 0}, /* HID_KEY_DEL */
{0, 0}, /* HID_KEY_TAB */
{' ', ' '}, /* HID_KEY_SPACE */
{'-', '_'}, /* HID_KEY_MINUS */
{'=', '+'}, /* HID_KEY_EQUAL */
{'[', '{'}, /* HID_KEY_OPEN_BRACKET */
{']', '}'}, /* HID_KEY_CLOSE_BRACKET */
{'\\', '|'}, /* HID_KEY_BACK_SLASH */
{'\\', '|'}, /* HID_KEY_SHARP */ // HOTFIX: for NonUS Keyboards repeat HID_KEY_BACK_SLASH
{';', ':'}, /* HID_KEY_COLON */
{'\'', '"'}, /* HID_KEY_QUOTE */
{'`', '~'}, /* HID_KEY_TILDE */
{',', '<'}, /* HID_KEY_LESS */
{'.', '>'}, /* HID_KEY_GREATER */
{'/', '?'} /* HID_KEY_SLASH */
};
if (shift > 1) {
shift = 1;
}
if ((key >= HID_KEY_A) && (key <= HID_KEY_SLASH)) {
ret_key = keycode2ascii[key][shift];
}
return ret_key;
}
static void lvgl_port_usb_hid_host_interface_callback(hid_host_device_handle_t hid_device_handle, const hid_host_interface_event_t event, void *arg)
{
hid_host_dev_params_t dev;
hid_host_device_get_params(hid_device_handle, &dev);
lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)arg;
uint8_t data[10];
unsigned int data_length = 0;
assert(hid_ctx != NULL);
switch (event) {
case HID_HOST_INTERFACE_EVENT_INPUT_REPORT:
hid_host_device_get_raw_input_report_data(hid_device_handle, data, sizeof(data), &data_length);
if (dev.proto == HID_PROTOCOL_KEYBOARD) {
hid_keyboard_input_report_boot_t *keyboard = (hid_keyboard_input_report_boot_t *)data;
if (data_length < sizeof(hid_keyboard_input_report_boot_t)) {
return;
}
for (int i = 0; i < HID_KEYBOARD_KEY_MAX; i++) {
if (keyboard->key[i] > HID_KEY_ERROR_UNDEFINED) {
char key = 0;
/* LVGL special keys */
if (keyboard->key[i] == HID_KEY_TAB) {
if ((keyboard->modifier.left_shift || keyboard->modifier.right_shift)) {
key = LV_KEY_PREV;
} else {
key = LV_KEY_NEXT;
}
} else if (keyboard->key[i] == HID_KEY_RIGHT) {
key = LV_KEY_RIGHT;
} else if (keyboard->key[i] == HID_KEY_LEFT) {
key = LV_KEY_LEFT;
} else if (keyboard->key[i] == HID_KEY_DOWN) {
key = LV_KEY_DOWN;
} else if (keyboard->key[i] == HID_KEY_UP) {
key = LV_KEY_UP;
} else if (keyboard->key[i] == HID_KEY_ENTER || keyboard->key[i] == HID_KEY_KEYPAD_ENTER) {
key = LV_KEY_ENTER;
} else if (keyboard->key[i] == HID_KEY_DELETE) {
key = LV_KEY_DEL;
} else if (keyboard->key[i] == HID_KEY_HOME) {
key = LV_KEY_HOME;
} else if (keyboard->key[i] == HID_KEY_END) {
key = LV_KEY_END;
} else {
/* Get ASCII char */
key = usb_hid_get_keyboard_char(keyboard->key[i], (keyboard->modifier.left_shift || keyboard->modifier.right_shift));
}
if (key == 0) {
ESP_LOGI(TAG, "Not recognized key: %c (%d)", keyboard->key[i], keyboard->key[i]);
}
hid_ctx->kb.last_key = key;
hid_ctx->kb.pressed = true;
}
}
} else if (dev.proto == HID_PROTOCOL_MOUSE) {
hid_mouse_input_report_boot_t *mouse = (hid_mouse_input_report_boot_t *)data;
if (data_length < sizeof(hid_mouse_input_report_boot_t)) {
break;
}
hid_ctx->mouse.left_button = mouse->buttons.button1;
hid_ctx->mouse.x += mouse->x_displacement;
hid_ctx->mouse.y += mouse->y_displacement;
}
break;
case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR:
break;
case HID_HOST_INTERFACE_EVENT_DISCONNECTED:
hid_host_device_close(hid_device_handle);
break;
default:
break;
}
}
static void lvgl_port_usb_hid_task(void *arg)
{
hid_host_dev_params_t dev;
lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)arg;
hid_host_device_handle_t hid_device_handle = NULL;
lvgl_port_usb_hid_event_t msg;
assert(ctx);
ctx->running = true;
while (ctx->running) {
if (xQueueReceive(ctx->queue, &msg, pdMS_TO_TICKS(50))) {
hid_device_handle = msg.hid_device_handle;
hid_host_device_get_params(hid_device_handle, &dev);
switch (msg.event) {
case HID_HOST_DRIVER_EVENT_CONNECTED:
/* Handle mouse or keyboard */
if (dev.proto == HID_PROTOCOL_KEYBOARD || dev.proto == HID_PROTOCOL_MOUSE) {
const hid_host_device_config_t dev_config = {
.callback = lvgl_port_usb_hid_host_interface_callback,
.callback_arg = ctx
};
ESP_ERROR_CHECK( hid_host_device_open(hid_device_handle, &dev_config) );
ESP_ERROR_CHECK( hid_class_request_set_idle(hid_device_handle, 0, 0) );
ESP_ERROR_CHECK( hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT) );
ESP_ERROR_CHECK( hid_host_device_start(hid_device_handle) );
}
break;
default:
break;
}
}
}
xQueueReset(ctx->queue);
vQueueDelete(ctx->queue);
hid_host_uninstall();
memset(&lvgl_hid_ctx, 0, sizeof(lvgl_port_usb_hid_ctx_t));
vTaskDelete(NULL);
}
static void lvgl_port_usb_hid_read_mouse(lv_indev_t *indev_drv, lv_indev_data_t *data)
{
int16_t width = 0;
int16_t height = 0;
assert(indev_drv);
lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_user_data(indev_drv);
assert(ctx);
lv_display_t *disp = lv_indev_get_display(indev_drv);
assert(disp);
if (lv_display_get_rotation(disp) == LV_DISPLAY_ROTATION_0 || lv_display_get_rotation(disp) == LV_DISPLAY_ROTATION_180) {
width = lv_display_get_physical_horizontal_resolution(disp);
height = lv_display_get_vertical_resolution(disp);
} else {
width = lv_display_get_vertical_resolution(disp);
height = lv_display_get_physical_horizontal_resolution(disp);
}
/* Screen borders */
if (ctx->mouse.x < 0) {
ctx->mouse.x = 0;
} else if (ctx->mouse.x > width * ctx->mouse.sensitivity) {
ctx->mouse.x = width * ctx->mouse.sensitivity;
}
if (ctx->mouse.y < 0) {
ctx->mouse.y = 0;
} else if (ctx->mouse.y > height * ctx->mouse.sensitivity) {
ctx->mouse.y = height * ctx->mouse.sensitivity;
}
/* Get coordinates by rotation with sensitivity */
switch (lv_display_get_rotation(disp)) {
case LV_DISPLAY_ROTATION_0:
data->point.x = ctx->mouse.x / ctx->mouse.sensitivity;
data->point.y = ctx->mouse.y / ctx->mouse.sensitivity;
break;
case LV_DISPLAY_ROTATION_90:
data->point.y = width - ctx->mouse.x / ctx->mouse.sensitivity;
data->point.x = ctx->mouse.y / ctx->mouse.sensitivity;
break;
case LV_DISPLAY_ROTATION_180:
data->point.x = width - ctx->mouse.x / ctx->mouse.sensitivity;
data->point.y = height - ctx->mouse.y / ctx->mouse.sensitivity;
break;
case LV_DISPLAY_ROTATION_270:
data->point.y = ctx->mouse.x / ctx->mouse.sensitivity;
data->point.x = height - ctx->mouse.y / ctx->mouse.sensitivity;
break;
}
if (ctx->mouse.left_button) {
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
static void lvgl_port_usb_hid_read_kb(lv_indev_t *indev_drv, lv_indev_data_t *data)
{
assert(indev_drv);
lvgl_port_usb_hid_ctx_t *ctx = (lvgl_port_usb_hid_ctx_t *)lv_indev_get_user_data(indev_drv);
assert(ctx);
data->key = ctx->kb.last_key;
if (ctx->kb.pressed) {
data->state = LV_INDEV_STATE_PRESSED;
ctx->kb.pressed = false;
} else {
data->state = LV_INDEV_STATE_RELEASED;
ctx->kb.last_key = 0;
}
}
static void lvgl_port_usb_hid_callback(hid_host_device_handle_t hid_device_handle, const hid_host_driver_event_t event, void *arg)
{
lvgl_port_usb_hid_ctx_t *hid_ctx = (lvgl_port_usb_hid_ctx_t *)arg;
const lvgl_port_usb_hid_event_t msg = {
.hid_device_handle = hid_device_handle,
.event = event,
.arg = arg
};
xQueueSend(hid_ctx->queue, &msg, 0);
}

View File

@ -1,12 +0,0 @@
# Comment to a new issue.
pullRequestOpened: |
Thank you for raising your pull request.
To ensure that all licensing criteria is met all repositories of the LVGL project apply a process called DCO (Developer's Certificate of Origin).
The text of DCO can be read here: https://developercertificate.org/
For a more detailed description see the [Documentation](https://docs.lvgl.io/latest/en/html/contributing/index.html#developer-certification-of-origin-dco) site.
By contributing to any repositories of the LVGL project you state that your contribution corresponds with the DCO.
No further action is required if your contribution fulfills the DCO. If you are not sure about it feel free to ask us in a comment.

View File

@ -1,17 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 21
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- architecture
- pinned
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue or pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -1,2 +0,0 @@
**/*.o
**/*.d

View File

@ -1,58 +0,0 @@
cmake_minimum_required(VERSION 3.12.4)
project(lv_drivers HOMEPAGE_URL https://github.com/lvgl/lv_drivers/)
# Option to build as shared library (as opposed to static), default: OFF
option(BUILD_SHARED_LIBS "Build shared as library (as opposed to static)" OFF)
file(GLOB_RECURSE SOURCES ./*.c)
if (BUILD_SHARED_LIBS)
add_library(lv_drivers SHARED ${SOURCES})
else()
add_library(lv_drivers STATIC ${SOURCES})
endif()
add_library(lvgl_drivers ALIAS lv_drivers)
add_library(lvgl::drivers ALIAS lv_drivers)
target_include_directories(lv_drivers SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
find_package(PkgConfig)
pkg_check_modules(PKG_WAYLAND wayland-client wayland-cursor wayland-protocols xkbcommon)
target_link_libraries(lv_drivers PUBLIC lvgl ${PKG_WAYLAND_LIBRARIES})
if("${LIB_INSTALL_DIR}" STREQUAL "")
set(LIB_INSTALL_DIR "lib")
endif()
if("${INC_INSTALL_DIR}" STREQUAL "")
set(INC_INSTALL_DIR "include/lvgl/lv_drivers")
endif()
install(
DIRECTORY "${CMAKE_SOURCE_DIR}/"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h"
PATTERN ".git*" EXCLUDE
PATTERN "CMakeFiles" EXCLUDE
PATTERN "docs" EXCLUDE
PATTERN "lib" EXCLUDE)
file(GLOB LV_DRIVERS_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_drv_conf.h")
set_target_properties(
lv_drivers
PROPERTIES OUTPUT_NAME lv_drivers
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
PUBLIC_HEADER "${LV_DRIVERS_PUBLIC_HEADERS}")
install(
TARGETS lv_drivers
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${LIB_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 LittlevGL
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,7 +0,0 @@
# Display and Touch pad drivers
Display controller and touchpad driver to can be directly used with [LittlevGL](https://littlevgl.com).
To learn more about using drivers in LittlevGL visit the [Porting guide](https://docs.lvgl.io/latest/en/html/porting/index.html).
If you used a new display or touchpad driver with LittlevGL please share it with other people!

View File

@ -1,597 +0,0 @@
/**
* @file GC9A01.c
*
**/
/*********************
* INCLUDES
*********************/
#include "GC9A01.h"
#if USE_GC9A01
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#ifndef GC9A01_XSTART
#define GC9A01_XSTART 0
#endif
#ifndef GC9A01_YSTART
#define GC9A01_YSTART 0
#endif
#define GC9A01_CMD_MODE 0
#define GC9A01_DATA_MODE 1
#define GC9A01_HOR_RES 240
#define GC9A01_VER_RES 240
/* GC9A01 Commands that we know of. Limited documentation */
#define GC9A01_INVOFF 0x20
#define GC9A01_INVON 0x21
#define GC9A01_DISPON 0x29
#define GC9A01_CASET 0x2A
#define GC9A01_RASET 0x2B
#define GC9A01_RAMWR 0x2C
#define GC9A01_COLMOD 0x3A
#define GC9A01_MADCTL 0x36
#define GC9A01_MADCTL_MY 0x80
#define GC9A01_MADCTL_MX 0x40
#define GC9A01_MADCTL_MV 0x20
#define GC9A01_MADCTL_RGB 0x00
#define GC9A01_DISFNCTRL 0xB6
/**********************
* TYPEDEFS
**********************/
/* Init script function */
struct GC9A01_function {
uint16_t cmd;
uint16_t data;
};
/* Init script commands */
enum GC9A01_cmd {
GC9A01_START,
GC9A01_END,
GC9A01_CMD,
GC9A01_DATA,
GC9A01_DELAY
};
/**********************
* STATIC PROTOTYPES
**********************/
static void GC9A01_command(uint8_t cmd);
static void GC9A01_data(uint8_t data);
static void GC9A01_set_addr_win(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
/**********************
* STATIC VARIABLES
**********************/
// Documentation on op codes for GC9A01 are very hard to find.
// Will document should they be found.
static struct GC9A01_function GC9A01_cfg_script[] = {
{ GC9A01_START, GC9A01_START},
{ GC9A01_CMD, 0xEF},
{ GC9A01_CMD, 0xEB},
{ GC9A01_DATA, 0x14},
{ GC9A01_CMD, 0xFE}, // Inter Register Enable1
{ GC9A01_CMD, 0xEF}, // Inter Register Enable2
{ GC9A01_CMD, 0xEB},
{ GC9A01_DATA, 0x14},
{ GC9A01_CMD, 0x84},
{ GC9A01_DATA, 0x40},
{ GC9A01_CMD, 0x85},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x86},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x87},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x88},
{ GC9A01_DATA, 0x0A},
{ GC9A01_CMD, 0x89},
{ GC9A01_DATA, 0x21},
{ GC9A01_CMD, 0x8A},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0x8B},
{ GC9A01_DATA, 0x80},
{ GC9A01_CMD, 0x8C},
{ GC9A01_DATA, 0x01},
{ GC9A01_CMD, 0x8D},
{ GC9A01_DATA, 0x01},
{ GC9A01_CMD, 0x8E},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x8F},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, GC9A01_DISFNCTRL}, // Display Function Control
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, GC9A01_MADCTL}, // Memory Access Control
{ GC9A01_DATA, 0x48}, // Set the display direction 0,1,2,3 four directions
{ GC9A01_CMD, GC9A01_COLMOD}, // COLMOD: Pixel Format Set
{ GC9A01_DATA, 0x05}, // 16 Bits per pixel
{ GC9A01_CMD, 0x90},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_CMD, 0xBD},
{ GC9A01_DATA, 0x06},
{ GC9A01_CMD, 0xBC},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0xFF},
{ GC9A01_DATA, 0x60},
{ GC9A01_DATA, 0x01},
{ GC9A01_DATA, 0x04},
{ GC9A01_CMD, 0xC3}, // Power Control 2
{ GC9A01_DATA, 0x13},
{ GC9A01_CMD, 0xC4}, // Power Control 3
{ GC9A01_DATA, 0x13},
{ GC9A01_CMD, 0xC9}, // Power Control 4
{ GC9A01_DATA, 0x22},
{ GC9A01_CMD, 0xBE},
{ GC9A01_DATA, 0x11},
{ GC9A01_CMD, 0xE1},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x0E},
{ GC9A01_CMD, 0xDF},
{ GC9A01_DATA, 0x21},
{ GC9A01_DATA, 0x0C},
{ GC9A01_DATA, 0x02},
{ GC9A01_CMD, 0xF0}, // SET_GAMMA1
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x09},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x26},
{ GC9A01_DATA, 0x2A},
{ GC9A01_CMD, 0xF1}, // SET_GAMMA2
{ GC9A01_DATA, 0x43},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x72},
{ GC9A01_DATA, 0x36},
{ GC9A01_DATA, 0x37},
{ GC9A01_DATA, 0x6F},
{ GC9A01_CMD, 0xF2}, // SET_GAMMA3
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x09},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x26},
{ GC9A01_DATA, 0x2A},
{ GC9A01_CMD, 0xF3}, // SET_GAMMA4
{ GC9A01_DATA, 0x43},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x72},
{ GC9A01_DATA, 0x36},
{ GC9A01_DATA, 0x37},
{ GC9A01_DATA, 0x6F},
{ GC9A01_CMD, 0xED},
{ GC9A01_DATA, 0x1B},
{ GC9A01_DATA, 0x0B},
{ GC9A01_CMD, 0xAE},
{ GC9A01_DATA, 0x77},
{ GC9A01_CMD, 0xCD},
{ GC9A01_DATA, 0x63},
{ GC9A01_CMD, 0x70},
{ GC9A01_DATA, 0x07},
{ GC9A01_DATA, 0x07},
{ GC9A01_DATA, 0x04},
{ GC9A01_DATA, 0x0E},
{ GC9A01_DATA, 0x0F},
{ GC9A01_DATA, 0x09},
{ GC9A01_DATA, 0x07},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x03},
{ GC9A01_CMD, 0xE8},
{ GC9A01_DATA, 0x34},
{ GC9A01_CMD, 0x62},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x0D},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xED},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x0F},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xEF},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_CMD, 0x63},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x11},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xF1},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x13},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xF3},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_CMD, 0x64},
{ GC9A01_DATA, 0x28},
{ GC9A01_DATA, 0x29},
{ GC9A01_DATA, 0xF1},
{ GC9A01_DATA, 0x01},
{ GC9A01_DATA, 0xF1},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x07},
{ GC9A01_CMD, 0x66},
{ GC9A01_DATA, 0x3C},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0xCD},
{ GC9A01_DATA, 0x67},
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0x67},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x3C},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x01},
{ GC9A01_DATA, 0x54},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x32},
{ GC9A01_DATA, 0x98},
{ GC9A01_CMD, 0x74},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x85},
{ GC9A01_DATA, 0x80},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x4E},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0x98},
{ GC9A01_DATA, 0x3E},
{ GC9A01_DATA, 0x07},
{ GC9A01_CMD, 0x35}, // Tearing Effect Line ON
{ GC9A01_CMD, 0x21}, // Display Inversion ON
{ GC9A01_CMD, 0x11}, // Sleep Out Mode
{ GC9A01_DELAY, 120},
{ GC9A01_CMD, GC9A01_DISPON}, // Display ON
{ GC9A01_DELAY, 255},
{ GC9A01_END, GC9A01_END},
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Write a command to the GC9A01
* @param cmd the command
*/
static void GC9A01_command(uint8_t cmd)
{
LV_DRV_DISP_CMD_DATA(GC9A01_CMD_MODE);
LV_DRV_DISP_SPI_WR_BYTE(cmd);
}
/**
* Write data to the GC9A01
* @param data the data
*/
static void GC9A01_data(uint8_t data)
{
LV_DRV_DISP_CMD_DATA(GC9A01_DATA_MODE);
LV_DRV_DISP_SPI_WR_BYTE(data);
}
static int GC9A01_data_array(uint8_t *buf, uint32_t len)
{
uint8_t *pt = buf;
for (uint32_t lp = 0; lp < len; lp++, pt++)
{
LV_DRV_DISP_SPI_WR_BYTE(*pt);
}
return 0;
}
static int GC9A01_databuf(uint32_t len, uint8_t *buf)
{
uint32_t byte_left = len;
uint8_t *pt = buf;
while (byte_left)
{
if (byte_left > 64)
{
LV_DRV_DISP_SPI_WR_ARRAY((char*)pt, 64);
byte_left = byte_left - 64;
pt = pt + 64;
}
else
{
LV_DRV_DISP_SPI_WR_ARRAY((char*)pt, byte_left);
byte_left=0;
}
}
return 0;
}
// hard reset of the tft controller
// ----------------------------------------------------------
static void GC9A01_hard_reset( void )
{
LV_DRV_DISP_SPI_CS(0); // Low to listen to us
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
}
// Configuration of the tft controller
// ----------------------------------------------------------
static void GC9A01_run_cfg_script(void)
{
int i = 0;
int end_script = 0;
do {
switch (GC9A01_cfg_script[i].cmd)
{
case GC9A01_START:
break;
case GC9A01_CMD:
GC9A01_command( GC9A01_cfg_script[i].data & 0xFF );
break;
case GC9A01_DATA:
GC9A01_data( GC9A01_cfg_script[i].data & 0xFF );
break;
case GC9A01_DELAY:
LV_DRV_DELAY_MS(GC9A01_cfg_script[i].data);
break;
case GC9A01_END:
end_script = 1;
}
i++;
} while (!end_script);
}
void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
// Rudimentary clipping
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
if((y+h-1) >= GC9A01_VER_RES) h = GC9A01_VER_RES - y;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x, y + h - 1);
uint8_t hi = color >> 8, lo = color;
while (h--) {
GC9A01_data(hi);
GC9A01_data(lo);
}
LV_DRV_DISP_SPI_CS(1);
}
void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
// Rudimentary clipping
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
if((x+w-1) >= GC9A01_HOR_RES) w = GC9A01_HOR_RES - x;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x + w - 1, y);
uint8_t hi = color >> 8, lo = color;
while (w--) {
GC9A01_data(hi);
GC9A01_data(lo);
}
LV_DRV_DISP_SPI_CS(1);
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
void GC9A01_invertDisplay(bool i)
{
GC9A01_command(i ? GC9A01_INVON : GC9A01_INVOFF);
}
void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color)
{
if((x < 0) ||(x >= GC9A01_HOR_RES) || (y < 0) || (y >= GC9A01_VER_RES)) return;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x, y);
uint8_t hi = color >> 8, lo = color;
GC9A01_data(hi);
GC9A01_data(lo);
LV_DRV_DISP_SPI_CS(1);
}
void GC9A01_fillScreen(uint16_t color) {
GC9A01_fillRect(0, 0, GC9A01_HOR_RES, GC9A01_VER_RES, color);
}
// fill a rectangle
void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
// rudimentary clipping (drawChar w/big text requires this)
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
if((x + w - 1) >= GC9A01_HOR_RES) w = GC9A01_HOR_RES - x;
if((y + h - 1) >= GC9A01_VER_RES) h = GC9A01_VER_RES - y;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x + w - 1, y + h - 1);
uint8_t hi = color >> 8, lo = color;
for (y = h; y > 0; y--)
{
for (x = w; x > 0; x--)
{
GC9A01_data(hi);
GC9A01_data(lo);
}
}
LV_DRV_DISP_SPI_CS(1);
}
void GC9A01_setRotation(uint8_t m) {
GC9A01_command(GC9A01_MADCTL);
m %= 4; // can't be higher than 3
switch (m) {
case 0:
GC9A01_data(GC9A01_MADCTL_MX | GC9A01_MADCTL_MY | GC9A01_MADCTL_RGB);
// _xstart = _colstart;
// _ystart = _rowstart;
break;
case 1:
GC9A01_data(GC9A01_MADCTL_MY | GC9A01_MADCTL_MV | GC9A01_MADCTL_RGB);
// _ystart = _colstart;
// _xstart = _rowstart;
break;
case 2:
GC9A01_data(GC9A01_MADCTL_RGB);
// _xstart = _colstart;
// _ystart = _rowstart;
break;
case 3:
GC9A01_data(GC9A01_MADCTL_MX | GC9A01_MADCTL_MV | GC9A01_MADCTL_RGB);
// _ystart = _colstart;
// _xstart = _rowstart;
break;
}
}
/**
* Initialize the GC9A01
*/
int GC9A01_init(void)
{
GC9A01_hard_reset();
GC9A01_run_cfg_script();
// GC9A01_fillScreen(0x0000); // Black
// GC9A01_fillScreen(0xFFFF); // White
GC9A01_fillScreen(0xAAAA); // ?
return 0;
}
static void GC9A01_set_addr_win(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
uint16_t x_start = x0 + GC9A01_XSTART, x_end = x1 + GC9A01_XSTART;
uint16_t y_start = y0 + GC9A01_YSTART, y_end = y1 + GC9A01_YSTART;
GC9A01_command(GC9A01_CASET); // Column addr set
GC9A01_data(x_start >> 8);
GC9A01_data(x_start & 0xFF); // XSTART
GC9A01_data(x_end >> 8);
GC9A01_data(x_end & 0xFF); // XEND
GC9A01_command(GC9A01_RASET); // Row addr set
GC9A01_data(y_start >> 8);
GC9A01_data(y_start & 0xFF); // YSTART
GC9A01_data(y_end >> 8);
GC9A01_data(y_end & 0xFF); // YEND
GC9A01_command(GC9A01_RAMWR);
}
void GC9A01_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t *color_p)
{
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(area->x1, area->y1, area->x2, area->y2);
int32_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;
LV_DRV_DISP_CMD_DATA(GC9A01_DATA_MODE);
LV_DRV_DISP_SPI_WR_ARRAY((char*)color_p, len);
LV_DRV_DISP_SPI_CS(1);
lv_disp_flush_ready(disp_drv); /* Indicate you are ready with the flushing*/
}
#endif

View File

@ -1,76 +0,0 @@
/**
* @file GC9A01.h
*
**/
#ifndef GC9A01_H
#define GC9A01_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_GC9A01
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if LV_COLOR_DEPTH != 16
#error "GC9A01 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h"
#endif
#if LV_COLOR_16_SWAP != 1
#error "GC9A01 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
int GC9A01_init(void);
void GC9A01_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void GC9A01_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
void GC9A01_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p);
void GC9A01_setRotation(uint8_t m);
void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void GC9A01_fillScreen(uint16_t color);
uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b);
void GC9A01_invertDisplay(bool i);
void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color);
void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t w, uint16_t color);
/**********************
* MACROS
**********************/
#endif /* USE_GC9A01 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* GC9A01_H */

View File

@ -1,432 +0,0 @@
/**
* @file ILI9341.c
*
* ILI9341.pdf [ILI9341_DS_V1.13_20110805]
*
* [references]
* - https://www.newhavendisplay.com/app_notes/ILI9341.pdf
* - Linux Source [v5.9-rc4] "drivers/staging/fbtft/fb_ili9341.c"
* - https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp
* - https://os.mbed.com/users/dreschpe/code/SPI_TFT_ILI9341
*
*/
/*********************
* INCLUDES
*********************/
#include "ILI9341.h"
#if USE_ILI9341 != 0
#include <stdio.h>
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define ILI9341_CMD_MODE 0
#define ILI9341_DATA_MODE 1
#define ILI9341_TFTWIDTH 240
#define ILI9341_TFTHEIGHT 320
/* Level 1 Commands -------------- [section] Description */
#define ILI9341_NOP 0x00 /* [8.2.1 ] No Operation / Terminate Frame Memory Write */
#define ILI9341_SWRESET 0x01 /* [8.2.2 ] Software Reset */
#define ILI9341_RDDIDIF 0x04 /* [8.2.3 ] Read Display Identification Information */
#define ILI9341_RDDST 0x09 /* [8.2.4 ] Read Display Status */
#define ILI9341_RDDPM 0x0A /* [8.2.5 ] Read Display Power Mode */
#define ILI9341_RDDMADCTL 0x0B /* [8.2.6 ] Read Display MADCTL */
#define ILI9341_RDDCOLMOD 0x0C /* [8.2.7 ] Read Display Pixel Format */
#define ILI9341_RDDIM 0x0D /* [8.2.8 ] Read Display Image Mode */
#define ILI9341_RDDSM 0x0E /* [8.2.9 ] Read Display Signal Mode */
#define ILI9341_RDDSDR 0x0F /* [8.2.10] Read Display Self-Diagnostic Result */
#define ILI9341_SLPIN 0x10 /* [8.2.11] Enter Sleep Mode */
#define ILI9341_SLPOUT 0x11 /* [8.2.12] Leave Sleep Mode */
#define ILI9341_PTLON 0x12 /* [8.2.13] Partial Display Mode ON */
#define ILI9341_NORON 0x13 /* [8.2.14] Normal Display Mode ON */
#define ILI9341_DINVOFF 0x20 /* [8.2.15] Display Inversion OFF */
#define ILI9341_DINVON 0x21 /* [8.2.16] Display Inversion ON */
#define ILI9341_GAMSET 0x26 /* [8.2.17] Gamma Set */
#define ILI9341_DISPOFF 0x28 /* [8.2.18] Display OFF*/
#define ILI9341_DISPON 0x29 /* [8.2.19] Display ON*/
#define ILI9341_CASET 0x2A /* [8.2.20] Column Address Set */
#define ILI9341_PASET 0x2B /* [8.2.21] Page Address Set */
#define ILI9341_RAMWR 0x2C /* [8.2.22] Memory Write */
#define ILI9341_RGBSET 0x2D /* [8.2.23] Color Set (LUT for 16-bit to 18-bit color depth conversion) */
#define ILI9341_RAMRD 0x2E /* [8.2.24] Memory Read */
#define ILI9341_PTLAR 0x30 /* [8.2.25] Partial Area */
#define ILI9341_VSCRDEF 0x33 /* [8.2.26] Veritcal Scrolling Definition */
#define ILI9341_TEOFF 0x34 /* [8.2.27] Tearing Effect Line OFF */
#define ILI9341_TEON 0x35 /* [8.2.28] Tearing Effect Line ON */
#define ILI9341_MADCTL 0x36 /* [8.2.29] Memory Access Control */
#define MADCTL_MY 0x80 /* MY row address order */
#define MADCTL_MX 0x40 /* MX column address order */
#define MADCTL_MV 0x20 /* MV row / column exchange */
#define MADCTL_ML 0x10 /* ML vertical refresh order */
#define MADCTL_MH 0x04 /* MH horizontal refresh order */
#define MADCTL_RGB 0x00 /* RGB Order [default] */
#define MADCTL_BGR 0x08 /* BGR Order */
#define ILI9341_VSCRSADD 0x37 /* [8.2.30] Vertical Scrolling Start Address */
#define ILI9341_IDMOFF 0x38 /* [8.2.31] Idle Mode OFF */
#define ILI9341_IDMON 0x39 /* [8.2.32] Idle Mode ON */
#define ILI9341_PIXSET 0x3A /* [8.2.33] Pixel Format Set */
#define ILI9341_WRMEMCONT 0x3C /* [8.2.34] Write Memory Continue */
#define ILI9341_RDMEMCONT 0x3E /* [8.2.35] Read Memory Continue */
#define ILI9341_SETSCANTE 0x44 /* [8.2.36] Set Tear Scanline */
#define ILI9341_GETSCAN 0x45 /* [8.2.37] Get Scanline */
#define ILI9341_WRDISBV 0x51 /* [8.2.38] Write Display Brightness Value */
#define ILI9341_RDDISBV 0x52 /* [8.2.39] Read Display Brightness Value */
#define ILI9341_WRCTRLD 0x53 /* [8.2.40] Write Control Display */
#define ILI9341_RDCTRLD 0x54 /* [8.2.41] Read Control Display */
#define ILI9341_WRCABC 0x55 /* [8.2.42] Write Content Adaptive Brightness Control Value */
#define ILI9341_RDCABC 0x56 /* [8.2.43] Read Content Adaptive Brightness Control Value */
#define ILI9341_WRCABCMIN 0x5E /* [8.2.44] Write CABC Minimum Brightness */
#define ILI9341_RDCABCMIN 0x5F /* [8.2.45] Read CABC Minimum Brightness */
#define ILI9341_RDID1 0xDA /* [8.2.46] Read ID1 - Manufacturer ID (user) */
#define ILI9341_RDID2 0xDB /* [8.2.47] Read ID2 - Module/Driver version (supplier) */
#define ILI9341_RDID3 0xDC /* [8.2.48] Read ID3 - Module/Driver version (user) */
/* Level 2 Commands -------------- [section] Description */
#define ILI9341_IFMODE 0xB0 /* [8.3.1 ] Interface Mode Control */
#define ILI9341_FRMCTR1 0xB1 /* [8.3.2 ] Frame Rate Control (In Normal Mode/Full Colors) */
#define ILI9341_FRMCTR2 0xB2 /* [8.3.3 ] Frame Rate Control (In Idle Mode/8 colors) */
#define ILI9341_FRMCTR3 0xB3 /* [8.3.4 ] Frame Rate control (In Partial Mode/Full Colors) */
#define ILI9341_INVTR 0xB4 /* [8.3.5 ] Display Inversion Control */
#define ILI9341_PRCTR 0xB5 /* [8.3.6 ] Blanking Porch Control */
#define ILI9341_DISCTRL 0xB6 /* [8.3.7 ] Display Function Control */
#define ILI9341_ETMOD 0xB7 /* [8.3.8 ] Entry Mode Set */
#define ILI9341_BLCTRL1 0xB8 /* [8.3.9 ] Backlight Control 1 - Grayscale Histogram UI mode */
#define ILI9341_BLCTRL2 0xB9 /* [8.3.10] Backlight Control 2 - Grayscale Histogram still picture mode */
#define ILI9341_BLCTRL3 0xBA /* [8.3.11] Backlight Control 3 - Grayscale Thresholds UI mode */
#define ILI9341_BLCTRL4 0xBB /* [8.3.12] Backlight Control 4 - Grayscale Thresholds still picture mode */
#define ILI9341_BLCTRL5 0xBC /* [8.3.13] Backlight Control 5 - Brightness Transition time */
#define ILI9341_BLCTRL7 0xBE /* [8.3.14] Backlight Control 7 - PWM Frequency */
#define ILI9341_BLCTRL8 0xBF /* [8.3.15] Backlight Control 8 - ON/OFF + PWM Polarity*/
#define ILI9341_PWCTRL1 0xC0 /* [8.3.16] Power Control 1 - GVDD */
#define ILI9341_PWCTRL2 0xC1 /* [8.3.17] Power Control 2 - step-up factor for operating voltage */
#define ILI9341_VMCTRL1 0xC5 /* [8.3.18] VCOM Control 1 - Set VCOMH and VCOML */
#define ILI9341_VMCTRL2 0xC7 /* [8.3.19] VCOM Control 2 - VCOM offset voltage */
#define ILI9341_NVMWR 0xD0 /* [8.3.20] NV Memory Write */
#define ILI9341_NVMPKEY 0xD1 /* [8.3.21] NV Memory Protection Key */
#define ILI9341_RDNVM 0xD2 /* [8.3.22] NV Memory Status Read */
#define ILI9341_RDID4 0xD3 /* [8.3.23] Read ID4 - IC Device Code */
#define ILI9341_PGAMCTRL 0xE0 /* [8.3.24] Positive Gamma Control */
#define ILI9341_NGAMCTRL 0xE1 /* [8.3.25] Negative Gamma Correction */
#define ILI9341_DGAMCTRL1 0xE2 /* [8.3.26] Digital Gamma Control 1 */
#define ILI9341_DGAMCTRL2 0xE3 /* [8.3.27] Digital Gamma Control 2 */
#define ILI9341_IFCTL 0xF6 /* [8.3.28] 16bits Data Format Selection */
/* Extended Commands --------------- [section] Description*/
#define ILI9341_PWCTRLA 0xCB /* [8.4.1] Power control A */
#define ILI9341_PWCTRLB 0xCF /* [8.4.2] Power control B */
#define ILI9341_TIMECTRLA_INT 0xE8 /* [8.4.3] Internal Clock Driver timing control A */
#define ILI9341_TIMECTRLA_EXT 0xE9 /* [8.4.4] External Clock Driver timing control A */
#define ILI9341_TIMECTRLB 0xEA /* [8.4.5] Driver timing control B (gate driver timing control) */
#define ILI9341_PWSEQCTRL 0xED /* [8.4.6] Power on sequence control */
#define ILI9341_GAM3CTRL 0xF2 /* [8.4.7] Enable 3 gamma control */
#define ILI9341_PUMPRATIO 0xF7 /* [8.4.8] Pump ratio control */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static inline void ili9341_write(int mode, uint8_t data);
static inline void ili9341_write_array(int mode, uint8_t *data, uint16_t len);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the ILI9341 display controller
*/
void ili9341_init(void)
{
uint8_t data[15];
/* hardware reset */
LV_DRV_DISP_SPI_CS(1);
LV_DRV_DISP_CMD_DATA(ILI9341_DATA_MODE);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_US(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(5);
/* software reset */
ili9341_write(ILI9341_CMD_MODE, ILI9341_SWRESET);
LV_DRV_DELAY_MS(5);
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISPOFF);
/* startup sequence */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRLB);
data[0] = 0x00;
data[1] = 0x83;
data[2] = 0x30;
ili9341_write_array(ILI9341_DATA_MODE, data, 3);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWSEQCTRL);
data[0] = 0x64;
data[1] = 0x03;
data[2] = 0x12;
data[3] = 0x81;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
ili9341_write(ILI9341_CMD_MODE, ILI9341_TIMECTRLA_INT);
data[0] = 0x85;
data[1] = 0x01;
data[2] = 0x79;
ili9341_write_array(ILI9341_DATA_MODE, data, 3);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRLA);
data[0] = 0x39;
data[1] = 0x2c;
data[2] = 0x00;
data[3] = 0x34;
data[4] = 0x02;
ili9341_write_array(ILI9341_DATA_MODE, data, 5);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PUMPRATIO);
ili9341_write(ILI9341_DATA_MODE, 0x20);
ili9341_write(ILI9341_CMD_MODE, ILI9341_TIMECTRLB);
data[0] = 0x00;
data[1] = 0x00;
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
/* power control */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRL1);
ili9341_write(ILI9341_DATA_MODE, 0x26);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRL2);
ili9341_write(ILI9341_DATA_MODE, 0x11);
/* VCOM */
ili9341_write(ILI9341_CMD_MODE, ILI9341_VMCTRL1);
data[0] = 0x35;
data[1] = 0x3e;
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
ili9341_write(ILI9341_CMD_MODE, ILI9341_VMCTRL2);
ili9341_write(ILI9341_DATA_MODE, 0xbe);
/* set orientation */
ili9341_rotate(0, ILI9341_BGR);
/* 16 bit pixel */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PIXSET);
ili9341_write(ILI9341_DATA_MODE, 0x55);
/* frame rate */
ili9341_write(ILI9341_CMD_MODE, ILI9341_FRMCTR1);
data[0] = 0x00;
data[1] = 0x1b;
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
#if ILI9341_GAMMA
/* gamma curve set */
ili9341_write(ILI9341_CMD_MODE, ILI9341_GAMSET);
ili9341_write(ILI9341_DATA_MODE, 0x01);
/* positive gamma correction */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PGAMCTRL);
data[0] = 0x1f;
data[1] = 0x1a;
data[2] = 0x18;
data[3] = 0x0a;
data[4] = 0x0f;
data[5] = 0x06;
data[6] = 0x45;
data[7] = 0x87;
data[8] = 0x32;
data[9] = 0x0a;
data[10] = 0x07;
data[11] = 0x02;
data[12] = 0x07;
data[13] = 0x05;
data[14] = 0x00;
ili9341_write_array(ILI9341_DATA_MODE, data, 15);
/* negative gamma correction */
ili9341_write(ILI9341_CMD_MODE, ILI9341_NGAMCTRL);
data[0] = 0x00;
data[1] = 0x25;
data[2] = 0x27;
data[3] = 0x05;
data[4] = 0x10;
data[5] = 0x09;
data[6] = 0x3a;
data[7] = 0x78;
data[8] = 0x4d;
data[9] = 0x05;
data[10] = 0x18;
data[11] = 0x0d;
data[12] = 0x38;
data[13] = 0x3a;
data[14] = 0x1f;
ili9341_write_array(ILI9341_DATA_MODE, data, 15);
#endif
/* window horizontal */
ili9341_write(ILI9341_CMD_MODE, ILI9341_CASET);
data[0] = 0;
data[1] = 0;
data[2] = (ILI9341_HOR_RES - 1) >> 8;
data[3] = (ILI9341_HOR_RES - 1);
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
/* window vertical */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PASET);
data[0] = 0;
data[1] = 0;
data[2] = (ILI9341_VER_RES - 1) >> 8;
data[3] = (ILI9341_VER_RES - 1);
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
ili9341_write(ILI9341_CMD_MODE, ILI9341_RAMWR);
#if ILI9341_TEARING
/* tearing effect off */
ili9341_write(ILI9341_CMD_MODE, ILI9341_TEOFF);
/* tearing effect on */
ili9341_write(ILI9341_CMD_MODE, ILI9341_TEON);
#endif
/* entry mode set */
ili9341_write(ILI9341_CMD_MODE, ILI9341_ETMOD);
ili9341_write(ILI9341_DATA_MODE, 0x07);
/* display function control */
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISCTRL);
data[0] = 0x0a;
data[1] = 0x82;
data[2] = 0x27;
data[3] = 0x00;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
/* exit sleep mode */
ili9341_write(ILI9341_CMD_MODE, ILI9341_SLPOUT);
LV_DRV_DELAY_MS(100);
/* display on */
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISPON);
LV_DRV_DELAY_MS(20);
}
void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
if(area->x2 < 0 || area->y2 < 0 || area->x1 > (ILI9341_HOR_RES - 1) || area->y1 > (ILI9341_VER_RES - 1)) {
lv_disp_flush_ready(drv);
return;
}
/* Truncate the area to the screen */
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > ILI9341_HOR_RES - 1 ? ILI9341_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > ILI9341_VER_RES - 1 ? ILI9341_VER_RES - 1 : area->y2;
int32_t y;
uint8_t data[4];
int32_t len = len = (act_x2 - act_x1 + 1) * 2;
lv_coord_t w = (area->x2 - area->x1) + 1;
/* window horizontal */
ili9341_write(ILI9341_CMD_MODE, ILI9341_CASET);
data[0] = act_x1 >> 8;
data[1] = act_x1;
data[2] = act_x2 >> 8;
data[3] = act_x2;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
/* window vertical */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PASET);
data[0] = act_y1 >> 8;
data[1] = act_y1;
data[2] = act_y2 >> 8;
data[3] = act_y2;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
ili9341_write(ILI9341_CMD_MODE, ILI9341_RAMWR);
for(y = act_y1; y <= act_y2; y++) {
ili9341_write_array(ILI9341_DATA_MODE, (uint8_t *)color_p, len);
color_p += w;
}
lv_disp_flush_ready(drv);
}
void ili9341_rotate(int degrees, bool bgr)
{
uint8_t color_order = MADCTL_RGB;
if(bgr)
color_order = MADCTL_BGR;
ili9341_write(ILI9341_CMD_MODE, ILI9341_MADCTL);
switch(degrees) {
case 270:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MV | color_order);
break;
case 180:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MY | color_order);
break;
case 90:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MX | MADCTL_MY | MADCTL_MV | color_order);
break;
case 0:
/* fall-through */
default:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MX | color_order);
break;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Write byte
* @param mode sets command or data mode for write
* @param byte the byte to write
*/
static inline void ili9341_write(int mode, uint8_t data)
{
LV_DRV_DISP_CMD_DATA(mode);
LV_DRV_DISP_SPI_WR_BYTE(data);
}
/**
* Write byte array
* @param mode sets command or data mode for write
* @param data the byte array to write
* @param len the length of the byte array
*/
static inline void ili9341_write_array(int mode, uint8_t *data, uint16_t len)
{
LV_DRV_DISP_CMD_DATA(mode);
LV_DRV_DISP_SPI_WR_ARRAY(data, len);
}
#endif

View File

@ -1,67 +0,0 @@
/**
* @file ILI9341.h
*
*/
#ifndef ILI9341_H
#define ILI9341_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <stdbool.h>
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_ILI9341
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if LV_COLOR_DEPTH != 16
#error "ILI9341 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h"
#endif
#if LV_COLOR_16_SWAP != 1
#error "ILI9341 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h"
#endif
/*********************
* DEFINES
*********************/
#define ILI9341_BGR true
#define ILI9341_RGB false
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void ili9341_init(void);
void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
void ili9341_rotate(int degrees, bool bgr);
/**********************
* MACROS
**********************/
#endif /* USE_ILI9341 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ILI9341_H */

View File

@ -1,425 +0,0 @@
/**
* @file R61581.c
*
*/
/*********************
* INCLUDES
*********************/
#include "R61581.h"
#if USE_R61581 != 0
#include <stdbool.h>
#include "lvgl/lv_core/lv_vdb.h"
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define R61581_CMD_MODE 0
#define R61581_DATA_MODE 1
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void r61581_io_init(void);
static void r61581_reset(void);
static void r61581_set_tft_spec(void);
static inline void r61581_cmd_mode(void);
static inline void r61581_data_mode(void);
static inline void r61581_cmd(uint8_t cmd);
static inline void r61581_data(uint8_t data);
/**********************
* STATIC VARIABLES
**********************/
static bool cmd_mode = true;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the R61581 display controller
* @return HW_RES_OK or any error from hw_res_t enum
*/
void r61581_init(void)
{
r61581_io_init();
/*Slow mode until the PLL is not started in the display controller*/
LV_DRV_DISP_PAR_SLOW;
r61581_reset();
r61581_set_tft_spec();
r61581_cmd(0x13); //SET display on
r61581_cmd(0x29); //SET display on
LV_DRV_DELAY_MS(30);
/*Parallel to max speed*/
LV_DRV_DISP_PAR_FAST;
}
void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > R61581_HOR_RES - 1) return;
if(y1 > R61581_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
//Set the rectangular area
r61581_cmd(0x002A);
r61581_data(act_x1 >> 8);
r61581_data(0x00FF & act_x1);
r61581_data(act_x2 >> 8);
r61581_data(0x00FF & act_x2);
r61581_cmd(0x002B);
r61581_data(act_y1 >> 8);
r61581_data(0x00FF & act_y1);
r61581_data(act_y2 >> 8);
r61581_data(0x00FF & act_y2);
r61581_cmd(0x2c);
int16_t i;
uint16_t full_w = x2 - x1 + 1;
r61581_data_mode();
#if LV_COLOR_DEPTH == 16
uint16_t act_w = act_x2 - act_x1 + 1;
for(i = act_y1; i <= act_y2; i++) {
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
color_p += full_w;
}
#else
int16_t j;
for(i = act_y1; i <= act_y2; i++) {
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j]));
color_p += full_w;
}
}
#endif
lv_flush_ready();
}
void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > R61581_HOR_RES - 1) return;
if(y1 > R61581_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
//Set the rectangular area
r61581_cmd(0x002A);
r61581_data(act_x1 >> 8);
r61581_data(0x00FF & act_x1);
r61581_data(act_x2 >> 8);
r61581_data(0x00FF & act_x2);
r61581_cmd(0x002B);
r61581_data(act_y1 >> 8);
r61581_data(0x00FF & act_y1);
r61581_data(act_y2 >> 8);
r61581_data(0x00FF & act_y2);
r61581_cmd(0x2c);
r61581_data_mode();
uint16_t color16 = lv_color_to16(color);
uint32_t size = (act_x2 - act_x1 + 1) * (act_y2 - act_y1 + 1);
uint32_t i;
for(i = 0; i < size; i++) {
LV_DRV_DISP_PAR_WR_WORD(color16);
}
}
void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > R61581_HOR_RES - 1) return;
if(y1 > R61581_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
//Set the rectangular area
r61581_cmd(0x002A);
r61581_data(act_x1 >> 8);
r61581_data(0x00FF & act_x1);
r61581_data(act_x2 >> 8);
r61581_data(0x00FF & act_x2);
r61581_cmd(0x002B);
r61581_data(act_y1 >> 8);
r61581_data(0x00FF & act_y1);
r61581_data(act_y2 >> 8);
r61581_data(0x00FF & act_y2);
r61581_cmd(0x2c);
int16_t i;
uint16_t full_w = x2 - x1 + 1;
r61581_data_mode();
#if LV_COLOR_DEPTH == 16
uint16_t act_w = act_x2 - act_x1 + 1;
for(i = act_y1; i <= act_y2; i++) {
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
color_p += full_w;
}
#else
int16_t j;
for(i = act_y1; i <= act_y2; i++) {
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j]));
color_p += full_w;
}
}
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Io init
*/
static void r61581_io_init(void)
{
LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE)
cmd_mode = true;
}
/**
* Reset
*/
static void r61581_reset(void)
{
/*Hardware reset*/
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
/*Chip enable*/
LV_DRV_DISP_PAR_CS(1);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_PAR_CS(0);
LV_DRV_DELAY_MS(5);
/*Software reset*/
r61581_cmd(0x01);
LV_DRV_DELAY_MS(20);
r61581_cmd(0x01);
LV_DRV_DELAY_MS(20);
r61581_cmd(0x01);
LV_DRV_DELAY_MS(20);
}
/**
* TFT specific initialization
*/
static void r61581_set_tft_spec(void)
{
r61581_cmd(0xB0);
r61581_data(0x00);
r61581_cmd(0xB3);
r61581_data(0x02);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(0x10);
r61581_cmd(0xB4);
r61581_data(0x00);//0X10
r61581_cmd(0xB9); //PWM
r61581_data(0x01);
r61581_data(0xFF); //FF brightness
r61581_data(0xFF);
r61581_data(0x18);
/*Panel Driving Setting*/
r61581_cmd(0xC0);
r61581_data(0x02);
r61581_data(0x3B);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(0x01);
r61581_data(0x00);//NW
r61581_data(0x43);
/*Display Timing Setting for Normal Mode */
r61581_cmd(0xC1);
r61581_data(0x08);
r61581_data(0x15); //CLOCK
r61581_data(R61581_VFP);
r61581_data(R61581_VBP);
/*Source/VCOM/Gate Driving Timing Setting*/
r61581_cmd(0xC4);
r61581_data(0x15);
r61581_data(0x03);
r61581_data(0x03);
r61581_data(0x01);
/*Interface Setting*/
r61581_cmd(0xC6);
r61581_data((R61581_DPL << 0) |
(R61581_EPL << 1) |
(R61581_HSPL << 4) |
(R61581_VSPL << 5));
/*Gamma Set*/
r61581_cmd(0xC8);
r61581_data(0x0c);
r61581_data(0x05);
r61581_data(0x0A);
r61581_data(0x6B);
r61581_data(0x04);
r61581_data(0x06);
r61581_data(0x15);
r61581_data(0x10);
r61581_data(0x00);
r61581_data(0x31);
r61581_cmd(0x36);
if(R61581_ORI == 0) r61581_data(0xE0);
else r61581_data(0x20);
r61581_cmd(0x0C);
r61581_data(0x55);
r61581_cmd(0x3A);
r61581_data(0x55);
r61581_cmd(0x38);
r61581_cmd(0xD0);
r61581_data(0x07);
r61581_data(0x07);
r61581_data(0x14);
r61581_data(0xA2);
r61581_cmd(0xD1);
r61581_data(0x03);
r61581_data(0x5A);
r61581_data(0x10);
r61581_cmd(0xD2);
r61581_data(0x03);
r61581_data(0x04);
r61581_data(0x04);
r61581_cmd(0x11);
LV_DRV_DELAY_MS(10);
r61581_cmd(0x2A);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(((R61581_HOR_RES - 1) >> 8) & 0XFF);
r61581_data((R61581_HOR_RES - 1) & 0XFF);
r61581_cmd(0x2B);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(((R61581_VER_RES - 1) >> 8) & 0XFF);
r61581_data((R61581_VER_RES - 1) & 0XFF);
LV_DRV_DELAY_MS(10);
r61581_cmd(0x29);
LV_DRV_DELAY_MS(5);
r61581_cmd(0x2C);
LV_DRV_DELAY_MS(5);
}
/**
* Command mode
*/
static inline void r61581_cmd_mode(void)
{
if(cmd_mode == false) {
LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE)
cmd_mode = true;
}
}
/**
* Data mode
*/
static inline void r61581_data_mode(void)
{
if(cmd_mode != false) {
LV_DRV_DISP_CMD_DATA(R61581_DATA_MODE);
cmd_mode = false;
}
}
/**
* Write command
* @param cmd the command
*/
static inline void r61581_cmd(uint8_t cmd)
{
r61581_cmd_mode();
LV_DRV_DISP_PAR_WR_WORD(cmd);
}
/**
* Write data
* @param data the data
*/
static inline void r61581_data(uint8_t data)
{
r61581_data_mode();
LV_DRV_DISP_PAR_WR_WORD(data);
}
#endif

View File

@ -1,57 +0,0 @@
/**
* @file R61581.h
*
*/
#ifndef R61581_H
#define R61581_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_R61581
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void r61581_init(void);
void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_R61581 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* R61581_H */

View File

@ -1,182 +0,0 @@
/**
* @file SHARP_MIP.c
*
*/
/*-------------------------------------------------------------------------------------------------
* SHARP memory in pixel monochrome display series
* LS012B7DD01 (184x38 pixels.)
* LS013B7DH03 (128x128 pixels.)
* LS013B7DH05 (144x168 pixels.)
* LS027B7DH01 (400x240 pixels.) (tested)
* LS032B7DD02 (336x536 pixels.)
* LS044Q7DH01 (320x240 pixels.)
*
* These displays need periodic com inversion, there are two ways :
* - software com inversion :
* define SHARP_MIP_SOFT_COM_INVERSION 1 and set EXTMODE display pin LOW,
* call sharp_mip_com_inversion() periodically
* - hardware com inversion with EXTCOMIN display pin :
* define SHARP_MIP_SOFT_COM_INVERSION 0,
* set EXTMODE display pin HIGH and handle
* EXTCOMIN waveform (for example with mcu pwm output),
* see datasheet pages 8-12 for details
*
* draw_buf size : (LV_VER_RES / X) * (2 + LV_HOR_RES / 8) + 2 bytes, structure :
* [FRAME_HEADER (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 1st line
* [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 2nd line
* ...........................................................................................
* [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] last line
* [DUMMY (2 bytes)]
*
* Since extra bytes (dummy, addresses, header) are stored in draw_buf, we need to use
* an "oversized" draw_buf. Buffer declaration in "lv_port_disp.c" becomes for example :
* static lv_disp_buf_t disp_buf;
* static uint8_t buf[(LV_VER_RES_MAX / X) * (2 + (LV_HOR_RES_MAX / 8)) + 2];
* lv_disp_buf_init(&disp_buf, buf, NULL, LV_VER_RES_MAX * LV_HOR_RES_MAX / X);
*-----------------------------------------------------------------------------------------------*/
/*********************
* INCLUDES
*********************/
#include "SHARP_MIP.h"
#if USE_SHARP_MIP
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define SHARP_MIP_HEADER 0
#define SHARP_MIP_UPDATE_RAM_FLAG (1 << 7) /* (M0) Mode flag : H -> update memory, L -> maintain memory */
#define SHARP_MIP_COM_INVERSION_FLAG (1 << 6) /* (M1) Frame inversion flag : relevant when EXTMODE = L, */
/* H -> outputs VCOM = H, L -> outputs VCOM = L */
#define SHARP_MIP_CLEAR_SCREEN_FLAG (1 << 5) /* (M2) All clear flag : H -> clear all pixels */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if SHARP_MIP_SOFT_COM_INVERSION
static bool_t com_output_state = false;
#endif
/**********************
* MACROS
**********************/
/*
* Return the draw_buf byte index corresponding to the pixel
* relatives coordinates (x, y) in the area.
* The area is rounded to a whole screen line.
*/
#define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (SHARP_MIP_HOR_RES >> 3))) + 2)
/*
* Return the byte bitmask of a pixel bit corresponding
* to draw_buf arrangement (8 pixels per byte on lines).
*/
#define PIXIDX(x) SHARP_MIP_REV_BYTE(1 << ((x) & 7))
/**********************
* GLOBAL FUNCTIONS
**********************/
void sharp_mip_init(void) {
/* These displays have nothing to initialize */
}
void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
/*Return if the area is out the screen*/
if(area->y2 < 0) return;
if(area->y1 > SHARP_MIP_VER_RES - 1) return;
/*Truncate the area to the screen*/
uint16_t act_y1 = area->y1 < 0 ? 0 : area->y1;
uint16_t act_y2 = area->y2 > SHARP_MIP_VER_RES - 1 ? SHARP_MIP_VER_RES - 1 : area->y2;
uint8_t * buf = (uint8_t *) color_p; /*Get the buffer address*/
uint16_t buf_h = (act_y2 - act_y1 + 1); /*Number of buffer lines*/
uint16_t buf_size = buf_h * (2 + SHARP_MIP_HOR_RES / 8) + 2; /*Buffer size in bytes */
/* Set lines to flush dummy byte & gate address in draw_buf*/
for(uint16_t act_y = 0 ; act_y < buf_h ; act_y++) {
buf[BUFIDX(0, act_y) - 1] = SHARP_MIP_REV_BYTE((act_y1 + act_y + 1));
buf[BUFIDX(0, act_y) - 2] = 0;
}
/* Set last dummy two bytes in draw_buf */
buf[BUFIDX(0, buf_h) - 1] = 0;
buf[BUFIDX(0, buf_h) - 2] = 0;
/* Set frame header in draw_buf */
buf[0] = SHARP_MIP_HEADER |
SHARP_MIP_UPDATE_RAM_FLAG;
/* Write the frame on display memory */
LV_DRV_DISP_SPI_CS(1);
LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size);
LV_DRV_DISP_SPI_CS(0);
lv_disp_flush_ready(disp_drv);
}
void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
(void) disp_drv;
(void) buf_w;
(void) opa;
if (lv_color_to1(color) != 0) {
buf[BUFIDX(x, y)] |= PIXIDX(x); /*Set draw_buf pixel bit to 1 for other colors than BLACK*/
} else {
buf[BUFIDX(x, y)] &= ~PIXIDX(x); /*Set draw_buf pixel bit to 0 for BLACK color*/
}
}
void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) {
(void) disp_drv;
/* Round area to a whole line */
area->x1 = 0;
area->x2 = SHARP_MIP_HOR_RES - 1;
}
#if SHARP_MIP_SOFT_COM_INVERSION
void sharp_mip_com_inversion(void) {
uint8_t inversion_header[2] = {0};
/* Set inversion header */
if (com_output_state) {
com_output_state = false;
} else {
inversion_header[0] |= SHARP_MIP_COM_INVERSION_FLAG;
com_output_state = true;
}
/* Write inversion header on display memory */
LV_DRV_DISP_SPI_CS(1);
LV_DRV_DISP_SPI_WR_ARRAY(inversion_header, 2);
LV_DRV_DISP_SPI_CS(0);
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -1,63 +0,0 @@
/**
* @file SHARP_MIP.h
*
*/
#ifndef SHARP_MIP_H
#define SHARP_MIP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_SHARP_MIP
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void sharp_mip_init(void);
void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area);
void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
#if SHARP_MIP_SOFT_COM_INVERSION
void sharp_mip_com_inversion(void);
#endif
/**********************
* MACROS
**********************/
#endif /* USE_SHARP_MIP */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SHARP_MIP_H */

View File

@ -1,292 +0,0 @@
/**
* @file SSD1963.c
*
*/
/*********************
* INCLUDES
*********************/
#include "SSD1963.h"
#if USE_SSD1963
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define SSD1963_CMD_MODE 0
#define SSD1963_DATA_MODE 1
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static inline void ssd1963_cmd_mode(void);
static inline void ssd1963_data_mode(void);
static inline void ssd1963_cmd(uint8_t cmd);
static inline void ssd1963_data(uint8_t data);
static void ssd1963_io_init(void);
static void ssd1963_reset(void);
static void ssd1963_set_clk(void);
static void ssd1963_set_tft_spec(void);
static void ssd1963_init_bl(void);
/**********************
* STATIC VARIABLES
**********************/
static bool cmd_mode = true;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void ssd1963_init(void)
{
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
cmd_mode = true;
LV_DRV_DELAY_MS(250);
ssd1963_cmd(0x00E2); //PLL multiplier, set PLL clock to 120M
ssd1963_data(0x0023); //N=0x36 for 6.5M, 0x23 for 10M crystal
ssd1963_data(0x0002);
ssd1963_data(0x0004);
ssd1963_cmd(0x00E0); // PLL enable
ssd1963_data(0x0001);
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x00E0);
ssd1963_data(0x0003); // now, use PLL output as system clock
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x0001); // software reset
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x00E6); //PLL setting for PCLK, depends on resolution
ssd1963_data(0x0001); //HX8257C
ssd1963_data(0x0033); //HX8257C
ssd1963_data(0x0033); //HX8257C
ssd1963_cmd(0x00B0); //LCD SPECIFICATION
ssd1963_data(0x0020);
ssd1963_data(0x0000);
ssd1963_data(((SSD1963_HOR_RES - 1) >> 8) & 0X00FF); //Set HDP
ssd1963_data((SSD1963_HOR_RES - 1) & 0X00FF);
ssd1963_data(((SSD1963_VER_RES - 1) >> 8) & 0X00FF); //Set VDP
ssd1963_data((SSD1963_VER_RES - 1) & 0X00FF);
ssd1963_data(0x0000);
LV_DRV_DELAY_MS(1);//Delay10us(5);
ssd1963_cmd(0x00B4); //HSYNC
ssd1963_data((SSD1963_HT >> 8) & 0X00FF); //Set HT
ssd1963_data(SSD1963_HT & 0X00FF);
ssd1963_data((SSD1963_HPS >> 8) & 0X00FF); //Set HPS
ssd1963_data(SSD1963_HPS & 0X00FF);
ssd1963_data(SSD1963_HPW); //Set HPW
ssd1963_data((SSD1963_LPS >> 8) & 0X00FF); //SetLPS
ssd1963_data(SSD1963_LPS & 0X00FF);
ssd1963_data(0x0000);
ssd1963_cmd(0x00B6); //VSYNC
ssd1963_data((SSD1963_VT >> 8) & 0X00FF); //Set VT
ssd1963_data(SSD1963_VT & 0X00FF);
ssd1963_data((SSD1963_VPS >> 8) & 0X00FF); //Set VPS
ssd1963_data(SSD1963_VPS & 0X00FF);
ssd1963_data(SSD1963_VPW); //Set VPW
ssd1963_data((SSD1963_FPS >> 8) & 0X00FF); //Set FPS
ssd1963_data(SSD1963_FPS & 0X00FF);
ssd1963_cmd(0x00B8);
ssd1963_data(0x000f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF
ssd1963_data(0x0001); //GPIO0 normal
ssd1963_cmd(0x00BA);
ssd1963_data(0x0001); //GPIO[0] out 1 --- LCD display on/off control PIN
ssd1963_cmd(0x0036); //rotation
ssd1963_data(0x0008); //RGB=BGR
ssd1963_cmd(0x003A); //Set the current pixel format for RGB image data
ssd1963_data(0x0050); //16-bit/pixel
ssd1963_cmd(0x00F0); //Pixel Data Interface Format
ssd1963_data(0x0003); //16-bit(565 format) data
ssd1963_cmd(0x00BC);
ssd1963_data(0x0040); //contrast value
ssd1963_data(0x0080); //brightness value
ssd1963_data(0x0040); //saturation value
ssd1963_data(0x0001); //Post Processor Enable
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x0029); //display on
ssd1963_cmd(0x00BE); //set PWM for B/L
ssd1963_data(0x0006);
ssd1963_data(0x0080);
ssd1963_data(0x0001);
ssd1963_data(0x00f0);
ssd1963_data(0x0000);
ssd1963_data(0x0000);
ssd1963_cmd(0x00d0);
ssd1963_data(0x000d);
//DisplayBacklightOn();
LV_DRV_DELAY_MS(30);
}
void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(area->x2 < 0) return;
if(area->y2 < 0) return;
if(area->x1 > SSD1963_HOR_RES - 1) return;
if(area->y1 > SSD1963_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > SSD1963_HOR_RES - 1 ? SSD1963_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > SSD1963_VER_RES - 1 ? SSD1963_VER_RES - 1 : area->y2;
//Set the rectangular area
ssd1963_cmd(0x002A);
ssd1963_data(act_x1 >> 8);
ssd1963_data(0x00FF & act_x1);
ssd1963_data(act_x2 >> 8);
ssd1963_data(0x00FF & act_x2);
ssd1963_cmd(0x002B);
ssd1963_data(act_y1 >> 8);
ssd1963_data(0x00FF & act_y1);
ssd1963_data(act_y2 >> 8);
ssd1963_data(0x00FF & act_y2);
ssd1963_cmd(0x2c);
int16_t i;
uint16_t full_w = area->x2 - area->x1 + 1;
ssd1963_data_mode();
LV_DRV_DISP_PAR_CS(0);
#if LV_COLOR_DEPTH == 16
uint16_t act_w = act_x2 - act_x1 + 1;
for(i = act_y1; i <= act_y2; i++) {
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
color_p += full_w;
}
LV_DRV_DISP_PAR_CS(1);
#else
int16_t j;
for(i = act_y1; i <= act_y2; i++) {
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
LV_DRV_DISP_PAR_WR_WORD(color_p[j]);
color_p += full_w;
}
}
#endif
lv_disp_flush_ready(disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void ssd1963_io_init(void)
{
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
cmd_mode = true;
}
static void ssd1963_reset(void)
{
/*Hardware reset*/
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
/*Chip enable*/
LV_DRV_DISP_PAR_CS(0);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_PAR_CS(1);
LV_DRV_DELAY_MS(5);
/*Software reset*/
ssd1963_cmd(0x01);
LV_DRV_DELAY_MS(20);
ssd1963_cmd(0x01);
LV_DRV_DELAY_MS(20);
ssd1963_cmd(0x01);
LV_DRV_DELAY_MS(20);
}
/**
* Command mode
*/
static inline void ssd1963_cmd_mode(void)
{
if(cmd_mode == false) {
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
cmd_mode = true;
}
}
/**
* Data mode
*/
static inline void ssd1963_data_mode(void)
{
if(cmd_mode != false) {
LV_DRV_DISP_CMD_DATA(SSD1963_DATA_MODE);
cmd_mode = false;
}
}
/**
* Write command
* @param cmd the command
*/
static inline void ssd1963_cmd(uint8_t cmd)
{
LV_DRV_DISP_PAR_CS(0);
ssd1963_cmd_mode();
LV_DRV_DISP_PAR_WR_WORD(cmd);
LV_DRV_DISP_PAR_CS(1);
}
/**
* Write data
* @param data the data
*/
static inline void ssd1963_data(uint8_t data)
{
LV_DRV_DISP_PAR_CS(0);
ssd1963_data_mode();
LV_DRV_DISP_PAR_WR_WORD(data);
LV_DRV_DISP_PAR_CS(1);
}
#endif

View File

@ -1,150 +0,0 @@
/**
* @file SSD1963.h
*
*/
#ifndef SSD1963_H
#define SSD1963_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_SSD1963
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
// SSD1963 command table
#define CMD_NOP 0x00 //No operation
#define CMD_SOFT_RESET 0x01 //Software reset
#define CMD_GET_PWR_MODE 0x0A //Get the current power mode
#define CMD_GET_ADDR_MODE 0x0B //Get the frame memory to the display panel read order
#define CMD_GET_PIXEL_FORMAT 0x0C //Get the current pixel format
#define CMD_GET_DISPLAY_MODE 0x0D //Returns the display mode
#define CMD_GET_SIGNAL_MODE 0x0E //
#define CMD_GET_DIAGNOSTIC 0x0F
#define CMD_ENT_SLEEP 0x10
#define CMD_EXIT_SLEEP 0x11
#define CMD_ENT_PARTIAL_MODE 0x12
#define CMD_ENT_NORMAL_MODE 0x13
#define CMD_EXIT_INVERT_MODE 0x20
#define CMD_ENT_INVERT_MODE 0x21
#define CMD_SET_GAMMA 0x26
#define CMD_BLANK_DISPLAY 0x28
#define CMD_ON_DISPLAY 0x29
#define CMD_SET_COLUMN 0x2A
#define CMD_SET_PAGE 0x2B
#define CMD_WR_MEMSTART 0x2C
#define CMD_RD_MEMSTART 0x2E
#define CMD_SET_PARTIAL_AREA 0x30
#define CMD_SET_SCROLL_AREA 0x33
#define CMD_SET_TEAR_OFF 0x34 //synchronization information is not sent from the display
#define CMD_SET_TEAR_ON 0x35 //sync. information is sent from the display
#define CMD_SET_ADDR_MODE 0x36 //set fram buffer read order to the display panel
#define CMD_SET_SCROLL_START 0x37
#define CMD_EXIT_IDLE_MODE 0x38
#define CMD_ENT_IDLE_MODE 0x39
#define CMD_SET_PIXEL_FORMAT 0x3A //defines how many bits per pixel is used
#define CMD_WR_MEM_AUTO 0x3C
#define CMD_RD_MEM_AUTO 0x3E
#define CMD_SET_TEAR_SCANLINE 0x44
#define CMD_GET_SCANLINE 0x45
#define CMD_RD_DDB_START 0xA1
#define CMD_RD_DDB_AUTO 0xA8
#define CMD_SET_PANEL_MODE 0xB0
#define CMD_GET_PANEL_MODE 0xB1
#define CMD_SET_HOR_PERIOD 0xB4
#define CMD_GET_HOR_PERIOD 0xB5
#define CMD_SET_VER_PERIOD 0xB6
#define CMD_GET_VER_PERIOD 0xB7
#define CMD_SET_GPIO_CONF 0xB8
#define CMD_GET_GPIO_CONF 0xB9
#define CMD_SET_GPIO_VAL 0xBA
#define CMD_GET_GPIO_STATUS 0xBB
#define CMD_SET_POST_PROC 0xBC
#define CMD_GET_POST_PROC 0xBD
#define CMD_SET_PWM_CONF 0xBE
#define CMD_GET_PWM_CONF 0xBF
#define CMD_SET_LCD_GEN0 0xC0
#define CMD_GET_LCD_GEN0 0xC1
#define CMD_SET_LCD_GEN1 0xC2
#define CMD_GET_LCD_GEN1 0xC3
#define CMD_SET_LCD_GEN2 0xC4
#define CMD_GET_LCD_GEN2 0xC5
#define CMD_SET_LCD_GEN3 0xC6
#define CMD_GET_LCD_GEN3 0xC7
#define CMD_SET_GPIO0_ROP 0xC8
#define CMD_GET_GPIO0_ROP 0xC9
#define CMD_SET_GPIO1_ROP 0xCA
#define CMD_GET_GPIO1_ROP 0xCB
#define CMD_SET_GPIO2_ROP 0xCC
#define CMD_GET_GPIO2_ROP 0xCD
#define CMD_SET_GPIO3_ROP 0xCE
#define CMD_GET_GPIO3_ROP 0xCF
#define CMD_SET_ABC_DBC_CONF 0xD0
#define CMD_GET_ABC_DBC_CONF 0xD1
#define CMD_SET_DBC_HISTO_PTR 0xD2
#define CMD_GET_DBC_HISTO_PTR 0xD3
#define CMD_SET_DBC_THRES 0xD4
#define CMD_GET_DBC_THRES 0xD5
#define CMD_SET_ABM_TMR 0xD6
#define CMD_GET_ABM_TMR 0xD7
#define CMD_SET_AMB_LVL0 0xD8
#define CMD_GET_AMB_LVL0 0xD9
#define CMD_SET_AMB_LVL1 0xDA
#define CMD_GET_AMB_LVL1 0xDB
#define CMD_SET_AMB_LVL2 0xDC
#define CMD_GET_AMB_LVL2 0xDD
#define CMD_SET_AMB_LVL3 0xDE
#define CMD_GET_AMB_LVL3 0xDF
#define CMD_PLL_START 0xE0 //start the PLL
#define CMD_PLL_STOP 0xE1 //disable the PLL
#define CMD_SET_PLL_MN 0xE2
#define CMD_GET_PLL_MN 0xE3
#define CMD_GET_PLL_STATUS 0xE4 //get the current PLL status
#define CMD_ENT_DEEP_SLEEP 0xE5
#define CMD_SET_PCLK 0xE6 //set pixel clock (LSHIFT signal) frequency
#define CMD_GET_PCLK 0xE7 //get pixel clock (LSHIFT signal) freq. settings
#define CMD_SET_DATA_INTERFACE 0xF0
#define CMD_GET_DATA_INTERFACE 0xF1
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void ssd1963_init(void);
void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_SSD1963 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SSD1963_H */

View File

@ -1,289 +0,0 @@
/**
* @file ST7565.c
*
*/
/*********************
* INCLUDES
*********************/
#include "ST7565.h"
#if USE_ST7565
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "lvgl/lv_core/lv_vdb.h"
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define ST7565_BAUD 2000000 /*< 2,5 MHz (400 ns)*/
#define ST7565_CMD_MODE 0
#define ST7565_DATA_MODE 1
#define ST7565_HOR_RES 128
#define ST7565_VER_RES 64
#define CMD_DISPLAY_OFF 0xAE
#define CMD_DISPLAY_ON 0xAF
#define CMD_SET_DISP_START_LINE 0x40
#define CMD_SET_PAGE 0xB0
#define CMD_SET_COLUMN_UPPER 0x10
#define CMD_SET_COLUMN_LOWER 0x00
#define CMD_SET_ADC_NORMAL 0xA0
#define CMD_SET_ADC_REVERSE 0xA1
#define CMD_SET_DISP_NORMAL 0xA6
#define CMD_SET_DISP_REVERSE 0xA7
#define CMD_SET_ALLPTS_NORMAL 0xA4
#define CMD_SET_ALLPTS_ON 0xA5
#define CMD_SET_BIAS_9 0xA2
#define CMD_SET_BIAS_7 0xA3
#define CMD_RMW 0xE0
#define CMD_RMW_CLEAR 0xEE
#define CMD_INTERNAL_RESET 0xE2
#define CMD_SET_COM_NORMAL 0xC0
#define CMD_SET_COM_REVERSE 0xC8
#define CMD_SET_POWER_CONTROL 0x28
#define CMD_SET_RESISTOR_RATIO 0x20
#define CMD_SET_VOLUME_FIRST 0x81
#define CMD_SET_VOLUME_SECOND 0x00
#define CMD_SET_STATIC_OFF 0xAC
#define CMD_SET_STATIC_ON 0xAD
#define CMD_SET_STATIC_REG 0x00
#define CMD_SET_BOOSTER_FIRST 0xF8
#define CMD_SET_BOOSTER_234 0x00
#define CMD_SET_BOOSTER_5 0x01
#define CMD_SET_BOOSTER_6 0x03
#define CMD_NOP 0xE3
#define CMD_TEST 0xF0
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2);
static void st7565_command(uint8_t cmd);
static void st7565_data(uint8_t data);
/**********************
* STATIC VARIABLES
**********************/
static uint8_t lcd_fb[ST7565_HOR_RES * ST7565_VER_RES / 8] = {0xAA, 0xAA};
static uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the ST7565
*/
void st7565_init(void)
{
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_SPI_CS(0);
st7565_command(CMD_SET_BIAS_7);
st7565_command(CMD_SET_ADC_NORMAL);
st7565_command(CMD_SET_COM_NORMAL);
st7565_command(CMD_SET_DISP_START_LINE);
st7565_command(CMD_SET_POWER_CONTROL | 0x4);
LV_DRV_DELAY_MS(50);
st7565_command(CMD_SET_POWER_CONTROL | 0x6);
LV_DRV_DELAY_MS(50);
st7565_command(CMD_SET_POWER_CONTROL | 0x7);
LV_DRV_DELAY_MS(10);
st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); // Defaulted to 0x26 (but could also be between 0x20-0x27 based on display's specs)
st7565_command(CMD_DISPLAY_ON);
st7565_command(CMD_SET_ALLPTS_NORMAL);
/*Set brightness*/
st7565_command(CMD_SET_VOLUME_FIRST);
st7565_command(CMD_SET_VOLUME_SECOND | (0x18 & 0x3f));
LV_DRV_DISP_SPI_CS(1);
memset(lcd_fb, 0x00, sizeof(lcd_fb));
}
void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > ST7565_HOR_RES - 1) return;
if(y1 > ST7565_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
int32_t x, y;
/*Set the first row in */
/*Refresh frame buffer*/
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
if(lv_color_to1(*color_p) != 0) {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
} else {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
}
color_p ++;
}
color_p += x2 - act_x2; /*Next row*/
}
st7565_sync(act_x1, act_y1, act_x2, act_y2);
lv_flush_ready();
}
void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > ST7565_HOR_RES - 1) return;
if(y1 > ST7565_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
int32_t x, y;
uint8_t white = lv_color_to1(color);
/*Refresh frame buffer*/
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
if(white != 0) {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
} else {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
}
}
}
st7565_sync(act_x1, act_y1, act_x2, act_y2);
}
void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > ST7565_HOR_RES - 1) return;
if(y1 > ST7565_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
int32_t x, y;
/*Set the first row in */
/*Refresh frame buffer*/
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
if(lv_color_to1(*color_p) != 0) {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
} else {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
}
color_p ++;
}
color_p += x2 - act_x2; /*Next row*/
}
st7565_sync(act_x1, act_y1, act_x2, act_y2);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Flush a specific part of the buffer to the display
* @param x1 left coordinate of the area to flush
* @param y1 top coordinate of the area to flush
* @param x2 right coordinate of the area to flush
* @param y2 bottom coordinate of the area to flush
*/
static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
{
LV_DRV_DISP_SPI_CS(0);
uint8_t c, p;
for(p = y1 / 8; p <= y2 / 8; p++) {
st7565_command(CMD_SET_PAGE | pagemap[p]);
st7565_command(CMD_SET_COLUMN_LOWER | (x1 & 0xf));
st7565_command(CMD_SET_COLUMN_UPPER | ((x1 >> 4) & 0xf));
st7565_command(CMD_RMW);
for(c = x1; c <= x2; c++) {
st7565_data(lcd_fb[(ST7565_HOR_RES * p) + c]);
}
}
LV_DRV_DISP_SPI_CS(1);
}
/**
* Write a command to the ST7565
* @param cmd the command
*/
static void st7565_command(uint8_t cmd)
{
LV_DRV_DISP_CMD_DATA(ST7565_CMD_MODE);
LV_DRV_DISP_SPI_WR_BYTE(cmd);
}
/**
* Write data to the ST7565
* @param data the data
*/
static void st7565_data(uint8_t data)
{
LV_DRV_DISP_CMD_DATA(ST7565_DATA_MODE);
LV_DRV_DISP_SPI_WR_BYTE(data);
}
#endif

View File

@ -1,58 +0,0 @@
/**
* @file ST7565.h
*
*/
#ifndef ST7565_H
#define ST7565_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_ST7565
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void st7565_init(void);
void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_ST7565 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ST7565_H */

View File

@ -1,206 +0,0 @@
/**
* @file UC1610.c
*
*/
/*********************
* INCLUDES
*********************/
#include "UC1610.h"
#if USE_UC1610
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define UC1610_CMD_MODE 0
#define UC1610_DATA_MODE 1
#define UC1610_RESET_MODE 0
#define UC1610_SET_MODE 1
/* hardware control commands */
#define UC1610_SYSTEM_RESET 0xE2 /* software reset */
#define UC1610_NOP 0xE3
#define UC1610_SET_TEMP_COMP 0x24 /* set temperature compensation, default -0.05%/°C */
#define UC1610_SET_PANEL_LOADING 0x29 /* set panel loading, default 16~21 nF */
#define UC1610_SET_PUMP_CONTROL 0x2F /* default internal Vlcd (8x pump) */
#define UC1610_SET_LCD_BIAS_RATIO 0xEB /* default 11 */
#define UC1610_SET_VBIAS_POT 0x81 /* 1 byte (0~255) to follow setting the contrast, default 0x81 */
#define UC1610_SET_LINE_RATE 0xA0 /* default 12,1 Klps */
#define UC1610_SET_DISPLAY_ENABLE 0xAE /* + 1 / 0 : exit sleep mode / entering sleep mode */
#define UC1610_SET_LCD_GRAY_SHADE 0xD0 /* default 24% between the two gray shade levels */
#define UC1610_SET_COM_END 0xF1 /* set the number of used com electrodes (lines number -1) */
/* ram address control */
#define UC1610_SET_AC 0x88 /* set ram address control */
#define UC1610_AC_WA_FLAG 1 /* automatic column/page increment wrap around (1 : cycle increment) */
#define UC1610_AC_AIO_FLAG (1 << 1) /* auto increment order (0/1 : column/page increment first) */
#define UC1610_AC_PID_FLAG (1 << 2) /* page address auto increment order (0/1 : +1/-1) */
/* set cursor ram address */
#define UC1610_SET_CA_LSB 0x00 /* + 4 LSB bits */
#define UC1610_SET_CA_MSB 0x10 /* + 4 MSB bits // MSB + LSB values range : 0~159 */
#define UC1610_SET_PA 0x60 /* + 5 bits // values range : 0~26 */
/* display control commands */
#define UC1610_SET_FIXED_LINES 0x90 /* + 4 bits = 2xFL */
#define UC1610_SET_SCROLL_LINES_LSB 0x40 /* + 4 LSB bits scroll up display by N (7 bits) lines */
#define UC1610_SET_SCROLL_LINES_MSB 0x50 /* + 3 MSB bits */
#define UC1610_SET_ALL_PIXEL_ON 0xA4 /* + 1 / 0 : set all pixel on, reverse */
#define UC1610_SET_INVERSE_DISPLAY 0xA6 /* + 1 / 0 : inverse all data stored in ram, reverse */
#define UC1610_SET_MAPPING_CONTROL 0xC0 /* control mirroring */
#define UC1610_SET_MAPPING_CONTROL_LC_FLAG 1
#define UC1610_SET_MAPPING_CONTROL_MX_FLAG (1 << 1)
#define UC1610_SET_MAPPING_CONTROL_MY_FLAG (1 << 2)
/* window program mode */
#define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 /* + 1 / 0 : enable / disable window programming mode, */
/* reset before changing boundaries */
#define UC1610_SET_WP_STARTING_CA 0xF4 /* 1 byte to follow for column address */
#define UC1610_SET_WP_ENDING_CA 0xF6 /* 1 byte to follow for column address */
#define UC1610_SET_WP_STARTING_PA 0xF5 /* 1 byte to follow for page address */
#define UC1610_SET_WP_ENDING_PA 0xF7 /* 1 byte to follow for page address */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static uint8_t cmd_buf[12];
/**********************
* MACROS
**********************/
/* Return the byte bitmask of a pixel color corresponding to draw_buf arrangement */
#define PIXIDX(y, c) ((c) << (((y) & 3) << 1))
/**********************
* GLOBAL FUNCTIONS
**********************/
void uc1610_init(void) {
LV_DRV_DELAY_MS(12);
/* initialization sequence */
#if UC1610_INIT_HARD_RST
LV_DRV_DISP_RST(UC1610_RESET_MODE); /* hardware reset */
LV_DRV_DELAY_MS(1);
LV_DRV_DISP_RST(UC1610_SET_MODE);
#else
cmd_buf[0] = UC1610_SYSTEM_RESET; /* software reset */
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 1);
LV_DRV_DISP_SPI_CS(1);
#endif
LV_DRV_DELAY_MS(2);
cmd_buf[0] = UC1610_SET_COM_END; /* set com end value */
cmd_buf[1] = UC1610_VER_RES - 1;
cmd_buf[2] = UC1610_SET_PANEL_LOADING;
cmd_buf[3] = UC1610_SET_LCD_BIAS_RATIO;
cmd_buf[4] = UC1610_SET_VBIAS_POT; /* set contrast */
cmd_buf[5] = (UC1610_INIT_CONTRAST * 255) / 100;
#if UC1610_TOP_VIEW
cmd_buf[6] = UC1610_SET_MAPPING_CONTROL | /* top view */
UC1610_SET_MAPPING_CONTROL_MY_FLAG |
UC1610_SET_MAPPING_CONTROL_MX_FLAG;
#else
cmd_buf[6] = UC1610_SET_MAPPING_CONTROL; /* bottom view */
#endif
cmd_buf[7] = UC1610_SET_SCROLL_LINES_LSB | 0; /* set scroll line on line 0 */
cmd_buf[8] = UC1610_SET_SCROLL_LINES_MSB | 0;
cmd_buf[9] = UC1610_SET_AC | UC1610_AC_WA_FLAG; /* set auto increment wrap around */
cmd_buf[10] = UC1610_SET_INVERSE_DISPLAY | 1; /* invert colors to complies lv color system */
cmd_buf[11] = UC1610_SET_DISPLAY_ENABLE | 1; /* turn display on */
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 12);
LV_DRV_DISP_SPI_CS(1);
}
void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
/*Return if the area is out the screen*/
if(area->x2 < 0) return;
if(area->y2 < 0) return;
if(area->x1 > UC1610_HOR_RES - 1) return;
if(area->y1 > UC1610_VER_RES - 1) return;
/*Truncate the area to the screen*/
uint8_t act_x1 = area->x1 < 0 ? 0 : area->x1;
uint8_t act_y1 = area->y1 < 0 ? 0 : area->y1;
uint8_t act_x2 = area->x2 > UC1610_HOR_RES - 1 ? UC1610_HOR_RES - 1 : area->x2;
uint8_t act_y2 = area->y2 > UC1610_VER_RES - 1 ? UC1610_VER_RES - 1 : area->y2;
uint8_t * buf = (uint8_t *) color_p;
uint16_t buf_size = (act_x2 - act_x1 + 1) * (((act_y2 - act_y1) >> 2) + 1);
/*Set display window to fill*/
cmd_buf[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; /* before changing boundaries */
cmd_buf[1] = UC1610_SET_WP_STARTING_CA;
cmd_buf[2] = act_x1;
cmd_buf[3] = UC1610_SET_WP_ENDING_CA;
cmd_buf[4] = act_x2;
cmd_buf[5] = UC1610_SET_WP_STARTING_PA;
cmd_buf[6] = act_y1 >> 2;
cmd_buf[7] = UC1610_SET_WP_ENDING_PA;
cmd_buf[8] = act_y2 >> 2;
cmd_buf[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; /* entering window programming */
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 10);
LV_DRV_DISP_SPI_CS(1);
/*Flush draw_buf on display memory*/
LV_DRV_DISP_CMD_DATA(UC1610_DATA_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size);
LV_DRV_DISP_SPI_CS(1);
lv_disp_flush_ready(disp_drv);
}
void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
(void) disp_drv;
(void) opa;
uint16_t idx = x + buf_w * (y >> 2);
/* Convert color to depth 2 */
#if LV_COLOR_DEPTH == 1
uint8_t color2 = color.full * 3;
#else
uint8_t color2 = color.full >> (LV_COLOR_DEPTH - 2);
#endif
buf[idx] &= ~PIXIDX(y, 3); /* reset pixel color */
buf[idx] |= PIXIDX(y, color2); /* write new color */
}
void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area) {
(void) disp_drv;
/* Round y window to display memory page size */
area->y1 = (area->y1 & (~3));
area->y2 = (area->y2 & (~3)) + 3;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -1,58 +0,0 @@
/**
* @file UC1610.h
*
*/
#ifndef UC1610_H
#define UC1610_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_UC1610
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void uc1610_init(void);
void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area);
void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
/**********************
* MACROS
**********************/
#endif /* USE_UC1610 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UC1610_H */

View File

@ -1,801 +0,0 @@
/**
* @file drm.c
*
*/
/*********************
* INCLUDES
*********************/
#include "drm.h"
#if USE_DRM
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <inttypes.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#define DBG_TAG "drm"
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define print(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__);
#define err(msg, ...) print("error: " msg "\n", ##__VA_ARGS__)
#define info(msg, ...) print(msg "\n", ##__VA_ARGS__)
#define dbg(msg, ...) {} //print(DBG_TAG ": " msg "\n", ##__VA_ARGS__)
struct drm_buffer {
uint32_t handle;
uint32_t pitch;
uint32_t offset;
unsigned long int size;
void * map;
uint32_t fb_handle;
};
struct drm_dev {
int fd;
uint32_t conn_id, enc_id, crtc_id, plane_id, crtc_idx;
uint32_t width, height;
uint32_t mmWidth, mmHeight;
uint32_t fourcc;
drmModeModeInfo mode;
uint32_t blob_id;
drmModeCrtc *saved_crtc;
drmModeAtomicReq *req;
drmEventContext drm_event_ctx;
drmModePlane *plane;
drmModeCrtc *crtc;
drmModeConnector *conn;
uint32_t count_plane_props;
uint32_t count_crtc_props;
uint32_t count_conn_props;
drmModePropertyPtr plane_props[128];
drmModePropertyPtr crtc_props[128];
drmModePropertyPtr conn_props[128];
struct drm_buffer drm_bufs[2]; /* DUMB buffers */
struct drm_buffer *cur_bufs[2]; /* double buffering handling */
} drm_dev;
static uint32_t get_plane_property_id(const char *name)
{
uint32_t i;
dbg("Find plane property: %s", name);
for (i = 0; i < drm_dev.count_plane_props; ++i)
if (!strcmp(drm_dev.plane_props[i]->name, name))
return drm_dev.plane_props[i]->prop_id;
dbg("Unknown plane property: %s", name);
return 0;
}
static uint32_t get_crtc_property_id(const char *name)
{
uint32_t i;
dbg("Find crtc property: %s", name);
for (i = 0; i < drm_dev.count_crtc_props; ++i)
if (!strcmp(drm_dev.crtc_props[i]->name, name))
return drm_dev.crtc_props[i]->prop_id;
dbg("Unknown crtc property: %s", name);
return 0;
}
static uint32_t get_conn_property_id(const char *name)
{
uint32_t i;
dbg("Find conn property: %s", name);
for (i = 0; i < drm_dev.count_conn_props; ++i)
if (!strcmp(drm_dev.conn_props[i]->name, name))
return drm_dev.conn_props[i]->prop_id;
dbg("Unknown conn property: %s", name);
return 0;
}
static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
unsigned int tv_usec, void *user_data)
{
dbg("flip");
}
static int drm_get_plane_props(void)
{
uint32_t i;
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.plane_id,
DRM_MODE_OBJECT_PLANE);
if (!props) {
err("drmModeObjectGetProperties failed");
return -1;
}
dbg("Found %u plane props", props->count_props);
drm_dev.count_plane_props = props->count_props;
for (i = 0; i < props->count_props; i++) {
drm_dev.plane_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
dbg("Added plane prop %u:%s", drm_dev.plane_props[i]->prop_id, drm_dev.plane_props[i]->name);
}
drmModeFreeObjectProperties(props);
return 0;
}
static int drm_get_crtc_props(void)
{
uint32_t i;
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!props) {
err("drmModeObjectGetProperties failed");
return -1;
}
dbg("Found %u crtc props", props->count_props);
drm_dev.count_crtc_props = props->count_props;
for (i = 0; i < props->count_props; i++) {
drm_dev.crtc_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
dbg("Added crtc prop %u:%s", drm_dev.crtc_props[i]->prop_id, drm_dev.crtc_props[i]->name);
}
drmModeFreeObjectProperties(props);
return 0;
}
static int drm_get_conn_props(void)
{
uint32_t i;
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.conn_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!props) {
err("drmModeObjectGetProperties failed");
return -1;
}
dbg("Found %u connector props", props->count_props);
drm_dev.count_conn_props = props->count_props;
for (i = 0; i < props->count_props; i++) {
drm_dev.conn_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
dbg("Added connector prop %u:%s", drm_dev.conn_props[i]->prop_id, drm_dev.conn_props[i]->name);
}
drmModeFreeObjectProperties(props);
return 0;
}
static int drm_add_plane_property(const char *name, uint64_t value)
{
int ret;
uint32_t prop_id = get_plane_property_id(name);
if (!prop_id) {
err("Couldn't find plane prop %s", name);
return -1;
}
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.plane_id, get_plane_property_id(name), value);
if (ret < 0) {
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
return ret;
}
return 0;
}
static int drm_add_crtc_property(const char *name, uint64_t value)
{
int ret;
uint32_t prop_id = get_crtc_property_id(name);
if (!prop_id) {
err("Couldn't find crtc prop %s", name);
return -1;
}
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.crtc_id, get_crtc_property_id(name), value);
if (ret < 0) {
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
return ret;
}
return 0;
}
static int drm_add_conn_property(const char *name, uint64_t value)
{
int ret;
uint32_t prop_id = get_conn_property_id(name);
if (!prop_id) {
err("Couldn't find conn prop %s", name);
return -1;
}
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.conn_id, get_conn_property_id(name), value);
if (ret < 0) {
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
return ret;
}
return 0;
}
static int drm_dmabuf_set_plane(struct drm_buffer *buf)
{
int ret;
static int first = 1;
uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT;
drm_dev.req = drmModeAtomicAlloc();
/* On first Atomic commit, do a modeset */
if (first) {
drm_add_conn_property("CRTC_ID", drm_dev.crtc_id);
drm_add_crtc_property("MODE_ID", drm_dev.blob_id);
drm_add_crtc_property("ACTIVE", 1);
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
first = 0;
}
drm_add_plane_property("FB_ID", buf->fb_handle);
drm_add_plane_property("CRTC_ID", drm_dev.crtc_id);
drm_add_plane_property("SRC_X", 0);
drm_add_plane_property("SRC_Y", 0);
drm_add_plane_property("SRC_W", drm_dev.width << 16);
drm_add_plane_property("SRC_H", drm_dev.height << 16);
drm_add_plane_property("CRTC_X", 0);
drm_add_plane_property("CRTC_Y", 0);
drm_add_plane_property("CRTC_W", drm_dev.width);
drm_add_plane_property("CRTC_H", drm_dev.height);
ret = drmModeAtomicCommit(drm_dev.fd, drm_dev.req, flags, NULL);
if (ret) {
err("drmModeAtomicCommit failed: %s", strerror(errno));
drmModeAtomicFree(drm_dev.req);
return ret;
}
return 0;
}
static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx)
{
drmModePlaneResPtr planes;
drmModePlanePtr plane;
unsigned int i;
unsigned int j;
int ret = 0;
unsigned int format = fourcc;
planes = drmModeGetPlaneResources(drm_dev.fd);
if (!planes) {
err("drmModeGetPlaneResources failed");
return -1;
}
dbg("drm: found planes %u", planes->count_planes);
for (i = 0; i < planes->count_planes; ++i) {
plane = drmModeGetPlane(drm_dev.fd, planes->planes[i]);
if (!plane) {
err("drmModeGetPlane failed: %s", strerror(errno));
break;
}
if (!(plane->possible_crtcs & (1 << crtc_idx))) {
drmModeFreePlane(plane);
continue;
}
for (j = 0; j < plane->count_formats; ++j) {
if (plane->formats[j] == format)
break;
}
if (j == plane->count_formats) {
drmModeFreePlane(plane);
continue;
}
*plane_id = plane->plane_id;
drmModeFreePlane(plane);
dbg("found plane %d", *plane_id);
break;
}
if (i == planes->count_planes)
ret = -1;
drmModeFreePlaneResources(planes);
return ret;
}
static int drm_find_connector(void)
{
drmModeConnector *conn = NULL;
drmModeEncoder *enc = NULL;
drmModeRes *res;
int i;
if ((res = drmModeGetResources(drm_dev.fd)) == NULL) {
err("drmModeGetResources() failed");
return -1;
}
if (res->count_crtcs <= 0) {
err("no Crtcs");
goto free_res;
}
/* find all available connectors */
for (i = 0; i < res->count_connectors; i++) {
conn = drmModeGetConnector(drm_dev.fd, res->connectors[i]);
if (!conn)
continue;
#if DRM_CONNECTOR_ID >= 0
if (conn->connector_id != DRM_CONNECTOR_ID) {
drmModeFreeConnector(conn);
continue;
}
#endif
if (conn->connection == DRM_MODE_CONNECTED) {
dbg("drm: connector %d: connected", conn->connector_id);
} else if (conn->connection == DRM_MODE_DISCONNECTED) {
dbg("drm: connector %d: disconnected", conn->connector_id);
} else if (conn->connection == DRM_MODE_UNKNOWNCONNECTION) {
dbg("drm: connector %d: unknownconnection", conn->connector_id);
} else {
dbg("drm: connector %d: unknown", conn->connector_id);
}
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
break;
drmModeFreeConnector(conn);
conn = NULL;
};
if (!conn) {
err("suitable connector not found");
goto free_res;
}
drm_dev.conn_id = conn->connector_id;
dbg("conn_id: %d", drm_dev.conn_id);
drm_dev.mmWidth = conn->mmWidth;
drm_dev.mmHeight = conn->mmHeight;
memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo));
if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode),
&drm_dev.blob_id)) {
err("error creating mode blob");
goto free_res;
}
drm_dev.width = conn->modes[0].hdisplay;
drm_dev.height = conn->modes[0].vdisplay;
for (i = 0 ; i < res->count_encoders; i++) {
enc = drmModeGetEncoder(drm_dev.fd, res->encoders[i]);
if (!enc)
continue;
dbg("enc%d enc_id %d conn enc_id %d", i, enc->encoder_id, conn->encoder_id);
if (enc->encoder_id == conn->encoder_id)
break;
drmModeFreeEncoder(enc);
enc = NULL;
}
if (enc) {
drm_dev.enc_id = enc->encoder_id;
dbg("enc_id: %d", drm_dev.enc_id);
drm_dev.crtc_id = enc->crtc_id;
dbg("crtc_id: %d", drm_dev.crtc_id);
drmModeFreeEncoder(enc);
} else {
/* Encoder hasn't been associated yet, look it up */
for (i = 0; i < conn->count_encoders; i++) {
int crtc, crtc_id = -1;
enc = drmModeGetEncoder(drm_dev.fd, conn->encoders[i]);
if (!enc)
continue;
for (crtc = 0 ; crtc < res->count_crtcs; crtc++) {
uint32_t crtc_mask = 1 << crtc;
crtc_id = res->crtcs[crtc];
dbg("enc_id %d crtc%d id %d mask %x possible %x", enc->encoder_id, crtc, crtc_id, crtc_mask, enc->possible_crtcs);
if (enc->possible_crtcs & crtc_mask)
break;
}
if (crtc_id > 0) {
drm_dev.enc_id = enc->encoder_id;
dbg("enc_id: %d", drm_dev.enc_id);
drm_dev.crtc_id = crtc_id;
dbg("crtc_id: %d", drm_dev.crtc_id);
break;
}
drmModeFreeEncoder(enc);
enc = NULL;
}
if (!enc) {
err("suitable encoder not found");
goto free_res;
}
drmModeFreeEncoder(enc);
}
drm_dev.crtc_idx = -1;
for (i = 0; i < res->count_crtcs; ++i) {
if (drm_dev.crtc_id == res->crtcs[i]) {
drm_dev.crtc_idx = i;
break;
}
}
if (drm_dev.crtc_idx == -1) {
err("drm: CRTC not found");
goto free_res;
}
dbg("crtc_idx: %d", drm_dev.crtc_idx);
return 0;
free_res:
drmModeFreeResources(res);
return -1;
}
static int drm_open(const char *path)
{
int fd, flags;
uint64_t has_dumb;
int ret;
fd = open(path, O_RDWR);
if (fd < 0) {
err("cannot open \"%s\"", path);
return -1;
}
/* set FD_CLOEXEC flag */
if ((flags = fcntl(fd, F_GETFD)) < 0 ||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
err("fcntl FD_CLOEXEC failed");
goto err;
}
/* check capability */
ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
if (ret < 0 || has_dumb == 0) {
err("drmGetCap DRM_CAP_DUMB_BUFFER failed or \"%s\" doesn't have dumb "
"buffer", path);
goto err;
}
return fd;
err:
close(fd);
return -1;
}
static int drm_setup(unsigned int fourcc)
{
int ret;
const char *device_path = NULL;
device_path = getenv("DRM_CARD");
if (!device_path)
device_path = DRM_CARD;
drm_dev.fd = drm_open(device_path);
if (drm_dev.fd < 0)
return -1;
ret = drmSetClientCap(drm_dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
if (ret) {
err("No atomic modesetting support: %s", strerror(errno));
goto err;
}
ret = drm_find_connector();
if (ret) {
err("available drm devices not found");
goto err;
}
ret = find_plane(fourcc, &drm_dev.plane_id, drm_dev.crtc_id, drm_dev.crtc_idx);
if (ret) {
err("Cannot find plane");
goto err;
}
drm_dev.plane = drmModeGetPlane(drm_dev.fd, drm_dev.plane_id);
if (!drm_dev.plane) {
err("Cannot get plane");
goto err;
}
drm_dev.crtc = drmModeGetCrtc(drm_dev.fd, drm_dev.crtc_id);
if (!drm_dev.crtc) {
err("Cannot get crtc");
goto err;
}
drm_dev.conn = drmModeGetConnector(drm_dev.fd, drm_dev.conn_id);
if (!drm_dev.conn) {
err("Cannot get connector");
goto err;
}
ret = drm_get_plane_props();
if (ret) {
err("Cannot get plane props");
goto err;
}
ret = drm_get_crtc_props();
if (ret) {
err("Cannot get crtc props");
goto err;
}
ret = drm_get_conn_props();
if (ret) {
err("Cannot get connector props");
goto err;
}
drm_dev.drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
drm_dev.drm_event_ctx.page_flip_handler = page_flip_handler;
drm_dev.fourcc = fourcc;
info("drm: Found plane_id: %u connector_id: %d crtc_id: %d",
drm_dev.plane_id, drm_dev.conn_id, drm_dev.crtc_id);
info("drm: %dx%d (%dmm X% dmm) pixel format %c%c%c%c",
drm_dev.width, drm_dev.height, drm_dev.mmWidth, drm_dev.mmHeight,
(fourcc>>0)&0xff, (fourcc>>8)&0xff, (fourcc>>16)&0xff, (fourcc>>24)&0xff);
return 0;
err:
close(drm_dev.fd);
return -1;
}
static int drm_allocate_dumb(struct drm_buffer *buf)
{
struct drm_mode_create_dumb creq;
struct drm_mode_map_dumb mreq;
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
int ret;
/* create dumb buffer */
memset(&creq, 0, sizeof(creq));
creq.width = drm_dev.width;
creq.height = drm_dev.height;
creq.bpp = LV_COLOR_DEPTH;
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
if (ret < 0) {
err("DRM_IOCTL_MODE_CREATE_DUMB fail");
return -1;
}
buf->handle = creq.handle;
buf->pitch = creq.pitch;
dbg("pitch %d", buf->pitch);
buf->size = creq.size;
dbg("size %d", buf->size);
/* prepare buffer for memory mapping */
memset(&mreq, 0, sizeof(mreq));
mreq.handle = creq.handle;
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (ret) {
err("DRM_IOCTL_MODE_MAP_DUMB fail");
return -1;
}
buf->offset = mreq.offset;
/* perform actual memory mapping */
buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset);
if (buf->map == MAP_FAILED) {
err("mmap fail");
return -1;
}
/* clear the framebuffer to 0 (= full transparency in ARGB8888) */
memset(buf->map, 0, creq.size);
/* create framebuffer object for the dumb-buffer */
handles[0] = creq.handle;
pitches[0] = creq.pitch;
offsets[0] = 0;
ret = drmModeAddFB2(drm_dev.fd, drm_dev.width, drm_dev.height, drm_dev.fourcc,
handles, pitches, offsets, &buf->fb_handle, 0);
if (ret) {
err("drmModeAddFB fail");
return -1;
}
return 0;
}
static int drm_setup_buffers(void)
{
int ret;
/* Allocate DUMB buffers */
ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]);
if (ret)
return ret;
ret = drm_allocate_dumb(&drm_dev.drm_bufs[1]);
if (ret)
return ret;
/* Set buffering handling */
drm_dev.cur_bufs[0] = NULL;
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[0];
return 0;
}
void drm_wait_vsync(lv_disp_drv_t *disp_drv)
{
int ret;
fd_set fds;
FD_ZERO(&fds);
FD_SET(drm_dev.fd, &fds);
do {
ret = select(drm_dev.fd + 1, &fds, NULL, NULL, NULL);
} while (ret == -1 && errno == EINTR);
if (ret < 0) {
err("select failed: %s", strerror(errno));
drmModeAtomicFree(drm_dev.req);
drm_dev.req = NULL;
return;
}
if (FD_ISSET(drm_dev.fd, &fds))
drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
drmModeAtomicFree(drm_dev.req);
drm_dev.req = NULL;
}
void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
struct drm_buffer *fbuf = drm_dev.cur_bufs[1];
lv_coord_t w = (area->x2 - area->x1 + 1);
lv_coord_t h = (area->y2 - area->y1 + 1);
int i, y;
dbg("x %d:%d y %d:%d w %d h %d", area->x1, area->x2, area->y1, area->y2, w, h);
/* Partial update */
if ((w != drm_dev.width || h != drm_dev.height) && drm_dev.cur_bufs[0])
memcpy(fbuf->map, drm_dev.cur_bufs[0]->map, fbuf->size);
for (y = 0, i = area->y1 ; i <= area->y2 ; ++i, ++y) {
memcpy((uint8_t *)fbuf->map + (area->x1 * (LV_COLOR_SIZE/8)) + (fbuf->pitch * i),
(uint8_t *)color_p + (w * (LV_COLOR_SIZE/8) * y),
w * (LV_COLOR_SIZE/8));
}
if (drm_dev.req)
drm_wait_vsync(disp_drv);
/* show fbuf plane */
if (drm_dmabuf_set_plane(fbuf)) {
err("Flush fail");
return;
}
else
dbg("Flush done");
if (!drm_dev.cur_bufs[0])
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1];
else
drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
drm_dev.cur_bufs[0] = fbuf;
lv_disp_flush_ready(disp_drv);
}
#if LV_COLOR_DEPTH == 32
#define DRM_FOURCC DRM_FORMAT_XRGB8888
#elif LV_COLOR_DEPTH == 16
#define DRM_FOURCC DRM_FORMAT_RGB565
#else
#error LV_COLOR_DEPTH not supported
#endif
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi)
{
if (width)
*width = drm_dev.width;
if (height)
*height = drm_dev.height;
if (dpi && drm_dev.mmWidth)
*dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000);
}
void drm_init(void)
{
int ret;
ret = drm_setup(DRM_FOURCC);
if (ret) {
close(drm_dev.fd);
drm_dev.fd = -1;
return;
}
ret = drm_setup_buffers();
if (ret) {
err("DRM buffer allocation failed");
close(drm_dev.fd);
drm_dev.fd = -1;
return;
}
info("DRM subsystem and buffer mapped successfully");
}
void drm_exit(void)
{
close(drm_dev.fd);
drm_dev.fd = -1;
}
#endif

View File

@ -1,60 +0,0 @@
/**
* @file drm.h
*
*/
#ifndef DRM_H
#define DRM_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_DRM
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void drm_init(void);
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi);
void drm_exit(void);
void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
void drm_wait_vsync(lv_disp_drv_t * drv);
/**********************
* MACROS
**********************/
#endif /*USE_DRM*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*DRM_H*/

View File

@ -1,277 +0,0 @@
/**
* @file fbdev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "fbdev.h"
#if USE_FBDEV || USE_BSD_FBDEV
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#if USE_BSD_FBDEV
#include <sys/fcntl.h>
#include <sys/time.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#else /* USE_BSD_FBDEV */
#include <linux/fb.h>
#endif /* USE_BSD_FBDEV */
/*********************
* DEFINES
*********************/
#ifndef FBDEV_PATH
#define FBDEV_PATH "/dev/fb0"
#endif
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STRUCTURES
**********************/
struct bsd_fb_var_info{
uint32_t xoffset;
uint32_t yoffset;
uint32_t xres;
uint32_t yres;
int bits_per_pixel;
};
struct bsd_fb_fix_info{
long int line_length;
long int smem_len;
};
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if USE_BSD_FBDEV
static struct bsd_fb_var_info vinfo;
static struct bsd_fb_fix_info finfo;
#else
static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
#endif /* USE_BSD_FBDEV */
static char *fbp = 0;
static long int screensize = 0;
static int fbfd = 0;
/**********************
* MACROS
**********************/
#if USE_BSD_FBDEV
#define FBIOBLANK FBIO_BLANK
#endif /* USE_BSD_FBDEV */
/**********************
* GLOBAL FUNCTIONS
**********************/
void fbdev_init(void)
{
// Open the file for reading and writing
fbfd = open(FBDEV_PATH, O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
return;
}
LV_LOG_INFO("The framebuffer device was opened successfully");
#if FBDEV_DISPLAY_POWER_ON
// Make sure that the display is on.
if (ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) {
perror("ioctl(FBIOBLANK)");
return;
}
#endif /* FBDEV_DISPLAY_POWER_ON */
#if USE_BSD_FBDEV
struct fbtype fb;
unsigned line_length;
//Get fb type
if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) {
perror("ioctl(FBIOGTYPE)");
return;
}
//Get screen width
if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) {
perror("ioctl(FBIO_GETLINEWIDTH)");
return;
}
vinfo.xres = (unsigned) fb.fb_width;
vinfo.yres = (unsigned) fb.fb_height;
vinfo.bits_per_pixel = fb.fb_depth;
vinfo.xoffset = 0;
vinfo.yoffset = 0;
finfo.line_length = line_length;
finfo.smem_len = finfo.line_length * vinfo.yres;
#else /* USE_BSD_FBDEV */
// Get fixed screen information
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
return;
}
// Get variable screen information
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
return;
}
#endif /* USE_BSD_FBDEV */
LV_LOG_INFO("%dx%d, %dbpp", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
// Figure out the size of the screen in bytes
screensize = finfo.smem_len; //finfo.line_length * vinfo.yres;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if((intptr_t)fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
return;
}
// Don't initialise the memory to retain what's currently displayed / avoid clearing the screen.
// This is important for applications that only draw to a subsection of the full framebuffer.
LV_LOG_INFO("The framebuffer device was mapped to memory successfully");
}
void fbdev_exit(void)
{
close(fbfd);
}
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
if(fbp == NULL ||
area->x2 < 0 ||
area->y2 < 0 ||
area->x1 > (int32_t)vinfo.xres - 1 ||
area->y1 > (int32_t)vinfo.yres - 1) {
lv_disp_flush_ready(drv);
return;
}
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2;
int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2;
lv_coord_t w = (act_x2 - act_x1 + 1);
long int location = 0;
long int byte_location = 0;
unsigned char bit_location = 0;
/*32 or 24 bit per pixel*/
if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {
uint32_t * fbp32 = (uint32_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 4;
memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4);
color_p += w;
}
}
/*16 bit per pixel*/
else if(vinfo.bits_per_pixel == 16) {
uint16_t * fbp16 = (uint16_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2;
memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2);
color_p += w;
}
}
/*8 bit per pixel*/
else if(vinfo.bits_per_pixel == 8) {
uint8_t * fbp8 = (uint8_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length;
memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1));
color_p += w;
}
}
/*1 bit per pixel*/
else if(vinfo.bits_per_pixel == 1) {
uint8_t * fbp8 = (uint8_t *)fbp;
int32_t x;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
location = (x + vinfo.xoffset) + (y + vinfo.yoffset) * vinfo.xres;
byte_location = location / 8; /* find the byte we need to change */
bit_location = location % 8; /* inside the byte found, find the bit we need to change */
fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location);
fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location;
color_p++;
}
color_p += area->x2 - act_x2;
}
} else {
/*Not supported bit per pixel*/
}
//May be some direct update command is required
//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));
lv_disp_flush_ready(drv);
}
void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *dpi) {
if (width)
*width = vinfo.xres;
if (height)
*height = vinfo.yres;
if (dpi && vinfo.height)
*dpi = DIV_ROUND_UP(vinfo.xres * 254, vinfo.width * 10);
}
void fbdev_set_offset(uint32_t xoffset, uint32_t yoffset) {
vinfo.xoffset = xoffset;
vinfo.yoffset = yoffset;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -1,65 +0,0 @@
/**
* @file fbdev.h
*
*/
#ifndef FBDEV_H
#define FBDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_FBDEV || USE_BSD_FBDEV
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void fbdev_init(void);
void fbdev_exit(void);
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *dpi);
/**
* Set the X and Y offset in the variable framebuffer info.
* @param xoffset horizontal offset
* @param yoffset vertical offset
*/
void fbdev_set_offset(uint32_t xoffset, uint32_t yoffset);
/**********************
* MACROS
**********************/
#endif /*USE_FBDEV*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*FBDEV_H*/

View File

@ -1,57 +0,0 @@
/**
* @file monitor.h
*
*/
#ifndef MONITOR_H
#define MONITOR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_MONITOR
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void monitor_init(void);
void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_MONITOR */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* MONITOR_H */

View File

@ -1 +0,0 @@
--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent=

View File

@ -1 +0,0 @@
--convert-tabs --indent=spaces=4

View File

@ -1,97 +0,0 @@
# Add GTK under Linux in Eclipse
## Install GDK
```
sudo apt-get install libgtk-3-dev
sudo apt-get install libglib2.0-dev
```
## Add GTK include paths and libraries
In "Project properties > C/C++ Build > Settings" set the followings:
- "Cross GCC Compiler > Command line pattern"
- Add ` ${gtk+-cflags}` to the end (add a space between the last command and this)
- "Cross GCC Compiler > Includes"
- /usr/include/glib-2.0
- /usr/include/gtk-3.0
- /usr/include/pango-1.0
- /usr/include/cairo
- /usr/include/gdk-pixbuf-2.0
- /usr/include/atk-1.0
- "Cross GCC Linker > Command line pattern"
- Add ` ${gtk+-libs}` to the end (add a space between the last command and this)
- "Cross GCC Linker > Libraries"
- Add `pthread`
- In "C/C++ Build > Build variables"
- Configuration: [All Configuration]
- Add
- Variable name: `gtk+-cflags`
- Type: `String`
- Value: `pkg-config --cflags gtk+-3.0`
- Variable name: `gtk+-libs`
- Type: `String`
- Value: `pkg-config --libs gtk+-3.0`
## Init GDK in LVGL
1. In `main.c` `#include "lv_drivers/gtkdrv/gtkdrv.h"`
2. Enable the GTK driver in `lv_drv_conf.h` with `USE_GTK 1`
3. After `lv_init()` call `gdkdrv_init()`;
4. Add a display:
```c
static lv_disp_buf_t disp_buf1;
static lv_color_t buf1_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];
lv_disp_buf_init(&disp_buf1, buf1_1, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX);
/*Create a display*/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.buffer = &disp_buf1;
disp_drv.flush_cb = gtkdrv_flush_cb;
```
5. Add mouse:
```c
lv_indev_drv_t indev_drv_mouse;
lv_indev_drv_init(&indev_drv_mouse);
indev_drv_mouse.type = LV_INDEV_TYPE_POINTER;
```
6. Add keyboard:
```c
lv_indev_drv_t indev_drv_kb;
lv_indev_drv_init(&indev_drv_kb);
indev_drv_kb.type = LV_INDEV_TYPE_KEYPAD;
indev_drv_kb.read_cb = lv_keyboard_read_cb;
lv_indev_drv_register(&indev_drv_kb);
```
7. Configure tick in `lv_conf.h`
```c
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "lv_drivers/gtkdrv/gtkdrv.h" /*Header for the sys time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (gtkdrv_tick_get()) /*Expression evaluating to current systime in ms*/
#endif /*LV_TICK_CUSTOM*/
```
8. Be sure `LV_COLOR_DEPTH` is `32` in `lv_conf.h`
## Run in a window
Build and Run to "normally" run the UI in a window
## Run in browser
With the help of `Broadway` the UI can be easily shown via a browser.
1. Open Terminal and start *Broadway* with `broadwayd :5`. Leave the terminal running.
2. Navigate to where eclipse created the binary executable (my_project/Debug) and open a terminal in that folder.
In this terminal run `GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 ./my_executable` (replace *my_executable* wih name of your executable)
3. Open a web browser and go to `http://localhost:8085/`
![LVGL with GTK/GDK Broadway backend](https://github.com/lvgl/lv_drivers/blob/master/gtkdrv/broadway.png?raw=true)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,323 +0,0 @@
/**
* @file gtk.c
*
*/
/*********************
* INCLUDES
*********************/
#include "gtkdrv.h"
#if USE_GTK
#define _DEFAULT_SOURCE /* needed for usleep() */
#include <stdlib.h>
#include <unistd.h>
#include <gtk/gtk.h>
#include <gtk/gtkx.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void gtkdrv_handler(void * p);
static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event,
gpointer user_data);
static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event,
gpointer user_data);
static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
gpointer user_data);
static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event,
gpointer user_data);
static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event,
gpointer user_data);
static void quit_handler(void);
/**********************
* STATIC VARIABLES
**********************/
static GtkWidget *window;
static GtkWidget *event_box;
static GtkWidget *output_image;
static GdkPixbuf *pixbuf;
static unsigned char run_gtk;
static lv_coord_t mouse_x;
static lv_coord_t mouse_y;
static lv_indev_state_t mouse_btn = LV_INDEV_STATE_REL;
static lv_key_t last_key;
static lv_indev_state_t last_key_state;
static uint8_t fb[LV_HOR_RES_MAX * LV_VER_RES_MAX * 3];
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void gtkdrv_init(void)
{
// Init GTK
gtk_init(NULL, NULL);
/* Or just set up the widgets in code */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), LV_HOR_RES_MAX, LV_VER_RES_MAX);
gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
output_image = gtk_image_new();
event_box = gtk_event_box_new (); // Use event_box around image, otherwise mouse position output in broadway is offset
gtk_container_add(GTK_CONTAINER (event_box), output_image);
gtk_container_add(GTK_CONTAINER (window), event_box);
gtk_widget_add_events(event_box, GDK_BUTTON_PRESS_MASK);
gtk_widget_add_events(event_box, GDK_SCROLL_MASK);
gtk_widget_add_events(event_box, GDK_POINTER_MOTION_MASK);
gtk_widget_add_events(window, GDK_KEY_PRESS_MASK);
g_signal_connect(window, "destroy", G_CALLBACK(quit_handler), NULL);
g_signal_connect(event_box, "button-press-event", G_CALLBACK(mouse_pressed), NULL);
g_signal_connect(event_box, "button-release-event", G_CALLBACK(mouse_released), NULL);
g_signal_connect(event_box, "motion-notify-event", G_CALLBACK(mouse_motion), NULL);
g_signal_connect(window, "key_press_event", G_CALLBACK(keyboard_press), NULL);
g_signal_connect(window, "key_release_event", G_CALLBACK(keyboard_release), NULL);
gtk_widget_show_all(window);
pixbuf = gdk_pixbuf_new_from_data((guchar*)fb, GDK_COLORSPACE_RGB, false, 8, LV_HOR_RES_MAX, LV_VER_RES_MAX, LV_HOR_RES_MAX * 3, NULL, NULL);
if (pixbuf == NULL)
{
fprintf(stderr, "Creating pixbuf failed\n");
return;
}
pthread_t thread;
pthread_create(&thread, NULL, gtkdrv_handler, NULL);
}
/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
uint32_t gtkdrv_tick_get(void)
{
static uint64_t start_ms = 0;
if(start_ms == 0) {
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
}
struct timeval tv_now;
gettimeofday(&tv_now, NULL);
uint64_t now_ms;
now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
uint32_t time_ms = now_ms - start_ms;
return time_ms;
}
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res;
lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res;
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
int32_t y;
int32_t x;
int32_t p;
for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
p = (y * disp_drv->hor_res + area->x1) * 3;
for(x = area->x1; x <= area->x2 && x < disp_drv->hor_res; x++) {
fb[p] = color_p->ch.red;
fb[p + 1] = color_p->ch.green;
fb[p + 2] = color_p->ch.blue;
p += 3;
color_p ++;
}
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
}
void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
data->point.x = mouse_x;
data->point.y = mouse_y;
data->state = mouse_btn;
}
void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
data->key = last_key;
data->state = last_key_state;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void gtkdrv_handler(void * p)
{
while(1) {
gtk_image_set_from_pixbuf(GTK_IMAGE(output_image), pixbuf); // Test code
/* Real code should: call gdk_pixbuf_new_from_data () with pointer to frame buffer
generated by LVGL. See
https://developer.gnome.org/gdk-pixbuf/2.36/gdk-pixbuf-Image-Data-in-Memory.html
*/
gtk_main_iteration_do(FALSE);
/* Explicitly calling each iteration of the GTK main loop allows LVGL to sync frame
buffer updates with GTK. It is perhaps also possible to just call gtk_main(), but not
sure how sync will work then
*/
usleep(1*1000);
}
}
static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
mouse_btn = LV_INDEV_STATE_PR;
// Important, if this function returns TRUE the window cannot be moved around inside the browser
// when using broadway
return FALSE;
}
static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
mouse_btn = LV_INDEV_STATE_REL;
// Important, if this function returns TRUE the window cannot be moved around inside the browser
// when using broadway
return FALSE;
}
/*****************************************************************************/
static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
gpointer user_data)
{
mouse_x = event->x;
mouse_y = event->y;
// Important, if this function returns TRUE the window cannot be moved around inside the browser
// when using broadway
return FALSE;
}
static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event,
gpointer user_data)
{
uint32_t ascii_key = event->keyval;
/*Remap some key to LV_KEY_... to manage groups*/
switch(event->keyval) {
case GDK_KEY_rightarrow:
case GDK_KEY_Right:
ascii_key = LV_KEY_RIGHT;
break;
case GDK_KEY_leftarrow:
case GDK_KEY_Left:
ascii_key = LV_KEY_LEFT;
break;
case GDK_KEY_uparrow:
case GDK_KEY_Up:
ascii_key = LV_KEY_UP;
break;
case GDK_KEY_downarrow:
case GDK_KEY_Down:
ascii_key = LV_KEY_DOWN;
break;
case GDK_KEY_Escape:
ascii_key = LV_KEY_ESC;
break;
case GDK_KEY_BackSpace:
ascii_key = LV_KEY_BACKSPACE;
break;
case GDK_KEY_Delete:
ascii_key = LV_KEY_DEL;
break;
case GDK_KEY_Tab:
ascii_key = LV_KEY_NEXT;
break;
case GDK_KEY_KP_Enter:
case GDK_KEY_Return:
case '\r':
ascii_key = LV_KEY_ENTER;
break;
default:
break;
}
last_key = ascii_key;
last_key_state = LV_INDEV_STATE_PR;
// For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey
return TRUE;
}
static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event,
gpointer user_data)
{
last_key = 0;
last_key_state = LV_INDEV_STATE_REL;
// For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey
return TRUE;
}
static void quit_handler(void)
{
exit(0);
run_gtk = FALSE;
}
#endif /*USE_GTK*/

View File

@ -1,59 +0,0 @@
/**
* @file gtkdrv
*
*/
#ifndef GTKDRV_H
#define GTKDRV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_GTK
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void gtkdrv_init(void);
uint32_t gtkdrv_tick_get(void);
void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data);
void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data);
/**********************
* MACROS
**********************/
#endif /*USE_GTK*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* GTKDRV_H */

View File

@ -1,383 +0,0 @@
/**
* @file AD_touch.c
*
*/
#include "AD_touch.h"
#if USE_AD_TOUCH
#include LV_DRV_INDEV_INCLUDE
#include LV_DRV_DELAY_INCLUDE
#define SAMPLE_POINTS 4
#define CALIBRATIONINSET 20 // range 0 <= CALIBRATIONINSET <= 40
#define RESISTIVETOUCH_AUTO_SAMPLE_MODE
#define TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD 350 // between 0-0x03ff the lesser this value
// Current ADC values for X and Y channels
int16_t adcX = 0;
int16_t adcY = 0;
volatile unsigned int adcTC = 0;
// coefficient values
volatile long _trA;
volatile long _trB;
volatile long _trC;
volatile long _trD;
volatile int16_t xRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULX, TOUCHCAL_URX, TOUCHCAL_LRX, TOUCHCAL_LLX};
volatile int16_t yRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULY, TOUCHCAL_URY, TOUCHCAL_LRY, TOUCHCAL_LLY};
#define TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR 8
// use this scale factor to avoid working in floating point numbers
#define SCALE_FACTOR (1 << TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR)
typedef enum {
IDLE, //0
SET_X, //1
RUN_X, //2
GET_X, //3
RUN_CHECK_X, //4
CHECK_X, //5
SET_Y, //6
RUN_Y, //7
GET_Y, //8
CHECK_Y, //9
SET_VALUES, //10
GET_POT, //11
RUN_POT //12
} TOUCH_STATES;
volatile TOUCH_STATES state = IDLE;
#define CAL_X_INSET (((GetMaxX() + 1) * (CALIBRATIONINSET >> 1)) / 100)
#define CAL_Y_INSET (((GetMaxY() + 1) * (CALIBRATIONINSET >> 1)) / 100)
int stat;
int16_t temp_x, temp_y;
static int16_t TouchGetX(void);
static int16_t TouchGetRawX(void);
static int16_t TouchGetY(void);
static int16_t TouchGetRawY(void);
static int16_t TouchDetectPosition(void);
static void TouchCalculateCalPoints(void);
/********************************************************************/
void ad_touch_init(void)
{
// Initialize ADC for auto sampling mode
AD1CON1 = 0; // reset
AD1CON2 = 0; // AVdd, AVss, int every conversion, MUXA only
AD1CON3 = 0x1FFF; // 31 Tad auto-sample, Tad = 256*Tcy
AD1CON1 = 0x80E0; // Turn on A/D module, use auto-convert
ADPCFG_XPOS = RESISTIVETOUCH_ANALOG;
ADPCFG_YPOS = RESISTIVETOUCH_ANALOG;
AD1CSSL = 0; // No scanned inputs
state = SET_X; // set the state of the state machine to start the sampling
/*Load calibration data*/
xRawTouch[0] = TOUCHCAL_ULX;
yRawTouch[0] = TOUCHCAL_ULY;
xRawTouch[1] = TOUCHCAL_URX;
yRawTouch[1] = TOUCHCAL_URY;
xRawTouch[3] = TOUCHCAL_LLX;
yRawTouch[3] = TOUCHCAL_LLY;
xRawTouch[2] = TOUCHCAL_LRX;
yRawTouch[2] = TOUCHCAL_LRY;
TouchCalculateCalPoints();
}
/*Use this in lv_indev_drv*/
bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static int16_t last_x = 0;
static int16_t last_y = 0;
int16_t x, y;
x = TouchGetX();
y = TouchGetY();
if((x > 0) && (y > 0)) {
data->point.x = x;
data->point.y = y;
last_x = data->point.x;
last_y = data->point.y;
data->state = LV_INDEV_STATE_PR;
} else {
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_REL;
}
return false;
}
/* Call periodically (e.g. in every 1 ms) to handle reading with ADC*/
int16_t ad_touch_handler(void)
{
static int16_t tempX, tempY;
int16_t temp;
switch(state) {
case IDLE:
adcX = 0;
adcY = 0;
break;
case SET_VALUES:
if(!TOUCH_ADC_DONE)
break;
if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) {
adcX = 0;
adcY = 0;
} else {
adcX = tempX;
adcY = tempY;
}
state = SET_X;
return 1; // touch screen acquisition is done
case SET_X:
TOUCH_ADC_INPUT_SEL = ADC_XPOS;
ResistiveTouchScreen_XPlus_Config_As_Input();
ResistiveTouchScreen_YPlus_Config_As_Input();
ResistiveTouchScreen_XMinus_Config_As_Input();
ResistiveTouchScreen_YMinus_Drive_Low();
ResistiveTouchScreen_YMinus_Config_As_Output();
ADPCFG_YPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin
ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; // set to analog pin
TOUCH_ADC_START = 1; // run conversion
state = CHECK_X;
break;
case CHECK_X:
case CHECK_Y:
if(TOUCH_ADC_DONE == 0) {
break;
}
if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD > (WORD)ADC1BUF0) {
if(state == CHECK_X) {
ResistiveTouchScreen_YPlus_Drive_High();
ResistiveTouchScreen_YPlus_Config_As_Output();
tempX = 0;
state = RUN_X;
} else {
ResistiveTouchScreen_XPlus_Drive_High();
ResistiveTouchScreen_XPlus_Config_As_Output();
tempY = 0;
state = RUN_Y;
}
} else {
adcX = 0;
adcY = 0;
state = SET_X;
return 1; // touch screen acquisition is done
break;
}
case RUN_X:
case RUN_Y:
TOUCH_ADC_START = 1;
state = (state == RUN_X) ? GET_X : GET_Y;
// no break needed here since the next state is either GET_X or GET_Y
break;
case GET_X:
case GET_Y:
if(!TOUCH_ADC_DONE)
break;
temp = ADC1BUF0;
if(state == GET_X) {
if(temp != tempX) {
tempX = temp;
state = RUN_X;
break;
}
} else {
if(temp != tempY) {
tempY = temp;
state = RUN_Y;
break;
}
}
if(state == GET_X)
ResistiveTouchScreen_YPlus_Config_As_Input();
else
ResistiveTouchScreen_XPlus_Config_As_Input();
TOUCH_ADC_START = 1;
state = (state == GET_X) ? SET_Y : SET_VALUES;
break;
case SET_Y:
if(!TOUCH_ADC_DONE)
break;
if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) {
adcX = 0;
adcY = 0;
state = SET_X;
return 1; // touch screen acquisition is done
break;
}
TOUCH_ADC_INPUT_SEL = ADC_YPOS;
ResistiveTouchScreen_XPlus_Config_As_Input();
ResistiveTouchScreen_YPlus_Config_As_Input();
ResistiveTouchScreen_XMinus_Drive_Low();
ResistiveTouchScreen_XMinus_Config_As_Output();
ResistiveTouchScreen_YMinus_Config_As_Input();
ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; // set to analog pin
ADPCFG_XPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin
TOUCH_ADC_START = 1; // run conversion
state = CHECK_Y;
break;
default:
state = SET_X;
return 1; // touch screen acquisition is done
}
stat = state;
temp_x = adcX;
temp_y = adcY;
return 0; // touch screen acquisition is not done
}
/**********************
* STATIC FUNCTIONS
**********************/
/********************************************************************/
static int16_t TouchGetX(void)
{
long result;
result = TouchGetRawX();
if(result > 0) {
result = (long)((((long)_trC * result) + _trD) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR);
}
return ((int16_t)result);
}
/********************************************************************/
static int16_t TouchGetRawX(void)
{
#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY
return adcY;
#else
return adcX;
#endif
}
/********************************************************************/
static int16_t TouchGetY(void)
{
long result;
result = TouchGetRawY();
if(result > 0) {
result = (long)((((long)_trA * result) + (long)_trB) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR);
}
return ((int16_t)result);
}
/********************************************************************/
static int16_t TouchGetRawY(void)
{
#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY
return adcX;
#else
return adcY;
#endif
}
static void TouchCalculateCalPoints(void)
{
long trA, trB, trC, trD; // variables for the coefficients
long trAhold, trBhold, trChold, trDhold;
long test1, test2; // temp variables (must be signed type)
int16_t xPoint[SAMPLE_POINTS], yPoint[SAMPLE_POINTS];
yPoint[0] = yPoint[1] = CAL_Y_INSET;
yPoint[2] = yPoint[3] = (GetMaxY() - CAL_Y_INSET);
xPoint[0] = xPoint[3] = CAL_X_INSET;
xPoint[1] = xPoint[2] = (GetMaxX() - CAL_X_INSET);
// calculate points transfer functiona
// based on two simultaneous equations solve for the
// constants
// use sample points 1 and 4
// Dy1 = aTy1 + b; Dy4 = aTy4 + b
// Dx1 = cTx1 + d; Dy4 = aTy4 + b
test1 = (long)yPoint[0] - (long)yPoint[3];
test2 = (long)yRawTouch[0] - (long)yRawTouch[3];
trA = ((long)((long)test1 * SCALE_FACTOR) / test2);
trB = ((long)((long)yPoint[0] * SCALE_FACTOR) - (trA * (long)yRawTouch[0]));
test1 = (long)xPoint[0] - (long)xPoint[2];
test2 = (long)xRawTouch[0] - (long)xRawTouch[2];
trC = ((long)((long)test1 * SCALE_FACTOR) / test2);
trD = ((long)((long)xPoint[0] * SCALE_FACTOR) - (trC * (long)xRawTouch[0]));
trAhold = trA;
trBhold = trB;
trChold = trC;
trDhold = trD;
// use sample points 2 and 3
// Dy2 = aTy2 + b; Dy3 = aTy3 + b
// Dx2 = cTx2 + d; Dy3 = aTy3 + b
test1 = (long)yPoint[1] - (long)yPoint[2];
test2 = (long)yRawTouch[1] - (long)yRawTouch[2];
trA = ((long)(test1 * SCALE_FACTOR) / test2);
trB = ((long)((long)yPoint[1] * SCALE_FACTOR) - (trA * (long)yRawTouch[1]));
test1 = (long)xPoint[1] - (long)xPoint[3];
test2 = (long)xRawTouch[1] - (long)xRawTouch[3];
trC = ((long)((long)test1 * SCALE_FACTOR) / test2);
trD = ((long)((long)xPoint[1] * SCALE_FACTOR) - (trC * (long)xRawTouch[1]));
// get the average and use the average
_trA = (trA + trAhold) >> 1;
_trB = (trB + trBhold) >> 1;
_trC = (trC + trChold) >> 1;
_trD = (trD + trDhold) >> 1;
}
#endif

View File

@ -1,120 +0,0 @@
/**
* @file AD_touch.h
*
*/
#ifndef AD_TOUCH_H
#define AD_TOUCH_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_AD_TOUCH
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#define _SUPPRESS_PLIB_WARNING
#include <plib.h>
#include "GenericTypeDefs.h"
#define DISP_ORIENTATION 0
#define DISP_HOR_RESOLUTION 320
#define DISP_VER_RESOLUTION 240
/*GetMaxX Macro*/
#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
#define GetMaxX() (DISP_VER_RESOLUTION - 1)
#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
#define GetMaxX() (DISP_HOR_RESOLUTION - 1)
#endif
/*GetMaxY Macro*/
#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
#define GetMaxY() (DISP_HOR_RESOLUTION - 1)
#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
#define GetMaxY() (DISP_VER_RESOLUTION - 1)
#endif
/*********************************************************************
* HARDWARE PROFILE FOR THE RESISTIVE TOUCHSCREEN
*********************************************************************/
#define TOUCH_ADC_INPUT_SEL AD1CHS
// ADC Sample Start
#define TOUCH_ADC_START AD1CON1bits.SAMP
// ADC Status
#define TOUCH_ADC_DONE AD1CON1bits.DONE
#define RESISTIVETOUCH_ANALOG 1
#define RESISTIVETOUCH_DIGITAL 0
// ADC channel constants
#define ADC_XPOS ADC_CH0_POS_SAMPLEA_AN12
#define ADC_YPOS ADC_CH0_POS_SAMPLEA_AN13
// ADC Port Control Bits
#define ADPCFG_XPOS AD1PCFGbits.PCFG12 //XR
#define ADPCFG_YPOS AD1PCFGbits.PCFG13 //YD
// X port definitions
#define ResistiveTouchScreen_XPlus_Drive_High() LATBbits.LATB12 = 1
#define ResistiveTouchScreen_XPlus_Drive_Low() LATBbits.LATB12 = 0 //LAT_XPOS
#define ResistiveTouchScreen_XPlus_Config_As_Input() TRISBbits.TRISB12 = 1 //TRIS_XPOS
#define ResistiveTouchScreen_XPlus_Config_As_Output() TRISBbits.TRISB12 = 0
#define ResistiveTouchScreen_XMinus_Drive_High() LATFbits.LATF0 = 1
#define ResistiveTouchScreen_XMinus_Drive_Low() LATFbits.LATF0 = 0 //LAT_XNEG
#define ResistiveTouchScreen_XMinus_Config_As_Input() TRISFbits.TRISF0 = 1 //TRIS_XNEG
#define ResistiveTouchScreen_XMinus_Config_As_Output() TRISFbits.TRISF0 = 0
// Y port definitions
#define ResistiveTouchScreen_YPlus_Drive_High() LATBbits.LATB13 = 1
#define ResistiveTouchScreen_YPlus_Drive_Low() LATBbits.LATB13 = 0 //LAT_YPOS
#define ResistiveTouchScreen_YPlus_Config_As_Input() TRISBbits.TRISB13 = 1 //TRIS_YPOS
#define ResistiveTouchScreen_YPlus_Config_As_Output() TRISBbits.TRISB13 = 0
#define ResistiveTouchScreen_YMinus_Drive_High() LATFbits.LATF1 = 1
#define ResistiveTouchScreen_YMinus_Drive_Low() LATFbits.LATF1 = 0 //LAT_YNEG
#define ResistiveTouchScreen_YMinus_Config_As_Input() TRISFbits.TRISF1 = 1 //TRIS_YNEG
#define ResistiveTouchScreen_YMinus_Config_As_Output() TRISFbits.TRISF1 = 0
// Default calibration points
#define TOUCHCAL_ULX 0x0348
#define TOUCHCAL_ULY 0x00CC
#define TOUCHCAL_URX 0x00D2
#define TOUCHCAL_URY 0x00CE
#define TOUCHCAL_LLX 0x034D
#define TOUCHCAL_LLY 0x0335
#define TOUCHCAL_LRX 0x00D6
#define TOUCHCAL_LRY 0x032D
void ad_touch_init(void);
bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
int16_t ad_touch_handler(void);
#endif /* USE_AD_TOUCH */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AD_TOUCH_H */

View File

@ -1,179 +0,0 @@
/**
* @file FT5406EE8.c
*
*/
/*********************
* INCLUDES
*********************/
#include "FT5406EE8.h"
#if USE_FT5406EE8
#include <stddef.h>
#include <stdbool.h>
#include LV_DRV_INDEV_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define I2C_WR_BIT 0x00
#define I2C_RD_BIT 0x01
/*DEVICE MODES*/
#define OPERAT_MD 0x00
#define TEST_MD 0x04
#define SYS_INF_MD 0x01
/*OPERATING MODE*/
#define DEVICE_MODE 0x00
#define GEST_ID 0x01
#define TD_STATUS 0x02
#define FT5406EE8_FINGER_MAX 10
/*Register addresses*/
#define FT5406EE8_REG_DEVICE_MODE 0x00
#define FT5406EE8_REG_GEST_ID 0x01
#define FT5406EE8_REG_TD_STATUS 0x02
#define FT5406EE8_REG_YH 0x03
#define FT5406EE8_REG_YL 0x04
#define FT5406EE8_REG_XH 0x05
#define FT5406EE8_REG_XL 0x06
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static bool ft5406ee8_get_touch_num(void);
static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
*
*/
void ft5406ee8_init(void)
{
}
/**
* Get the current position and state of the touchpad
* @param data store the read data here
* @return false: because no ore data to be read
*/
bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static int16_t x_last;
static int16_t y_last;
int16_t x;
int16_t y;
bool valid = true;
valid = ft5406ee8_get_touch_num();
if(valid == true) {
valid = ft5406ee8_read_finger1(&x, &y);
}
if(valid == true) {
x = (uint32_t)((uint32_t)x * 320) / 2048;
y = (uint32_t)((uint32_t)y * 240) / 2048;
x_last = x;
y_last = y;
} else {
x = x_last;
y = y_last;
}
data->point.x = x;
data->point.y = y;
data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
return false;
}
/**********************
* STATIC FUNCTIONS
**********************/
static bool ft5406ee8_get_touch_num(void)
{
bool ok = true;
uint8_t t_num = 0;
LV_DRV_INDEV_I2C_START;
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT);
LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_TD_STATUS)
LV_DRV_INDEV_I2C_RESTART;
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT);
t_num = LV_DRV_INDEV_I2C_READ(0);
/* Error if not touched or too much finger */
if(t_num > FT5406EE8_FINGER_MAX || t_num == 0) {
ok = false;
}
return ok;
}
/**
* Read the x and y coordinated
* @param x store the x coordinate here
* @param y store the y coordinate here
* @return false: not valid point; true: valid point
*/
static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y)
{
uint8_t temp_xH = 0;
uint8_t temp_xL = 0;
uint8_t temp_yH = 0;
uint8_t temp_yL = 0;
/*Read Y High and low byte*/
LV_DRV_INDEV_I2C_START;
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT);
LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_YH)
LV_DRV_INDEV_I2C_RESTART;
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT);
temp_yH = LV_DRV_INDEV_I2C_READ(1);
temp_yL = LV_DRV_INDEV_I2C_READ(1);
/*The upper two bit must be 2 on valid press*/
if(((temp_yH >> 6) & 0xFF) != 2) {
(void) LV_DRV_INDEV_I2C_READ(0); /*Dummy read to close read sequence*/
*x = 0;
*y = 0;
return false;
}
/*Read X High and low byte*/
temp_xH = LV_DRV_INDEV_I2C_READ(1);
temp_xL = LV_DRV_INDEV_I2C_READ(0);
/*Save the result*/
*x = (temp_xH & 0x0F) << 8;
*x += temp_xL;
*y = (temp_yH & 0x0F) << 8;
*y += temp_yL;
return true;
}
#endif

View File

@ -1,56 +0,0 @@
/**
* @file FT5406EE8.h
*
*/
#ifndef FT5406EE8_H
#define FT5406EE8_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_FT5406EE8
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void ft5406ee8_init(void);
bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**********************
* MACROS
**********************/
#endif /* USE_FT5406EE8 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* FT5406EE8_H */

View File

@ -1,174 +0,0 @@
/**
* @file XPT2046.c
*
*/
/*********************
* INCLUDES
*********************/
#include "XPT2046.h"
#if USE_XPT2046
#include <stddef.h>
#include LV_DRV_INDEV_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define CMD_X_READ 0b10010000
#define CMD_Y_READ 0b11010000
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void xpt2046_corr(int16_t * x, int16_t * y);
static void xpt2046_avg(int16_t * x, int16_t * y);
/**********************
* STATIC VARIABLES
**********************/
int16_t avg_buf_x[XPT2046_AVG];
int16_t avg_buf_y[XPT2046_AVG];
uint8_t avg_last;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the XPT2046
*/
void xpt2046_init(void)
{
}
/**
* Get the current position and state of the touchpad
* @param data store the read data here
* @return false: because no ore data to be read
*/
bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static int16_t last_x = 0;
static int16_t last_y = 0;
uint8_t buf;
int16_t x = 0;
int16_t y = 0;
uint8_t irq = LV_DRV_INDEV_IRQ_READ;
if(irq == 0) {
LV_DRV_INDEV_SPI_CS(0);
LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_X_READ); /*Start x read*/
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read x MSB*/
x = buf << 8;
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_Y_READ); /*Until x LSB converted y command can be sent*/
x += buf;
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y MSB*/
y = buf << 8;
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y LSB*/
y += buf;
/*Normalize Data*/
x = x >> 3;
y = y >> 3;
xpt2046_corr(&x, &y);
xpt2046_avg(&x, &y);
last_x = x;
last_y = y;
data->state = LV_INDEV_STATE_PR;
LV_DRV_INDEV_SPI_CS(1);
} else {
x = last_x;
y = last_y;
avg_last = 0;
data->state = LV_INDEV_STATE_REL;
}
data->point.x = x;
data->point.y = y;
return false;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void xpt2046_corr(int16_t * x, int16_t * y)
{
#if XPT2046_XY_SWAP != 0
int16_t swap_tmp;
swap_tmp = *x;
*x = *y;
*y = swap_tmp;
#endif
if((*x) > XPT2046_X_MIN)(*x) -= XPT2046_X_MIN;
else(*x) = 0;
if((*y) > XPT2046_Y_MIN)(*y) -= XPT2046_Y_MIN;
else(*y) = 0;
(*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) /
(XPT2046_X_MAX - XPT2046_X_MIN);
(*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) /
(XPT2046_Y_MAX - XPT2046_Y_MIN);
#if XPT2046_X_INV != 0
(*x) = XPT2046_HOR_RES - (*x);
#endif
#if XPT2046_Y_INV != 0
(*y) = XPT2046_VER_RES - (*y);
#endif
}
static void xpt2046_avg(int16_t * x, int16_t * y)
{
/*Shift out the oldest data*/
uint8_t i;
for(i = XPT2046_AVG - 1; i > 0 ; i--) {
avg_buf_x[i] = avg_buf_x[i - 1];
avg_buf_y[i] = avg_buf_y[i - 1];
}
/*Insert the new point*/
avg_buf_x[0] = *x;
avg_buf_y[0] = *y;
if(avg_last < XPT2046_AVG) avg_last++;
/*Sum the x and y coordinates*/
int32_t x_sum = 0;
int32_t y_sum = 0;
for(i = 0; i < avg_last ; i++) {
x_sum += avg_buf_x[i];
y_sum += avg_buf_y[i];
}
/*Normalize the sums*/
(*x) = (int32_t)x_sum / avg_last;
(*y) = (int32_t)y_sum / avg_last;
}
#endif

View File

@ -1,56 +0,0 @@
/**
* @file XPT2046.h
*
*/
#ifndef XPT2046_H
#define XPT2046_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_XPT2046
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void xpt2046_init(void);
bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**********************
* MACROS
**********************/
#endif /* USE_XPT2046 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* XPT2046_H */

View File

@ -1,251 +0,0 @@
/**
* @file evdev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "evdev.h"
#if USE_EVDEV != 0 || USE_BSD_EVDEV
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#if USE_BSD_EVDEV
#include <dev/evdev/input.h>
#else
#include <linux/input.h>
#endif
#if USE_XKB
#include "xkb.h"
#endif /* USE_XKB */
/*********************
* 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 = -1;
int evdev_root_x;
int evdev_root_y;
int evdev_button;
int evdev_key_val;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the evdev interface
*/
void evdev_init(void)
{
if (!evdev_set_file(EVDEV_NAME)) {
return;
}
#if USE_XKB
xkb_init();
#endif
}
/**
* 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 to 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
*/
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) {
#if USE_XKB
data->key = xkb_process_key(in.code, in.value != 0);
#else
switch(in.code) {
case KEY_BACKSPACE:
data->key = LV_KEY_BACKSPACE;
break;
case KEY_ENTER:
data->key = LV_KEY_ENTER;
break;
case KEY_PREVIOUS:
data->key = LV_KEY_PREV;
break;
case KEY_NEXT:
data->key = LV_KEY_NEXT;
break;
case KEY_UP:
data->key = LV_KEY_UP;
break;
case KEY_LEFT:
data->key = LV_KEY_LEFT;
break;
case KEY_RIGHT:
data->key = LV_KEY_RIGHT;
break;
case KEY_DOWN:
data->key = LV_KEY_DOWN;
break;
case KEY_TAB:
data->key = LV_KEY_NEXT;
break;
default:
data->key = 0;
break;
}
#endif /* USE_XKB */
if (data->key != 0) {
/* Only record button state when actual output is produced to prevent widgets from refreshing */
data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
}
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(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

View File

@ -1,72 +0,0 @@
/**
* @file evdev.h
*
*/
#ifndef EVDEV_H
#define EVDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_EVDEV || USE_BSD_EVDEV
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the evdev
*/
void evdev_init(void);
/**
* 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
*/
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 */

View File

@ -1,81 +0,0 @@
/**
* @file keyboard.h
*
*/
#ifndef KEYBOARD_H
#define KEYBOARD_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_KEYBOARD
#warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c"
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if USE_SDL_GPU
#include "../sdl/sdl_gpu.h"
#else
#include "../sdl/sdl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the keyboard
*/
static inline void keyboard_init(void)
{
/*Nothing to do*/
}
/**
* Get the last pressed or released character from the PC's keyboard
* @param indev_drv pointer to the related input device driver
* @param data store the read data here
*/
static inline void keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
sdl_keyboard_read(indev_drv, data);
}
/**********************
* MACROS
**********************/
#endif /*USE_KEYBOARD*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*KEYBOARD_H*/

View File

@ -1,501 +0,0 @@
/**
* @file libinput.c
*
*/
/*********************
* INCLUDES
*********************/
#include "libinput_drv.h"
#if USE_LIBINPUT || USE_BSD_LIBINPUT
#include <stdio.h>
#include <unistd.h>
#include <linux/limits.h>
#include <fcntl.h>
#include <errno.h>
#include <stdbool.h>
#include <dirent.h>
#include <libinput.h>
#if USE_BSD_LIBINPUT
#include <dev/evdev/input.h>
#else
#include <linux/input.h>
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct input_device {
libinput_capability capabilities;
char *path;
};
/**********************
* STATIC PROTOTYPES
**********************/
static bool rescan_devices(void);
static bool add_scanned_device(char *path, libinput_capability capabilities);
static void reset_scanned_devices(void);
static void read_pointer(libinput_drv_state_t *state, struct libinput_event *event);
static void read_keypad(libinput_drv_state_t *state, struct libinput_event *event);
static int open_restricted(const char *path, int flags, void *user_data);
static void close_restricted(int fd, void *user_data);
/**********************
* STATIC VARIABLES
**********************/
static struct input_device *devices = NULL;
static size_t num_devices = 0;
static libinput_drv_state_t default_state = { .most_recent_touch_point = { .x = 0, .y = 0 } };
static const int timeout = 0; // do not block
static const nfds_t nfds = 1;
static const struct libinput_interface interface = {
.open_restricted = open_restricted,
.close_restricted = close_restricted,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* find connected input device with specific capabilities
* @param capabilities required device capabilities
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
* @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found.
* The pointer is safe to use until the next forceful device search.
*/
char *libinput_find_dev(libinput_capability capabilities, bool force_rescan) {
char *path = NULL;
libinput_find_devs(capabilities, &path, 1, force_rescan);
return path;
}
/**
* find connected input devices with specific capabilities
* @param capabilities required device capabilities
* @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are
* safe to use until the next forceful device search.
* @param count maximum number of devices to find (the devices array should be at least this long)
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
* @return number of devices that were found
*/
size_t libinput_find_devs(libinput_capability capabilities, char **found, size_t count, bool force_rescan) {
if ((!devices || force_rescan) && !rescan_devices()) {
return 0;
}
size_t num_found = 0;
for (size_t i = 0; i < num_devices && num_found < count; ++i) {
if (devices[i].capabilities & capabilities) {
found[num_found] = devices[i].path;
num_found++;
}
}
return num_found;
}
/**
* Reconfigure the device file for libinput using the default driver state. Use this function if you only want
* to connect a single device.
* @param dev_name input device node path (e.g. /dev/input/event0)
* @return true: the device file set complete
* false: the device file doesn't exist current system
*/
bool libinput_set_file(char* dev_name)
{
return libinput_set_file_state(&default_state, dev_name);
}
/**
* Reconfigure the device file for libinput using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state the driver state to configure
* @param dev_name input device node path (e.g. /dev/input/event0)
* @return true: the device file set complete
* false: the device file doesn't exist current system
*/
bool libinput_set_file_state(libinput_drv_state_t *state, char* dev_name)
{
// This check *should* not be necessary, yet applications crashes even on NULL handles.
// citing libinput.h:libinput_path_remove_device:
// > If no matching device exists, this function does nothing.
if (state->libinput_device) {
state->libinput_device = libinput_device_unref(state->libinput_device);
libinput_path_remove_device(state->libinput_device);
}
state->libinput_device = libinput_path_add_device(state->libinput_context, dev_name);
if(!state->libinput_device) {
perror("unable to add device to libinput context:");
return false;
}
state->libinput_device = libinput_device_ref(state->libinput_device);
if(!state->libinput_device) {
perror("unable to reference device within libinput context:");
return false;
}
state->button = LV_INDEV_STATE_REL;
state->key_val = 0;
return true;
}
/**
* Prepare for reading input via libinput using the default driver state. Use this function if you only want
* to connect a single device.
*/
void libinput_init(void)
{
libinput_init_state(&default_state, LIBINPUT_NAME);
}
/**
* Prepare for reading input via libinput using the a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state driver state to initialize
* @param path input device node path (e.g. /dev/input/event0)
*/
void libinput_init_state(libinput_drv_state_t *state, char* path)
{
state->libinput_device = NULL;
state->libinput_context = libinput_path_create_context(&interface, NULL);
if(path == NULL || !libinput_set_file_state(state, path)) {
fprintf(stderr, "unable to add device \"%s\" to libinput context: %s\n", path ? path : "NULL", strerror(errno));
return;
}
state->fd = libinput_get_fd(state->libinput_context);
/* prepare poll */
state->fds[0].fd = state->fd;
state->fds[0].events = POLLIN;
state->fds[0].revents = 0;
#if USE_XKB
xkb_init_state(&(state->xkb_state));
#endif
}
/**
* Read available input events via libinput using the default driver state. Use this function if you only want
* to connect a single device.
* @param indev_drv driver object itself
* @param data store the libinput data here
*/
void libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
libinput_read_state(&default_state, indev_drv, data);
}
/**
* Read available input events via libinput using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state the driver state to use
* @param indev_drv driver object itself
* @param data store the libinput data here
*/
void libinput_read_state(libinput_drv_state_t * state, lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
struct libinput_event *event;
int rc = 0;
rc = poll(state->fds, nfds, timeout);
switch (rc){
case -1:
perror(NULL);
case 0:
goto report_most_recent_state;
default:
break;
}
libinput_dispatch(state->libinput_context);
while((event = libinput_get_event(state->libinput_context)) != NULL) {
switch (indev_drv->type) {
case LV_INDEV_TYPE_POINTER:
read_pointer(state, event);
break;
case LV_INDEV_TYPE_KEYPAD:
read_keypad(state, event);
break;
default:
break;
}
libinput_event_destroy(event);
}
report_most_recent_state:
data->point.x = state->most_recent_touch_point.x;
data->point.y = state->most_recent_touch_point.y;
data->state = state->button;
data->key = state->key_val;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* rescan all attached evdev devices and store capable ones into the static devices array for quick later filtering
* @return true if the operation succeeded
*/
static bool rescan_devices(void) {
reset_scanned_devices();
DIR *dir;
struct dirent *ent;
if (!(dir = opendir("/dev/input"))) {
perror("unable to open directory /dev/input");
return false;
}
struct libinput *context = libinput_path_create_context(&interface, NULL);
while ((ent = readdir(dir))) {
if (strncmp(ent->d_name, "event", 5) != 0) {
continue;
}
/* 11 characters for /dev/input/ + length of name + 1 NUL terminator */
char *path = malloc((11 + strlen(ent->d_name) + 1) * sizeof(char));
if (!path) {
perror("could not allocate memory for device node path");
libinput_unref(context);
reset_scanned_devices();
return false;
}
strcpy(path, "/dev/input/");
strcat(path, ent->d_name);
struct libinput_device *device = libinput_path_add_device(context, path);
if(!device) {
perror("unable to add device to libinput context");
free(path);
continue;
}
/* The device pointer is guaranteed to be valid until the next libinput_dispatch. Since we're not dispatching events
* as part of this function, we don't have to increase its reference count to keep it alive.
* https://wayland.freedesktop.org/libinput/doc/latest/api/group__base.html#gaa797496f0150b482a4e01376bd33a47b */
libinput_capability capabilities = LIBINPUT_CAPABILITY_NONE;
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)
&& (libinput_device_keyboard_has_key(device, KEY_ENTER) || libinput_device_keyboard_has_key(device, KEY_KPENTER)))
{
capabilities |= LIBINPUT_CAPABILITY_KEYBOARD;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
capabilities |= LIBINPUT_CAPABILITY_POINTER;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) {
capabilities |= LIBINPUT_CAPABILITY_TOUCH;
}
libinput_path_remove_device(device);
if (capabilities == LIBINPUT_CAPABILITY_NONE) {
free(path);
continue;
}
if (!add_scanned_device(path, capabilities)) {
free(path);
libinput_unref(context);
reset_scanned_devices();
return false;
}
}
libinput_unref(context);
return true;
}
/**
* add a new scanned device to the static devices array, growing its size when necessary
* @param path device file path
* @param capabilities device input capabilities
* @return true if the operation succeeded
*/
static bool add_scanned_device(char *path, libinput_capability capabilities) {
/* Double array size every 2^n elements */
if ((num_devices & (num_devices + 1)) == 0) {
struct input_device *tmp = realloc(devices, (2 * num_devices + 1) * sizeof(struct input_device));
if (!tmp) {
perror("could not reallocate memory for devices array");
return false;
}
devices = tmp;
}
devices[num_devices].path = path;
devices[num_devices].capabilities = capabilities;
num_devices++;
return true;
}
/**
* reset the array of scanned devices and free any dynamically allocated memory
*/
static void reset_scanned_devices(void) {
if (!devices) {
return;
}
for (size_t i = 0; i < num_devices; ++i) {
free(devices[i].path);
}
free(devices);
devices = NULL;
num_devices = 0;
}
/**
* Handle libinput touch / pointer events
* @param state driver state to use
* @param event libinput event
*/
static void read_pointer(libinput_drv_state_t *state, struct libinput_event *event) {
struct libinput_event_touch *touch_event = NULL;
struct libinput_event_pointer *pointer_event = NULL;
enum libinput_event_type type = libinput_event_get_type(event);
/* We need to read unrotated display dimensions directly from the driver because libinput won't account
* for any rotation inside of LVGL */
lv_disp_drv_t *drv = lv_disp_get_default()->driver;
switch (type) {
case LIBINPUT_EVENT_TOUCH_MOTION:
case LIBINPUT_EVENT_TOUCH_DOWN:
touch_event = libinput_event_get_touch_event(event);
lv_coord_t x_touch = libinput_event_touch_get_x_transformed(touch_event, drv->physical_hor_res > 0 ? drv->physical_hor_res : drv->hor_res) - drv->offset_x;
lv_coord_t y_touch = libinput_event_touch_get_y_transformed(touch_event, drv->physical_ver_res > 0 ? drv->physical_ver_res : drv->ver_res) - drv->offset_y;
if (x_touch < 0 || x_touch > drv->hor_res || y_touch < 0 || y_touch > drv->ver_res) {
break; /* ignore touches that are out of bounds */
}
state->most_recent_touch_point.x = x_touch;
state->most_recent_touch_point.y = y_touch;
state->button = LV_INDEV_STATE_PR;
break;
case LIBINPUT_EVENT_TOUCH_UP:
state->button = LV_INDEV_STATE_REL;
break;
case LIBINPUT_EVENT_POINTER_MOTION:
pointer_event = libinput_event_get_pointer_event(event);
state->most_recent_touch_point.x += libinput_event_pointer_get_dx(pointer_event);
state->most_recent_touch_point.y += libinput_event_pointer_get_dy(pointer_event);
state->most_recent_touch_point.x = LV_CLAMP(0, state->most_recent_touch_point.x, drv->hor_res - 1);
state->most_recent_touch_point.y = LV_CLAMP(0, state->most_recent_touch_point.y, drv->ver_res - 1);
break;
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
pointer_event = libinput_event_get_pointer_event(event);
lv_coord_t x_pointer = libinput_event_pointer_get_absolute_x_transformed(pointer_event, drv->physical_hor_res > 0 ? drv->physical_hor_res : drv->hor_res) - drv->offset_x;
lv_coord_t y_pointer = libinput_event_pointer_get_absolute_y_transformed(pointer_event, drv->physical_ver_res > 0 ? drv->physical_ver_res : drv->ver_res) - drv->offset_y;
if (x_pointer < 0 || x_pointer > drv->hor_res || y_pointer < 0 || y_pointer > drv->ver_res) {
break; /* ignore pointer events that are out of bounds */
}
state->most_recent_touch_point.x = x_pointer;
state->most_recent_touch_point.y = y_pointer;
break;
case LIBINPUT_EVENT_POINTER_BUTTON:
pointer_event = libinput_event_get_pointer_event(event);
enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event);
state->button = button_state == LIBINPUT_BUTTON_STATE_RELEASED ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
break;
default:
break;
}
}
/**
* Handle libinput keyboard events
* @param state driver state to use
* @param event libinput event
*/
static void read_keypad(libinput_drv_state_t *state, struct libinput_event *event) {
struct libinput_event_keyboard *keyboard_event = NULL;
enum libinput_event_type type = libinput_event_get_type(event);
switch (type) {
case LIBINPUT_EVENT_KEYBOARD_KEY:
keyboard_event = libinput_event_get_keyboard_event(event);
enum libinput_key_state key_state = libinput_event_keyboard_get_key_state(keyboard_event);
uint32_t code = libinput_event_keyboard_get_key(keyboard_event);
#if USE_XKB
state->key_val = xkb_process_key_state(&(state->xkb_state), code, key_state == LIBINPUT_KEY_STATE_PRESSED);
#else
switch(code) {
case KEY_BACKSPACE:
state->key_val = LV_KEY_BACKSPACE;
break;
case KEY_ENTER:
state->key_val = LV_KEY_ENTER;
break;
case KEY_PREVIOUS:
state->key_val = LV_KEY_PREV;
break;
case KEY_NEXT:
state->key_val = LV_KEY_NEXT;
break;
case KEY_UP:
state->key_val = LV_KEY_UP;
break;
case KEY_LEFT:
state->key_val = LV_KEY_LEFT;
break;
case KEY_RIGHT:
state->key_val = LV_KEY_RIGHT;
break;
case KEY_DOWN:
state->key_val = LV_KEY_DOWN;
break;
case KEY_TAB:
state->key_val = LV_KEY_NEXT;
break;
default:
state->key_val = 0;
break;
}
#endif /* USE_XKB */
if (state->key_val != 0) {
/* Only record button state when actual output is produced to prevent widgets from refreshing */
state->button = (key_state == LIBINPUT_KEY_STATE_RELEASED) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
}
break;
default:
break;
}
}
static int open_restricted(const char *path, int flags, void *user_data)
{
LV_UNUSED(user_data);
int fd = open(path, flags);
return fd < 0 ? -errno : fd;
}
static void close_restricted(int fd, void *user_data)
{
LV_UNUSED(user_data);
close(fd);
}
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */

View File

@ -1,145 +0,0 @@
/**
* @file libinput.h
*
*/
#ifndef LVGL_LIBINPUT_H
#define LVGL_LIBINPUT_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_LIBINPUT || USE_BSD_LIBINPUT
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#include <poll.h>
#if USE_XKB
#include "xkb.h"
#endif /* USE_XKB */
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef enum {
LIBINPUT_CAPABILITY_NONE = 0,
LIBINPUT_CAPABILITY_KEYBOARD = 1U << 0,
LIBINPUT_CAPABILITY_POINTER = 1U << 1,
LIBINPUT_CAPABILITY_TOUCH = 1U << 2
} libinput_capability;
typedef struct {
int fd;
struct pollfd fds[1];
int button;
int key_val;
lv_point_t most_recent_touch_point;
struct libinput *libinput_context;
struct libinput_device *libinput_device;
#if USE_XKB
xkb_drv_state_t xkb_state;
#endif /* USE_XKB */
} libinput_drv_state_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* find connected input device with specific capabilities
* @param capabilities required device capabilities
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
* @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found.
* The pointer is safe to use until the next forceful device search.
*/
char *libinput_find_dev(libinput_capability capabilities, bool force_rescan);
/**
* find connected input devices with specific capabilities
* @param capabilities required device capabilities
* @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are
* safe to use until the next forceful device search.
* @param count maximum number of devices to find (the devices array should be at least this long)
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
* @return number of devices that were found
*/
size_t libinput_find_devs(libinput_capability capabilities, char **found, size_t count, bool force_rescan);
/**
* Prepare for reading input via libinput using the default driver state. Use this function if you only want
* to connect a single device.
*/
void libinput_init(void);
/**
* Prepare for reading input via libinput using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state driver state to initialize
* @param path input device node path (e.g. /dev/input/event0)
*/
void libinput_init_state(libinput_drv_state_t *state, char* path);
/**
* Reconfigure the device file for libinput using the default driver state. Use this function if you only want
* to connect a single device.
* @param dev_name input device node path (e.g. /dev/input/event0)
* @return true: the device file set complete
* false: the device file doesn't exist current system
*/
bool libinput_set_file(char* dev_name);
/**
* Reconfigure the device file for libinput using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state the driver state to configure
* @param dev_name input device node path (e.g. /dev/input/event0)
* @return true: the device file set complete
* false: the device file doesn't exist current system
*/
bool libinput_set_file_state(libinput_drv_state_t *state, char* dev_name);
/**
* Read available input events via libinput using the default driver state. Use this function if you only want
* to connect a single device.
* @param indev_drv driver object itself
* @param data store the libinput data here
*/
void libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Read available input events via libinput using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state the driver state to use
* @param indev_drv driver object itself
* @param data store the libinput data here
*/
void libinput_read_state(libinput_drv_state_t * state, lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**********************
* MACROS
**********************/
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LVGL_LIBINPUT_H */

View File

@ -1,81 +0,0 @@
/**
* @file mouse.h
*
*/
#ifndef MOUSE_H
#define MOUSE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_MOUSE
#warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c"
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if USE_SDL_GPU
#include "../sdl/sdl_gpu.h"
#else
#include "../sdl/sdl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the mouse
*/
static inline void mouse_init(void)
{
/*Nothing to do*/
}
/**
* Get the current position and state of the mouse
* @param indev_drv pointer to the related input device driver
* @param data store the mouse data here
*/
void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
sdl_mouse_read(indev_drv, data);
}
/**********************
* MACROS
**********************/
#endif /* USE_MOUSE */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* MOUSE_H */

View File

@ -1,80 +0,0 @@
/**
* @file mousewheel.h
*
*/
#ifndef MOUSEWHEEL_H
#define MOUSEWHEEL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_MOUSEWHEEL
#warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c"
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if USE_SDL_GPU
#include "../sdl/sdl_gpu.h"
#else
#include "../sdl/sdl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the encoder
*/
static inline void mousewheel_init(void)
{
/*Nothing to do*/
}
/**
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
* @param indev_drv pointer to the related input device driver
* @param data store the read data here
*/
static inline void mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
sdl_mousewheel_read(indev_drv, data);
}
/**********************
* MACROS
**********************/
#endif /*USE_MOUSEWHEEL*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*MOUSEWHEEL_H*/

View File

@ -1,217 +0,0 @@
/**
* @file xkb.c
*
*/
/*********************
* INCLUDES
*********************/
#include "xkb.h"
#if USE_XKB
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xkbcommon/xkbcommon.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static struct xkb_context *context = NULL;
static xkb_drv_state_t default_state = { .keymap = NULL, .state = NULL };
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialise the XKB system using the default driver state. Use this function if you only want
* to connect a single device.
* @return true if the initialisation was successful
*/
bool xkb_init(void) {
return xkb_init_state(&default_state);
}
/**
* Initialise the XKB system using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state XKB driver state to use
* @return true if the initialisation was successful
*/
bool xkb_init_state(xkb_drv_state_t *state) {
if (!context) {
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) {
perror("could not create new XKB context");
return false;
}
}
#ifdef XKB_KEY_MAP
struct xkb_rule_names names = XKB_KEY_MAP;
return xkb_set_keymap_state(state, names);
#else
return false; /* Keymap needs to be set manually using xkb_set_keymap_state to complete initialisation */
#endif
}
/**
* Set a new keymap to be used for processing future key events using the default driver state. Use
* this function if you only want to connect a single device.
* @param names XKB rule names structure (use NULL components for default values)
* @return true if creating the keymap and associated state succeeded
*/
bool xkb_set_keymap(struct xkb_rule_names names) {
return xkb_set_keymap_state(&default_state, names);
}
/**
* Set a new keymap to be used for processing future key events using a specific driver state. Use
* this function if you want to connect multiple devices.
* @param state XKB driver state to use
* @param names XKB rule names structure (use NULL components for default values)
* @return true if creating the keymap and associated state succeeded
*/
bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names) {
if (state->keymap) {
xkb_keymap_unref(state->keymap);
state->keymap = NULL;
}
state->keymap = xkb_keymap_new_from_names(context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!state->keymap) {
perror("could not create XKB keymap");
return false;
}
state->keymap = xkb_keymap_ref(state->keymap);
if (!state->keymap) {
perror("could not reference XKB keymap");
return false;
}
if (state->state) {
xkb_state_unref(state->state);
state->state = NULL;
}
state->state = xkb_state_new(state->keymap);
if (!state->state) {
perror("could not create XKB state");
return false;
}
state->state = xkb_state_ref(state->state);
if (!state->state) {
perror("could not reference XKB state");
return false;
}
return true;
}
/**
* Process an evdev scancode using the default driver state. Use this function if you only want to
* connect a single device.
* @param scancode evdev scancode to process
* @param down true if the key was pressed, false if it was releases
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
*/
uint32_t xkb_process_key(uint32_t scancode, bool down) {
return xkb_process_key_state(&default_state, scancode, down);
}
/**
* Process an evdev scancode using a specific driver state. Use this function if you want to connect
* multiple devices.
* @param state XKB driver state to use
* @param scancode evdev scancode to process
* @param down true if the key was pressed, false if it was releases
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
*/
uint32_t xkb_process_key_state(xkb_drv_state_t *state, uint32_t scancode, bool down) {
/* Offset the evdev scancode by 8, see https://xkbcommon.org/doc/current/xkbcommon_8h.html#ac29aee92124c08d1953910ab28ee1997 */
xkb_keycode_t keycode = scancode + 8;
uint32_t result = 0;
switch (xkb_state_key_get_one_sym(state->state, keycode)) {
case XKB_KEY_BackSpace:
result = LV_KEY_BACKSPACE;
break;
case XKB_KEY_Return:
case XKB_KEY_KP_Enter:
result = LV_KEY_ENTER;
break;
case XKB_KEY_Prior:
case XKB_KEY_KP_Prior:
result = LV_KEY_PREV;
break;
case XKB_KEY_Next:
case XKB_KEY_KP_Next:
result = LV_KEY_NEXT;
break;
case XKB_KEY_Up:
case XKB_KEY_KP_Up:
result = LV_KEY_UP;
break;
case XKB_KEY_Left:
case XKB_KEY_KP_Left:
result = LV_KEY_LEFT;
break;
case XKB_KEY_Right:
case XKB_KEY_KP_Right:
result = LV_KEY_RIGHT;
break;
case XKB_KEY_Down:
case XKB_KEY_KP_Down:
result = LV_KEY_DOWN;
break;
case XKB_KEY_Tab:
case XKB_KEY_KP_Tab:
result = LV_KEY_NEXT;
break;
case XKB_KEY_ISO_Left_Tab: /* Sent on SHIFT + TAB */
result = LV_KEY_PREV;
break;
default:
break;
}
if (result == 0) {
char buffer[4] = { 0, 0, 0, 0 };
int size = xkb_state_key_get_utf8(state->state, keycode, NULL, 0) + 1;
if (size > 1) {
xkb_state_key_get_utf8(state->state, keycode, buffer, size);
memcpy(&result, buffer, 4);
}
}
xkb_state_update_key(state->state, keycode, down ? XKB_KEY_DOWN : XKB_KEY_UP);
return result;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /* USE_XKB */

View File

@ -1,106 +0,0 @@
/**
* @file xkb.h
*
*/
#ifndef XKB_H
#define XKB_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_XKB
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct xkb_rule_names;
typedef struct {
struct xkb_keymap *keymap;
struct xkb_state *state;
} xkb_drv_state_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialise the XKB system using the default driver state. Use this function if you only want
* to connect a single device.
* @return true if the initialisation was successful
*/
bool xkb_init(void);
/**
* Initialise the XKB system using a specific driver state. Use this function if you want to
* connect multiple devices.
* @param state XKB driver state to use
* @return true if the initialisation was successful
*/
bool xkb_init_state(xkb_drv_state_t *state);
/**
* Set a new keymap to be used for processing future key events using the default driver state. Use
* this function if you only want to connect a single device.
* @param names XKB rule names structure (use NULL components for default values)
* @return true if creating the keymap and associated state succeeded
*/
bool xkb_set_keymap(struct xkb_rule_names names);
/**
* Set a new keymap to be used for processing future key events using a specific driver state. Use
* this function if you want to connect multiple devices.
* @param state XKB driver state to use
* @param names XKB rule names structure (use NULL components for default values)
* @return true if creating the keymap and associated state succeeded
*/
bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names);
/**
* Process an evdev scancode using the default driver state. Use this function if you only want to
* connect a single device.
* @param scancode evdev scancode to process
* @param down true if the key was pressed, false if it was releases
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
*/
uint32_t xkb_process_key(uint32_t scancode, bool down);
/**
* Process an evdev scancode using a specific driver state. Use this function if you want to connect
* multiple devices.
* @param state XKB driver state to use
* @param scancode evdev scancode to process
* @param down true if the key was pressed, false if it was releases
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
*/
uint32_t xkb_process_key_state(xkb_drv_state_t *state, uint32_t scancode, bool down);
/**********************
* MACROS
**********************/
#endif /* USE_XKB */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* XKB_H */

View File

@ -1,13 +0,0 @@
{
"name": "lv_drivers",
"version": "8.3.0",
"keywords": "littlevgl, lvgl, driver, display, touchpad",
"description": "Drivers for LittlevGL graphics library.",
"repository": {
"type": "git",
"url": "https://github.com/littlevgl/lv_drivers.git"
},
"build": {
"includeDir": "."
}
}

View File

@ -1,10 +0,0 @@
LV_DRIVERS_DIR_NAME ?= lv_drivers
override CFLAGS := -I$(LVGL_DIR) $(CFLAGS)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/wayland/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/indev/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/gtkdrv/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/display/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/sdl/*.c)

View File

@ -1,496 +0,0 @@
/**
* @file lv_drv_conf.h
* Configuration file for v8.3.0
*/
/*
* COPY THIS FILE AS lv_drv_conf.h
*/
/* clang-format off */
#if 0 /*Set it to "1" to enable the content*/
#ifndef LV_DRV_CONF_H
#define LV_DRV_CONF_H
#include "lv_conf.h"
/*********************
* DELAY INTERFACE
*********************/
#define LV_DRV_DELAY_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/
#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/
/*********************
* DISPLAY INTERFACE
*********************/
/*------------
* Common
*------------*/
#define LV_DRV_DISP_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/
#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
/*---------
* SPI
*---------*/
#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/
/*------------------
* Parallel port
*-----------------*/
#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/
#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/
#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/
#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/
/***************************
* INPUT DEVICE INTERFACE
***************************/
/*----------
* Common
*----------*/
#define LV_DRV_INDEV_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/
/*---------
* SPI
*---------*/
#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/
/*---------
* I2C
*---------*/
#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/
#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/
#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/
#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/
#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/
/*********************
* DISPLAY DRIVERS
*********************/
/*-------------------
* SDL
*-------------------*/
/* SDL based drivers for display, mouse, mousewheel and keyboard*/
#ifndef USE_SDL
# define USE_SDL 0
#endif
/* Hardware accelerated SDL driver */
#ifndef USE_SDL_GPU
# define USE_SDL_GPU 0
#endif
#if USE_SDL || USE_SDL_GPU
# define SDL_HOR_RES 480
# define SDL_VER_RES 320
/* Scale window by this factor (useful when simulating small screens) */
# define SDL_ZOOM 1
/* Used to test true double buffering with only address changing.
* Use 2 draw buffers, bith with SDL_HOR_RES x SDL_VER_RES size*/
# define SDL_DOUBLE_BUFFERED 0
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
# define SDL_INCLUDE_PATH <SDL2/SDL.h>
/*Open two windows to test multi display support*/
# define SDL_DUAL_DISPLAY 0
#endif
/*-------------------
* Monitor of PC
*-------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_MONITOR
# define USE_MONITOR 0
#endif
#if USE_MONITOR
# define MONITOR_HOR_RES 480
# define MONITOR_VER_RES 320
/* Scale window by this factor (useful when simulating small screens) */
# define MONITOR_ZOOM 1
/* Used to test true double buffering with only address changing.
* Use 2 draw buffers, bith with MONITOR_HOR_RES x MONITOR_VER_RES size*/
# define MONITOR_DOUBLE_BUFFERED 0
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
/*Open two windows to test multi display support*/
# define MONITOR_DUAL 0
#endif
/*-----------------------------------
* Native Windows (including mouse)
*----------------------------------*/
#ifndef USE_WINDOWS
# define USE_WINDOWS 0
#endif
#if USE_WINDOWS
# define WINDOW_HOR_RES 480
# define WINDOW_VER_RES 320
#endif
/*----------------------------
* Native Windows (win32drv)
*---------------------------*/
#ifndef USE_WIN32DRV
# define USE_WIN32DRV 0
#endif
#if USE_WIN32DRV
/* Scale window by this factor (useful when simulating small screens) */
# define WIN32DRV_MONITOR_ZOOM 1
#endif
/*----------------------------------------
* GTK drivers (monitor, mouse, keyboard
*---------------------------------------*/
#ifndef USE_GTK
# define USE_GTK 0
#endif
/*----------------------------------------
* Wayland drivers (monitor, mouse, keyboard, touchscreen)
*---------------------------------------*/
#ifndef USE_WAYLAND
# define USE_WAYLAND 0
#endif
#if USE_WAYLAND
/* Support for client-side decorations */
# ifndef LV_WAYLAND_CLIENT_SIDE_DECORATIONS
# define LV_WAYLAND_CLIENT_SIDE_DECORATIONS 1
# endif
/* Support for (deprecated) wl-shell protocol */
# ifndef LV_WAYLAND_WL_SHELL
# define LV_WAYLAND_WL_SHELL 1
# endif
/* Support for xdg-shell protocol */
# ifndef LV_WAYLAND_XDG_SHELL
# define LV_WAYLAND_XDG_SHELL 0
# endif
#endif
/*----------------
* SSD1963
*--------------*/
#ifndef USE_SSD1963
# define USE_SSD1963 0
#endif
#if USE_SSD1963
# define SSD1963_HOR_RES LV_HOR_RES
# define SSD1963_VER_RES LV_VER_RES
# define SSD1963_HT 531
# define SSD1963_HPS 43
# define SSD1963_LPS 8
# define SSD1963_HPW 10
# define SSD1963_VT 288
# define SSD1963_VPS 12
# define SSD1963_FPS 4
# define SSD1963_VPW 10
# define SSD1963_HS_NEG 0 /*Negative hsync*/
# define SSD1963_VS_NEG 0 /*Negative vsync*/
# define SSD1963_ORI 0 /*0, 90, 180, 270*/
# define SSD1963_COLOR_DEPTH 16
#endif
/*----------------
* R61581
*--------------*/
#ifndef USE_R61581
# define USE_R61581 0
#endif
#if USE_R61581
# define R61581_HOR_RES LV_HOR_RES
# define R61581_VER_RES LV_VER_RES
# define R61581_HSPL 0 /*HSYNC signal polarity*/
# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/
# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/
# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */
# define R61581_VSPL 0 /*VSYNC signal polarity*/
# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/
# define R61581_VFP 8 /*Vertical Front poarch*/
# define R61581_VBP 8 /*Vertical Back poarch */
# define R61581_DPL 0 /*DCLK signal polarity*/
# define R61581_EPL 1 /*ENABLE signal polarity*/
# define R61581_ORI 0 /*0, 180*/
# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/
#endif
/*------------------------------
* ST7565 (Monochrome, low res.)
*-----------------------------*/
#ifndef USE_ST7565
# define USE_ST7565 0
#endif
#if USE_ST7565
/*No settings*/
#endif /*USE_ST7565*/
/*------------------------------
* GC9A01 (color, low res.)
*-----------------------------*/
#ifndef USE_GC9A01
# define USE_GC9A01 0
#endif
#if USE_GC9A01
/*No settings*/
#endif /*USE_GC9A01*/
/*------------------------------------------
* UC1610 (4 gray 160*[104|128])
* (EA DOGXL160 160x104 tested)
*-----------------------------------------*/
#ifndef USE_UC1610
# define USE_UC1610 0
#endif
#if USE_UC1610
# define UC1610_HOR_RES LV_HOR_RES
# define UC1610_VER_RES LV_VER_RES
# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */
# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */
# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */
#endif /*USE_UC1610*/
/*-------------------------------------------------
* SHARP memory in pixel monochrome display series
* LS012B7DD01 (184x38 pixels.)
* LS013B7DH03 (128x128 pixels.)
* LS013B7DH05 (144x168 pixels.)
* LS027B7DH01 (400x240 pixels.) (tested)
* LS032B7DD02 (336x536 pixels.)
* LS044Q7DH01 (320x240 pixels.)
*------------------------------------------------*/
#ifndef USE_SHARP_MIP
# define USE_SHARP_MIP 0
#endif
#if USE_SHARP_MIP
# define SHARP_MIP_HOR_RES LV_HOR_RES
# define SHARP_MIP_VER_RES LV_VER_RES
# define SHARP_MIP_SOFT_COM_INVERSION 0
# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/
#endif /*USE_SHARP_MIP*/
/*-------------------------------------------------
* ILI9341 240X320 TFT LCD
*------------------------------------------------*/
#ifndef USE_ILI9341
# define USE_ILI9341 0
#endif
#if USE_ILI9341
# define ILI9341_HOR_RES LV_HOR_RES
# define ILI9341_VER_RES LV_VER_RES
# define ILI9341_GAMMA 1
# define ILI9341_TEARING 0
#endif /*USE_ILI9341*/
/*-----------------------------------------
* Linux frame buffer device (/dev/fbx)
*-----------------------------------------*/
#ifndef USE_FBDEV
# define USE_FBDEV 0
#endif
#if USE_FBDEV
# define FBDEV_PATH "/dev/fb0"
# define FBDEV_DISPLAY_POWER_ON 1 /* 1 to force display power during initialization */
#endif
/*-----------------------------------------
* FreeBSD frame buffer device (/dev/fbx)
*.........................................*/
#ifndef USE_BSD_FBDEV
# define USE_BSD_FBDEV 0
#endif
#if USE_BSD_FBDEV
# define FBDEV_PATH "/dev/fb0"
# define FBDEV_DISPLAY_POWER_ON 1 /* 1 to force display power during initialization */
#endif
/*-----------------------------------------
* DRM/KMS device (/dev/dri/cardX)
*-----------------------------------------*/
#ifndef USE_DRM
# define USE_DRM 0
#endif
#if USE_DRM
# define DRM_CARD "/dev/dri/card0"
# define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */
#endif
/*********************
* INPUT DEVICES
*********************/
/*--------------
* XPT2046
*--------------*/
#ifndef USE_XPT2046
# define USE_XPT2046 0
#endif
#if USE_XPT2046
# define XPT2046_HOR_RES 480
# define XPT2046_VER_RES 320
# define XPT2046_X_MIN 200
# define XPT2046_Y_MIN 200
# define XPT2046_X_MAX 3800
# define XPT2046_Y_MAX 3800
# define XPT2046_AVG 4
# define XPT2046_X_INV 0
# define XPT2046_Y_INV 0
# define XPT2046_XY_SWAP 0
#endif
/*-----------------
* FT5406EE8
*-----------------*/
#ifndef USE_FT5406EE8
# define USE_FT5406EE8 0
#endif
#if USE_FT5406EE8
# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/
#endif
/*---------------
* AD TOUCH
*--------------*/
#ifndef USE_AD_TOUCH
# define USE_AD_TOUCH 0
#endif
#if USE_AD_TOUCH
/*No settings*/
#endif
/*---------------------------------------
* Mouse or touchpad on PC (using SDL)
*-------------------------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_MOUSE
# define USE_MOUSE 0
#endif
#if USE_MOUSE
/*No settings*/
#endif
/*-------------------------------------------
* Mousewheel as encoder on PC (using SDL)
*------------------------------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_MOUSEWHEEL
# define USE_MOUSEWHEEL 0
#endif
#if USE_MOUSEWHEEL
/*No settings*/
#endif
/*-------------------------------------------------
* Touchscreen, mouse/touchpad or keyboard as libinput interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_LIBINPUT
# define USE_LIBINPUT 0
#endif
#ifndef USE_BSD_LIBINPUT
# define USE_BSD_LIBINPUT 0
#endif
#if USE_LIBINPUT || USE_BSD_LIBINPUT
/*If only a single device of the same type is connected, you can also auto detect it, e.g.:
*#define LIBINPUT_NAME libinput_find_dev(LIBINPUT_CAPABILITY_TOUCH, false)*/
# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT*/
/*-------------------------------------------------
* Mouse or touchpad as evdev interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_EVDEV
# define USE_EVDEV 0
#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*/
/*-------------------------------------------------
* Full keyboard support for evdev and libinput interface
*------------------------------------------------*/
# ifndef USE_XKB
# define USE_XKB 0
# endif
#if USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV
# if USE_XKB
# define XKB_KEY_MAP { .rules = NULL, \
.model = "pc101", \
.layout = "us", \
.variant = NULL, \
.options = NULL } /*"setxkbmap -query" can help find the right values for your keyboard*/
# endif /*USE_XKB*/
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV*/
/*-------------------------------
* Keyboard of a PC (using SDL)
*------------------------------*/
/*DEPRECATED: Use the SDL driver instead. */
#ifndef USE_KEYBOARD
# define USE_KEYBOARD 0
#endif
#if USE_KEYBOARD
/*No settings*/
#endif
#endif /*LV_DRV_CONF_H*/
#endif /*End of "Content enable"*/

View File

@ -1,391 +0,0 @@
/**
* @file sdl.h
*
*/
/*********************
* INCLUDES
*********************/
#include "sdl.h"
#if USE_MONITOR || USE_SDL
#if LV_USE_GPU_SDL
# error "LV_USE_GPU_SDL must not be enabled"
#endif
#if USE_MONITOR
# warning "MONITOR is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
#endif
#if USE_KEYBOARD
# warning "KEYBOARD is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
#endif
#if USE_MOUSE
# warning "MOUSE is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
#endif
#if USE_MOUSEWHEEL
# warning "MOUSEWHEEL is deprecated, use SDL instead that. See lv_drivers/sdl/sdl.c"
#endif
#if USE_MONITOR && USE_SDL
# error "Cannot enable both MONITOR and SDL at the same time. "
#endif
#if USE_MONITOR
# define SDL_HOR_RES MONITOR_HOR_RES
# define SDL_VER_RES MONITOR_VER_RES
# define SDL_ZOOM MONITOR_ZOOM
# define SDL_DOUBLE_BUFFERED MONITOR_DOUBLE_BUFFERED
# define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
# define SDL_VIRTUAL_MACHINE MONITOR_VIRTUAL_MACHINE
# define SDL_DUAL_DISPLAY MONITOR_DUAL
#endif
#ifndef SDL_FULLSCREEN
# define SDL_FULLSCREEN 0
#endif
#include "sdl_common_internal.h"
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include SDL_INCLUDE_PATH
/*********************
* DEFINES
*********************/
#ifndef KEYBOARD_BUFFER_SIZE
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * texture;
volatile bool sdl_refr_qry;
#if SDL_DOUBLE_BUFFERED
uint32_t * tft_fb_act;
#else
uint32_t * tft_fb;
#endif
}monitor_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void window_create(monitor_t * m);
static void window_update(monitor_t * m);
static void monitor_sdl_clean_up(void);
static void sdl_event_handler(lv_timer_t * t);
static void monitor_sdl_refr(lv_timer_t * t);
/***********************
* GLOBAL PROTOTYPES
***********************/
/**********************
* STATIC VARIABLES
**********************/
monitor_t monitor;
#if SDL_DUAL_DISPLAY
monitor_t monitor2;
#endif
static volatile bool sdl_inited = false;
static bool left_button_down = false;
static int16_t last_x = 0;
static int16_t last_y = 0;
static int16_t wheel_diff = 0;
static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED;
static char buf[KEYBOARD_BUFFER_SIZE];
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void sdl_init(void)
{
/*Initialize the SDL*/
SDL_Init(SDL_INIT_VIDEO);
SDL_SetEventFilter(quit_filter, NULL);
window_create(&monitor);
#if SDL_DUAL_DISPLAY
window_create(&monitor2);
int x, y;
SDL_GetWindowPosition(monitor2.window, &x, &y);
SDL_SetWindowPosition(monitor.window, x + (SDL_HOR_RES * SDL_ZOOM) / 2 + 10, y);
SDL_SetWindowPosition(monitor2.window, x - (SDL_HOR_RES * SDL_ZOOM) / 2 - 10, y);
#endif
SDL_StartTextInput();
lv_timer_create(sdl_event_handler, 10, NULL);
}
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
const lv_coord_t hres = disp_drv->physical_hor_res == -1 ? disp_drv->hor_res : disp_drv->physical_hor_res;
const lv_coord_t vres = disp_drv->physical_ver_res == -1 ? disp_drv->ver_res : disp_drv->physical_ver_res;
// printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2);
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
#if SDL_DOUBLE_BUFFERED
monitor.tft_fb_act = (uint32_t *)color_p;
#else /*SDL_DOUBLE_BUFFERED*/
int32_t y;
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
int32_t x;
for(y = area->y1; y <= area->y2 && y < vres; y++) {
for(x = area->x1; x <= area->x2; x++) {
monitor.tft_fb[y * hres + x] = lv_color_to32(*color_p);
color_p++;
}
}
#else
uint32_t w = lv_area_get_width(area);
for(y = area->y1; y <= area->y2 && y < vres; y++) {
memcpy(&monitor.tft_fb[y * hres + area->x1], color_p, w * sizeof(lv_color_t));
color_p += w;
}
#endif
#endif /*SDL_DOUBLE_BUFFERED*/
monitor.sdl_refr_qry = true;
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
if(lv_disp_flush_is_last(disp_drv)) {
monitor_sdl_refr(NULL);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
}
#if SDL_DUAL_DISPLAY
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
const lv_coord_t hres = disp_drv->physical_hor_res == -1 ? disp_drv->hor_res : disp_drv->physical_hor_res;
const lv_coord_t vres = disp_drv->physical_ver_res == -1 ? disp_drv->ver_res : disp_drv->physical_ver_res;
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
#if SDL_DOUBLE_BUFFERED
monitor2.tft_fb_act = (uint32_t *)color_p;
monitor2.sdl_refr_qry = true;
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
#else
int32_t y;
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
int32_t x;
for(y = area->y1; y <= area->y2 && y < vres; y++) {
for(x = area->x1; x <= area->x2; x++) {
monitor2.tft_fb[y * hres + x] = lv_color_to32(*color_p);
color_p++;
}
}
#else
uint32_t w = lv_area_get_width(area);
for(y = area->y1; y <= area->y2 && y < vres; y++) {
memcpy(&monitor2.tft_fb[y * hres + area->x1], color_p, w * sizeof(lv_color_t));
color_p += w;
}
#endif
monitor2.sdl_refr_qry = true;
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
if(lv_disp_flush_is_last(disp_drv)) {
monitor_sdl_refr(NULL);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
#endif
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
/**
* SDL main thread. All SDL related task have to be handled here!
* It initializes SDL, handles drawing and the mouse.
*/
static void sdl_event_handler(lv_timer_t * t)
{
(void)t;
/*Refresh handling*/
SDL_Event event;
while(SDL_PollEvent(&event)) {
mouse_handler(&event);
mousewheel_handler(&event);
keyboard_handler(&event);
if((&event)->type == SDL_WINDOWEVENT) {
switch((&event)->window.event) {
#if SDL_VERSION_ATLEAST(2, 0, 5)
case SDL_WINDOWEVENT_TAKE_FOCUS:
#endif
case SDL_WINDOWEVENT_EXPOSED:
window_update(&monitor);
#if SDL_DUAL_DISPLAY
window_update(&monitor2);
#endif
break;
default:
break;
}
}
}
/*Run until quit event not arrives*/
if(sdl_quit_qry) {
monitor_sdl_clean_up();
exit(0);
}
}
/**
* SDL main thread. All SDL related task have to be handled here!
* It initializes SDL, handles drawing and the mouse.
*/
static void monitor_sdl_refr(lv_timer_t * t)
{
(void)t;
/*Refresh handling*/
if(monitor.sdl_refr_qry != false) {
monitor.sdl_refr_qry = false;
window_update(&monitor);
}
#if SDL_DUAL_DISPLAY
if(monitor2.sdl_refr_qry != false) {
monitor2.sdl_refr_qry = false;
window_update(&monitor2);
}
#endif
}
static void monitor_sdl_clean_up(void)
{
SDL_DestroyTexture(monitor.texture);
SDL_DestroyRenderer(monitor.renderer);
SDL_DestroyWindow(monitor.window);
#if SDL_DUAL_DISPLAY
SDL_DestroyTexture(monitor2.texture);
SDL_DestroyRenderer(monitor2.renderer);
SDL_DestroyWindow(monitor2.window);
#endif
SDL_Quit();
}
static void window_create(monitor_t * m)
{
int flag = 0;
#if SDL_FULLSCREEN
flag |= SDL_WINDOW_FULLSCREEN;
#endif
m->window = SDL_CreateWindow(SDL_WINDOW_NAME,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/
m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_SOFTWARE);
m->texture = SDL_CreateTexture(m->renderer,
SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, SDL_HOR_RES, SDL_VER_RES);
SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_BLEND);
/*Initialize the frame buffer to gray (77 is an empirical value) */
#if SDL_DOUBLE_BUFFERED
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, SDL_HOR_RES * sizeof(uint32_t));
#else
m->tft_fb = (uint32_t *)malloc(sizeof(uint32_t) * SDL_HOR_RES * SDL_VER_RES);
memset(m->tft_fb, 0x44, SDL_HOR_RES * SDL_VER_RES * sizeof(uint32_t));
#endif
m->sdl_refr_qry = true;
}
static void window_update(monitor_t * m)
{
#if SDL_DOUBLE_BUFFERED == 0
SDL_UpdateTexture(m->texture, NULL, m->tft_fb, SDL_HOR_RES * sizeof(uint32_t));
#else
if(m->tft_fb_act == NULL) return;
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, SDL_HOR_RES * sizeof(uint32_t));
#endif
SDL_RenderClear(m->renderer);
lv_disp_t * d = _lv_refr_get_disp_refreshing();
if(d->driver->screen_transp) {
SDL_SetRenderDrawColor(m->renderer, 0xff, 0, 0, 0xff);
SDL_Rect r;
r.x = 0; r.y = 0; r.w = SDL_HOR_RES; r.h = SDL_VER_RES;
SDL_RenderDrawRect(m->renderer, &r);
}
/*Update the renderer with the texture containing the rendered image*/
SDL_RenderCopy(m->renderer, m->texture, NULL, NULL);
SDL_RenderPresent(m->renderer);
}
#endif /*USE_MONITOR || USE_SDL*/

View File

@ -1,103 +0,0 @@
/**
* @file sdl.h
*
*/
#ifndef SDL_H
#define SDL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_MONITOR || USE_SDL
#include "sdl_common.h"
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize SDL to be used as display, mouse and mouse wheel drivers.
*/
void sdl_init(void);
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**
* Get the current position and state of the mouse
* @param indev_drv pointer to the related input device driver
* @param data store the mouse data here
*/
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
* @param indev_drv pointer to the related input device driver
* @param data store the read data here
*/
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Get input from the keyboard.
* @param indev_drv pointer to the related input device driver
* @param data store the red data here
*/
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/*For backward compatibility. Will be removed.*/
#define monitor_init sdl_init
#define monitor_flush sdl_display_flush
#define monitor_flush2 sdl_display_flush2
/**********************
* MACROS
**********************/
#endif /* USE_MONITOR || USE_SDL */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SDL_H */

View File

@ -1,273 +0,0 @@
//
// Created by Mariotaku on 2021/10/14.
//
#include "sdl_common.h"
#if USE_SDL || USE_SDL_GPU
#include "sdl_common_internal.h"
/*********************
* DEFINES
*********************/
#ifndef KEYBOARD_BUFFER_SIZE
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
#endif
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
volatile bool sdl_quit_qry = false;
static bool left_button_down = false;
static int16_t last_x = 0;
static int16_t last_y = 0;
static int16_t wheel_diff = 0;
static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED;
static char buf[KEYBOARD_BUFFER_SIZE];
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Get the current position and state of the mouse
* @param indev_drv pointer to the related input device driver
* @param data store the mouse data here
*/
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
(void) indev_drv; /*Unused*/
/*Store the collected data*/
data->point.x = last_x;
data->point.y = last_y;
data->state = left_button_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
/**
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
* @param indev_drv pointer to the related input device driver
* @param data store the read data here
*/
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
(void) indev_drv; /*Unused*/
data->state = wheel_state;
data->enc_diff = wheel_diff;
wheel_diff = 0;
}
/**
* Get input from the keyboard.
* @param indev_drv pointer to the related input device driver
* @param data store the red data here
*/
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
(void) indev_drv; /*Unused*/
static bool dummy_read = false;
const size_t len = strlen(buf);
/*Send a release manually*/
if (dummy_read) {
dummy_read = false;
data->state = LV_INDEV_STATE_RELEASED;
data->continue_reading = len > 0;
}
/*Send the pressed character*/
else if (len > 0) {
dummy_read = true;
data->state = LV_INDEV_STATE_PRESSED;
data->key = buf[0];
memmove(buf, buf + 1, len);
data->continue_reading = true;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
int quit_filter(void * userdata, SDL_Event * event)
{
(void)userdata;
if(event->type == SDL_QUIT) {
sdl_quit_qry = true;
}
return 1;
}
void mouse_handler(SDL_Event * event)
{
switch(event->type) {
case SDL_MOUSEBUTTONUP:
if(event->button.button == SDL_BUTTON_LEFT)
left_button_down = false;
break;
case SDL_MOUSEBUTTONDOWN:
if(event->button.button == SDL_BUTTON_LEFT) {
left_button_down = true;
last_x = event->motion.x / SDL_ZOOM;
last_y = event->motion.y / SDL_ZOOM;
}
break;
case SDL_MOUSEMOTION:
last_x = event->motion.x / SDL_ZOOM;
last_y = event->motion.y / SDL_ZOOM;
break;
case SDL_FINGERUP:
left_button_down = false;
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM;
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM;
break;
case SDL_FINGERDOWN:
left_button_down = true;
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM;
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM;
break;
case SDL_FINGERMOTION:
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM;
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM;
break;
}
}
/**
* It is called periodically from the SDL thread to check mouse wheel state
* @param event describes the event
*/
void mousewheel_handler(SDL_Event * event)
{
switch(event->type) {
case SDL_MOUSEWHEEL:
// Scroll down (y = -1) means positive encoder turn,
// so invert it
#ifdef __EMSCRIPTEN__
/*Escripten scales it wrong*/
if(event->wheel.y < 0) wheel_diff++;
if(event->wheel.y > 0) wheel_diff--;
#else
wheel_diff = -event->wheel.y;
#endif
break;
case SDL_MOUSEBUTTONDOWN:
if(event->button.button == SDL_BUTTON_MIDDLE) {
wheel_state = LV_INDEV_STATE_PRESSED;
}
break;
case SDL_MOUSEBUTTONUP:
if(event->button.button == SDL_BUTTON_MIDDLE) {
wheel_state = LV_INDEV_STATE_RELEASED;
}
break;
default:
break;
}
}
/**
* Called periodically from the SDL thread, store text input or control characters in the buffer.
* @param event describes the event
*/
void keyboard_handler(SDL_Event * event)
{
/* We only care about SDL_KEYDOWN and SDL_TEXTINPUT events */
switch(event->type) {
case SDL_KEYDOWN: /*Button press*/
{
const uint32_t ctrl_key = keycode_to_ctrl_key(event->key.keysym.sym);
if (ctrl_key == '\0')
return;
const size_t len = strlen(buf);
if (len < KEYBOARD_BUFFER_SIZE - 1) {
buf[len] = ctrl_key;
buf[len + 1] = '\0';
}
break;
}
case SDL_TEXTINPUT: /*Text input*/
{
const size_t len = strlen(buf) + strlen(event->text.text);
if (len < KEYBOARD_BUFFER_SIZE - 1)
strcat(buf, event->text.text);
}
break;
default:
break;
}
}
/**
* Convert a SDL key code to it's LV_KEY_* counterpart or return '\0' if it's not a control character.
* @param sdl_key the key code
* @return LV_KEY_* control character or '\0'
*/
uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key)
{
/*Remap some key to LV_KEY_... to manage groups*/
SDL_Keymod mode = SDL_GetModState();
switch(sdl_key) {
case SDLK_RIGHT:
case SDLK_KP_PLUS:
return LV_KEY_RIGHT;
case SDLK_LEFT:
case SDLK_KP_MINUS:
return LV_KEY_LEFT;
case SDLK_UP:
return LV_KEY_UP;
case SDLK_DOWN:
return LV_KEY_DOWN;
case SDLK_ESCAPE:
return LV_KEY_ESC;
case SDLK_BACKSPACE:
return LV_KEY_BACKSPACE;
case SDLK_DELETE:
return LV_KEY_DEL;
case SDLK_KP_ENTER:
case '\r':
return LV_KEY_ENTER;
case SDLK_TAB:
return (mode & KMOD_SHIFT)? LV_KEY_PREV: LV_KEY_NEXT;
case SDLK_PAGEDOWN:
return LV_KEY_NEXT;
case SDLK_PAGEUP:
return LV_KEY_PREV;
default:
return '\0';
}
}
#endif /* USE_SDL || USD_SDL_GPU */

View File

@ -1,93 +0,0 @@
/**
* @file sdl_common.h
*
*/
#ifndef SDL_COMMON_H
#define SDL_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if USE_SDL || USE_SDL_GPU
#ifndef SDL_INCLUDE_PATH
#define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
#endif
#ifndef SDL_ZOOM
#define SDL_ZOOM MONITOR_ZOOM
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
extern volatile bool sdl_quit_qry;
/**
* Initialize SDL to be used as display, mouse and mouse wheel drivers.
*/
void sdl_init(void);
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixel to copy to the `area` part of the screen
*/
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**
* Get the current position and state of the mouse
* @param indev_drv pointer to the related input device driver
* @param data store the mouse data here
*/
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
* @param indev_drv pointer to the related input device driver
* @param data store the read data here
*/
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Get input from the keyboard.
* @param indev_drv pointer to the related input device driver
* @param data store the red data here
*/
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
#endif /* USE_SDL || USE_SDL_GPU */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SDL_COMMON_H */

View File

@ -1,39 +0,0 @@
/**
* @file sdl_common_internal.h
* Provides SDL related functions which are only used internal.
*
*/
#ifndef SDL_COMMON_INTERNAL_H
#define SDL_COMMON_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "sdl_common.h"
#if USE_SDL || USE_SDL_GPU
#include SDL_INCLUDE_PATH
/**********************
* GLOBAL PROTOTYPES
**********************/
int quit_filter(void * userdata, SDL_Event * event);
void mouse_handler(SDL_Event * event);
void mousewheel_handler(SDL_Event * event);
uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key);
void keyboard_handler(SDL_Event * event);
#endif /* USE_SDL || USE_SDL_GPU */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SDL_COMMON_INTERNAL_H */

Some files were not shown because too many files have changed in this diff Show More