├── .github ├── auto-comment.yml └── stale.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── display ├── GC9A01.c ├── GC9A01.h ├── ILI9341.c ├── ILI9341.h ├── R61581.c ├── R61581.h ├── SHARP_MIP.c ├── SHARP_MIP.h ├── SSD1963.c ├── SSD1963.h ├── ST7565.c ├── ST7565.h ├── UC1610.c ├── UC1610.h ├── drm.c ├── drm.h ├── fbdev.c ├── fbdev.h └── monitor.h ├── docs ├── astyle_c └── astyle_h ├── gtkdrv ├── README.md ├── broadway.png ├── gtkdrv.c └── gtkdrv.h ├── indev ├── AD_touch.c ├── AD_touch.h ├── FT5406EE8.c ├── FT5406EE8.h ├── XPT2046.c ├── XPT2046.h ├── evdev.c ├── evdev.h ├── keyboard.h ├── libinput.c ├── libinput_drv.h ├── mouse.h ├── mousewheel.h ├── xkb.c └── xkb.h ├── library.json ├── lv-drivers.pc.in ├── lv_drivers.mk ├── lv_drv_conf_template.h ├── sdl ├── sdl.c ├── sdl.h ├── sdl_common.c ├── sdl_common.h ├── sdl_common_internal.h ├── sdl_gpu.c └── sdl_gpu.h ├── wayland ├── .gitignore ├── CMakeLists.txt ├── README.md ├── smm.c ├── smm.h ├── wayland.c └── wayland.h ├── win32drv ├── win32drv.c └── win32drv.h ├── win_drv.c ├── win_drv.h └── x11 ├── x11.c └── x11.h /.github/auto-comment.yml: -------------------------------------------------------------------------------- 1 | # Comment to a new issue. 2 | pullRequestOpened: | 3 | Thank you for raising your pull request. 4 | 5 | To ensure that all licensing criteria is met all repositories of the LVGL project apply a process called DCO (Developer's Certificate of Origin). 6 | 7 | The text of DCO can be read here: https://developercertificate.org/ 8 | For a more detailed description see the [Documentation](https://docs.lvgl.io/latest/en/html/contributing/index.html#developer-certification-of-origin-dco) site. 9 | 10 | By contributing to any repositories of the LVGL project you state that your contribution corresponds with the DCO. 11 | 12 | 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. 13 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 21 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - architecture 8 | - pinned 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue or pull request has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.o 2 | **/*.d 3 | build/* 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12.4) 2 | 3 | project(lv_drivers HOMEPAGE_URL https://github.com/lvgl/lv_drivers/) 4 | 5 | # Option to build as shared library (as opposed to static), default: OFF 6 | option(BUILD_SHARED_LIBS "Build shared as library (as opposed to static)" OFF) 7 | 8 | file(GLOB_RECURSE SOURCES ./*.c) 9 | 10 | if (BUILD_SHARED_LIBS) 11 | add_library(lv_drivers SHARED ${SOURCES}) 12 | else() 13 | add_library(lv_drivers STATIC ${SOURCES}) 14 | endif() 15 | 16 | add_library(lvgl_drivers ALIAS lv_drivers) 17 | add_library(lvgl::drivers ALIAS lv_drivers) 18 | 19 | target_include_directories(lv_drivers SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 20 | 21 | find_package(PkgConfig) 22 | pkg_check_modules(PKG_WAYLAND wayland-client wayland-cursor wayland-protocols xkbcommon) 23 | pkg_check_modules(PKG_LVGL lvgl) 24 | target_link_libraries(lv_drivers PUBLIC lvgl ${PKG_WAYLAND_LIBRARIES}) 25 | 26 | if("${LIB_INSTALL_DIR}" STREQUAL "") 27 | set(LIB_INSTALL_DIR "lib") 28 | endif() 29 | 30 | if("${INC_INSTALL_DIR}" STREQUAL "") 31 | set(INC_INSTALL_DIR "include/lvgl/lv_drivers") 32 | endif() 33 | 34 | install( 35 | DIRECTORY "${CMAKE_SOURCE_DIR}/" 36 | DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/" 37 | FILES_MATCHING 38 | PATTERN "*.h" 39 | PATTERN ".git*" EXCLUDE 40 | PATTERN "CMakeFiles" EXCLUDE 41 | PATTERN "docs" EXCLUDE 42 | PATTERN "lib" EXCLUDE 43 | PATTERN "*.pc.in" EXCLUDE) 44 | 45 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PKG_LVGL_CFLAGS}") 46 | 47 | configure_file("${CMAKE_SOURCE_DIR}/lv-drivers.pc.in" lv-drivers.pc @ONLY) 48 | 49 | install( 50 | FILES "${CMAKE_BINARY_DIR}/lv-drivers.pc" 51 | DESTINATION "${LIB_INSTALL_DIR}/pkgconfig/") 52 | 53 | file(GLOB LV_DRIVERS_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_drv_conf.h") 54 | 55 | set_target_properties( 56 | lv_drivers 57 | PROPERTIES OUTPUT_NAME lv_drivers 58 | ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" 59 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" 60 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" 61 | PUBLIC_HEADER "${LV_DRIVERS_PUBLIC_HEADERS}") 62 | 63 | install( 64 | TARGETS lv_drivers 65 | ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" 66 | LIBRARY DESTINATION "${LIB_INSTALL_DIR}" 67 | RUNTIME DESTINATION "${LIB_INSTALL_DIR}" 68 | PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}") 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 LittlevGL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Display and Touch pad drivers 2 | 3 | **The drivers are merged to LVGL since v9.** 4 | 5 | Display controller and touchpad driver to can be directly used with [LVGL](https://lvgl.io/). 6 | 7 | To learn more about using drivers in LittlevGL visit the [Porting guide](https://docs.lvgl.io/latest/en/html/porting/index.html). 8 | 9 | If you used a new display or touchpad driver with LittlevGL please share it with other people! 10 | -------------------------------------------------------------------------------- /display/GC9A01.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file GC9A01.h 3 | * 4 | **/ 5 | 6 | #ifndef GC9A01_H 7 | #define GC9A01_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_GC9A01 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | #if LV_COLOR_DEPTH != 16 33 | #error "GC9A01 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h" 34 | #endif 35 | 36 | #if LV_COLOR_16_SWAP != 1 37 | #error "GC9A01 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h" 38 | #endif 39 | 40 | /********************* 41 | * DEFINES 42 | *********************/ 43 | 44 | /********************** 45 | * TYPEDEFS 46 | **********************/ 47 | 48 | /********************** 49 | * GLOBAL PROTOTYPES 50 | **********************/ 51 | 52 | int GC9A01_init(void); 53 | void GC9A01_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 54 | void GC9A01_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); 55 | void GC9A01_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p); 56 | void GC9A01_setRotation(uint8_t m); 57 | void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); 58 | void GC9A01_fillScreen(uint16_t color); 59 | uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b); 60 | void GC9A01_invertDisplay(bool i); 61 | void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color); 62 | void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); 63 | void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t w, uint16_t color); 64 | 65 | /********************** 66 | * MACROS 67 | **********************/ 68 | 69 | #endif /* USE_GC9A01 */ 70 | 71 | #ifdef __cplusplus 72 | } /* extern "C" */ 73 | #endif 74 | 75 | #endif /* GC9A01_H */ 76 | 77 | -------------------------------------------------------------------------------- /display/ILI9341.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ILI9341.h 3 | * 4 | */ 5 | 6 | #ifndef ILI9341_H 7 | #define ILI9341_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #include 17 | #ifndef LV_DRV_NO_CONF 18 | #ifdef LV_CONF_INCLUDE_SIMPLE 19 | #include "lv_drv_conf.h" 20 | #else 21 | #include "../../lv_drv_conf.h" 22 | #endif 23 | #endif 24 | 25 | #if USE_ILI9341 26 | 27 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 28 | #include "lvgl.h" 29 | #else 30 | #include "lvgl/lvgl.h" 31 | #endif 32 | 33 | #if LV_COLOR_DEPTH != 16 34 | #error "ILI9341 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h" 35 | #endif 36 | 37 | #if LV_COLOR_16_SWAP != 1 38 | #error "ILI9341 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h" 39 | #endif 40 | 41 | /********************* 42 | * DEFINES 43 | *********************/ 44 | #define ILI9341_BGR true 45 | #define ILI9341_RGB false 46 | 47 | /********************** 48 | * TYPEDEFS 49 | **********************/ 50 | 51 | /********************** 52 | * GLOBAL PROTOTYPES 53 | **********************/ 54 | void ili9341_init(void); 55 | void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); 56 | void ili9341_rotate(int degrees, bool bgr); 57 | /********************** 58 | * MACROS 59 | **********************/ 60 | 61 | #endif /* USE_ILI9341 */ 62 | 63 | #ifdef __cplusplus 64 | } /* extern "C" */ 65 | #endif 66 | 67 | #endif /* ILI9341_H */ 68 | -------------------------------------------------------------------------------- /display/R61581.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file R61581.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "R61581.h" 10 | #if USE_R61581 != 0 11 | 12 | #include 13 | #include "lvgl/lv_core/lv_vdb.h" 14 | #include LV_DRV_DISP_INCLUDE 15 | #include LV_DRV_DELAY_INCLUDE 16 | 17 | /********************* 18 | * DEFINES 19 | *********************/ 20 | #define R61581_CMD_MODE 0 21 | #define R61581_DATA_MODE 1 22 | 23 | /********************** 24 | * TYPEDEFS 25 | **********************/ 26 | 27 | /********************** 28 | * STATIC PROTOTYPES 29 | **********************/ 30 | static void r61581_io_init(void); 31 | static void r61581_reset(void); 32 | static void r61581_set_tft_spec(void); 33 | static inline void r61581_cmd_mode(void); 34 | static inline void r61581_data_mode(void); 35 | static inline void r61581_cmd(uint8_t cmd); 36 | static inline void r61581_data(uint8_t data); 37 | 38 | /********************** 39 | * STATIC VARIABLES 40 | **********************/ 41 | static bool cmd_mode = true; 42 | 43 | /********************** 44 | * MACROS 45 | **********************/ 46 | 47 | /********************** 48 | * GLOBAL FUNCTIONS 49 | **********************/ 50 | 51 | /** 52 | * Initialize the R61581 display controller 53 | * @return HW_RES_OK or any error from hw_res_t enum 54 | */ 55 | void r61581_init(void) 56 | { 57 | r61581_io_init(); 58 | 59 | /*Slow mode until the PLL is not started in the display controller*/ 60 | LV_DRV_DISP_PAR_SLOW; 61 | 62 | r61581_reset(); 63 | 64 | r61581_set_tft_spec(); 65 | 66 | r61581_cmd(0x13); //SET display on 67 | 68 | r61581_cmd(0x29); //SET display on 69 | LV_DRV_DELAY_MS(30); 70 | 71 | /*Parallel to max speed*/ 72 | LV_DRV_DISP_PAR_FAST; 73 | } 74 | 75 | void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) 76 | { 77 | /*Return if the area is out the screen*/ 78 | if(x2 < 0) return; 79 | if(y2 < 0) return; 80 | if(x1 > R61581_HOR_RES - 1) return; 81 | if(y1 > R61581_VER_RES - 1) return; 82 | 83 | /*Truncate the area to the screen*/ 84 | int32_t act_x1 = x1 < 0 ? 0 : x1; 85 | int32_t act_y1 = y1 < 0 ? 0 : y1; 86 | int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; 87 | int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; 88 | 89 | 90 | //Set the rectangular area 91 | r61581_cmd(0x002A); 92 | r61581_data(act_x1 >> 8); 93 | r61581_data(0x00FF & act_x1); 94 | r61581_data(act_x2 >> 8); 95 | r61581_data(0x00FF & act_x2); 96 | 97 | r61581_cmd(0x002B); 98 | r61581_data(act_y1 >> 8); 99 | r61581_data(0x00FF & act_y1); 100 | r61581_data(act_y2 >> 8); 101 | r61581_data(0x00FF & act_y2); 102 | 103 | r61581_cmd(0x2c); 104 | 105 | int16_t i; 106 | uint16_t full_w = x2 - x1 + 1; 107 | 108 | r61581_data_mode(); 109 | 110 | #if LV_COLOR_DEPTH == 16 111 | uint16_t act_w = act_x2 - act_x1 + 1; 112 | for(i = act_y1; i <= act_y2; i++) { 113 | LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); 114 | color_p += full_w; 115 | } 116 | #else 117 | int16_t j; 118 | for(i = act_y1; i <= act_y2; i++) { 119 | for(j = 0; j <= act_x2 - act_x1 + 1; j++) { 120 | LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j])); 121 | color_p += full_w; 122 | } 123 | } 124 | #endif 125 | 126 | lv_flush_ready(); 127 | } 128 | 129 | void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) 130 | { 131 | /*Return if the area is out the screen*/ 132 | if(x2 < 0) return; 133 | if(y2 < 0) return; 134 | if(x1 > R61581_HOR_RES - 1) return; 135 | if(y1 > R61581_VER_RES - 1) return; 136 | 137 | /*Truncate the area to the screen*/ 138 | int32_t act_x1 = x1 < 0 ? 0 : x1; 139 | int32_t act_y1 = y1 < 0 ? 0 : y1; 140 | int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; 141 | int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; 142 | 143 | //Set the rectangular area 144 | r61581_cmd(0x002A); 145 | r61581_data(act_x1 >> 8); 146 | r61581_data(0x00FF & act_x1); 147 | r61581_data(act_x2 >> 8); 148 | r61581_data(0x00FF & act_x2); 149 | 150 | r61581_cmd(0x002B); 151 | r61581_data(act_y1 >> 8); 152 | r61581_data(0x00FF & act_y1); 153 | r61581_data(act_y2 >> 8); 154 | r61581_data(0x00FF & act_y2); 155 | 156 | r61581_cmd(0x2c); 157 | 158 | r61581_data_mode(); 159 | 160 | uint16_t color16 = lv_color_to16(color); 161 | uint32_t size = (act_x2 - act_x1 + 1) * (act_y2 - act_y1 + 1); 162 | uint32_t i; 163 | for(i = 0; i < size; i++) { 164 | LV_DRV_DISP_PAR_WR_WORD(color16); 165 | } 166 | } 167 | 168 | void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) 169 | { 170 | /*Return if the area is out the screen*/ 171 | if(x2 < 0) return; 172 | if(y2 < 0) return; 173 | if(x1 > R61581_HOR_RES - 1) return; 174 | if(y1 > R61581_VER_RES - 1) return; 175 | 176 | /*Truncate the area to the screen*/ 177 | int32_t act_x1 = x1 < 0 ? 0 : x1; 178 | int32_t act_y1 = y1 < 0 ? 0 : y1; 179 | int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; 180 | int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; 181 | 182 | 183 | //Set the rectangular area 184 | r61581_cmd(0x002A); 185 | r61581_data(act_x1 >> 8); 186 | r61581_data(0x00FF & act_x1); 187 | r61581_data(act_x2 >> 8); 188 | r61581_data(0x00FF & act_x2); 189 | 190 | r61581_cmd(0x002B); 191 | r61581_data(act_y1 >> 8); 192 | r61581_data(0x00FF & act_y1); 193 | r61581_data(act_y2 >> 8); 194 | r61581_data(0x00FF & act_y2); 195 | 196 | r61581_cmd(0x2c); 197 | 198 | int16_t i; 199 | uint16_t full_w = x2 - x1 + 1; 200 | 201 | r61581_data_mode(); 202 | 203 | #if LV_COLOR_DEPTH == 16 204 | uint16_t act_w = act_x2 - act_x1 + 1; 205 | for(i = act_y1; i <= act_y2; i++) { 206 | LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); 207 | color_p += full_w; 208 | } 209 | #else 210 | int16_t j; 211 | for(i = act_y1; i <= act_y2; i++) { 212 | for(j = 0; j <= act_x2 - act_x1 + 1; j++) { 213 | LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j])); 214 | color_p += full_w; 215 | } 216 | } 217 | #endif 218 | } 219 | 220 | /********************** 221 | * STATIC FUNCTIONS 222 | **********************/ 223 | 224 | /** 225 | * Io init 226 | */ 227 | static void r61581_io_init(void) 228 | { 229 | LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE) 230 | cmd_mode = true; 231 | } 232 | 233 | /** 234 | * Reset 235 | */ 236 | static void r61581_reset(void) 237 | { 238 | /*Hardware reset*/ 239 | LV_DRV_DISP_RST(1); 240 | LV_DRV_DELAY_MS(50); 241 | LV_DRV_DISP_RST(0); 242 | LV_DRV_DELAY_MS(50); 243 | LV_DRV_DISP_RST(1); 244 | LV_DRV_DELAY_MS(50); 245 | 246 | /*Chip enable*/ 247 | LV_DRV_DISP_PAR_CS(1); 248 | LV_DRV_DELAY_MS(10); 249 | LV_DRV_DISP_PAR_CS(0); 250 | LV_DRV_DELAY_MS(5); 251 | 252 | /*Software reset*/ 253 | r61581_cmd(0x01); 254 | LV_DRV_DELAY_MS(20); 255 | 256 | r61581_cmd(0x01); 257 | LV_DRV_DELAY_MS(20); 258 | 259 | r61581_cmd(0x01); 260 | LV_DRV_DELAY_MS(20); 261 | } 262 | 263 | /** 264 | * TFT specific initialization 265 | */ 266 | static void r61581_set_tft_spec(void) 267 | { 268 | r61581_cmd(0xB0); 269 | r61581_data(0x00); 270 | 271 | r61581_cmd(0xB3); 272 | r61581_data(0x02); 273 | r61581_data(0x00); 274 | r61581_data(0x00); 275 | r61581_data(0x10); 276 | 277 | r61581_cmd(0xB4); 278 | r61581_data(0x00);//0X10 279 | 280 | r61581_cmd(0xB9); //PWM 281 | r61581_data(0x01); 282 | r61581_data(0xFF); //FF brightness 283 | r61581_data(0xFF); 284 | r61581_data(0x18); 285 | 286 | /*Panel Driving Setting*/ 287 | r61581_cmd(0xC0); 288 | r61581_data(0x02); 289 | r61581_data(0x3B); 290 | r61581_data(0x00); 291 | r61581_data(0x00); 292 | r61581_data(0x00); 293 | r61581_data(0x01); 294 | r61581_data(0x00);//NW 295 | r61581_data(0x43); 296 | 297 | /*Display Timing Setting for Normal Mode */ 298 | r61581_cmd(0xC1); 299 | r61581_data(0x08); 300 | r61581_data(0x15); //CLOCK 301 | r61581_data(R61581_VFP); 302 | r61581_data(R61581_VBP); 303 | 304 | /*Source/VCOM/Gate Driving Timing Setting*/ 305 | r61581_cmd(0xC4); 306 | r61581_data(0x15); 307 | r61581_data(0x03); 308 | r61581_data(0x03); 309 | r61581_data(0x01); 310 | 311 | /*Interface Setting*/ 312 | r61581_cmd(0xC6); 313 | r61581_data((R61581_DPL << 0) | 314 | (R61581_EPL << 1) | 315 | (R61581_HSPL << 4) | 316 | (R61581_VSPL << 5)); 317 | 318 | /*Gamma Set*/ 319 | r61581_cmd(0xC8); 320 | r61581_data(0x0c); 321 | r61581_data(0x05); 322 | r61581_data(0x0A); 323 | r61581_data(0x6B); 324 | r61581_data(0x04); 325 | r61581_data(0x06); 326 | r61581_data(0x15); 327 | r61581_data(0x10); 328 | r61581_data(0x00); 329 | r61581_data(0x31); 330 | 331 | 332 | r61581_cmd(0x36); 333 | if(R61581_ORI == 0) r61581_data(0xE0); 334 | else r61581_data(0x20); 335 | 336 | r61581_cmd(0x0C); 337 | r61581_data(0x55); 338 | 339 | r61581_cmd(0x3A); 340 | r61581_data(0x55); 341 | 342 | r61581_cmd(0x38); 343 | 344 | r61581_cmd(0xD0); 345 | r61581_data(0x07); 346 | r61581_data(0x07); 347 | r61581_data(0x14); 348 | r61581_data(0xA2); 349 | 350 | r61581_cmd(0xD1); 351 | r61581_data(0x03); 352 | r61581_data(0x5A); 353 | r61581_data(0x10); 354 | 355 | r61581_cmd(0xD2); 356 | r61581_data(0x03); 357 | r61581_data(0x04); 358 | r61581_data(0x04); 359 | 360 | r61581_cmd(0x11); 361 | LV_DRV_DELAY_MS(10); 362 | 363 | r61581_cmd(0x2A); 364 | r61581_data(0x00); 365 | r61581_data(0x00); 366 | r61581_data(((R61581_HOR_RES - 1) >> 8) & 0XFF); 367 | r61581_data((R61581_HOR_RES - 1) & 0XFF); 368 | 369 | r61581_cmd(0x2B); 370 | r61581_data(0x00); 371 | r61581_data(0x00); 372 | r61581_data(((R61581_VER_RES - 1) >> 8) & 0XFF); 373 | r61581_data((R61581_VER_RES - 1) & 0XFF); 374 | 375 | LV_DRV_DELAY_MS(10); 376 | 377 | r61581_cmd(0x29); 378 | LV_DRV_DELAY_MS(5); 379 | 380 | r61581_cmd(0x2C); 381 | LV_DRV_DELAY_MS(5); 382 | } 383 | 384 | /** 385 | * Command mode 386 | */ 387 | static inline void r61581_cmd_mode(void) 388 | { 389 | if(cmd_mode == false) { 390 | LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE) 391 | cmd_mode = true; 392 | } 393 | } 394 | 395 | /** 396 | * Data mode 397 | */ 398 | static inline void r61581_data_mode(void) 399 | { 400 | if(cmd_mode != false) { 401 | LV_DRV_DISP_CMD_DATA(R61581_DATA_MODE); 402 | cmd_mode = false; 403 | } 404 | } 405 | 406 | /** 407 | * Write command 408 | * @param cmd the command 409 | */ 410 | static inline void r61581_cmd(uint8_t cmd) 411 | { 412 | r61581_cmd_mode(); 413 | LV_DRV_DISP_PAR_WR_WORD(cmd); 414 | } 415 | 416 | /** 417 | * Write data 418 | * @param data the data 419 | */ 420 | static inline void r61581_data(uint8_t data) 421 | { 422 | r61581_data_mode(); 423 | LV_DRV_DISP_PAR_WR_WORD(data); 424 | } 425 | #endif 426 | -------------------------------------------------------------------------------- /display/R61581.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file R61581.h 3 | * 4 | */ 5 | 6 | #ifndef R61581_H 7 | #define R61581_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_R61581 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void r61581_init(void); 44 | void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); 45 | void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); 46 | void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); 47 | /********************** 48 | * MACROS 49 | **********************/ 50 | 51 | #endif /* USE_R61581 */ 52 | 53 | #ifdef __cplusplus 54 | } /* extern "C" */ 55 | #endif 56 | 57 | #endif /* R61581_H */ 58 | -------------------------------------------------------------------------------- /display/SHARP_MIP.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SHARP_MIP.c 3 | * 4 | */ 5 | 6 | /*------------------------------------------------------------------------------------------------- 7 | * SHARP memory in pixel monochrome display series 8 | * LS012B7DD01 (184x38 pixels.) 9 | * LS013B7DH03 (128x128 pixels.) 10 | * LS013B7DH05 (144x168 pixels.) 11 | * LS027B7DH01 (400x240 pixels.) (tested) 12 | * LS032B7DD02 (336x536 pixels.) 13 | * LS044Q7DH01 (320x240 pixels.) 14 | * 15 | * These displays need periodic com inversion, there are two ways : 16 | * - software com inversion : 17 | * define SHARP_MIP_SOFT_COM_INVERSION 1 and set EXTMODE display pin LOW, 18 | * call sharp_mip_com_inversion() periodically 19 | * - hardware com inversion with EXTCOMIN display pin : 20 | * define SHARP_MIP_SOFT_COM_INVERSION 0, 21 | * set EXTMODE display pin HIGH and handle 22 | * EXTCOMIN waveform (for example with mcu pwm output), 23 | * see datasheet pages 8-12 for details 24 | * 25 | * draw_buf size : (LV_VER_RES / X) * (2 + LV_HOR_RES / 8) + 2 bytes, structure : 26 | * [FRAME_HEADER (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 1st line 27 | * [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 2nd line 28 | * ........................................................................................... 29 | * [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] last line 30 | * [DUMMY (2 bytes)] 31 | * 32 | * Since extra bytes (dummy, addresses, header) are stored in draw_buf, we need to use 33 | * an "oversized" draw_buf. Buffer declaration in "lv_port_disp.c" becomes for example : 34 | * static lv_disp_buf_t disp_buf; 35 | * static uint8_t buf[(LV_VER_RES_MAX / X) * (2 + (LV_HOR_RES_MAX / 8)) + 2]; 36 | * lv_disp_buf_init(&disp_buf, buf, NULL, LV_VER_RES_MAX * LV_HOR_RES_MAX / X); 37 | *-----------------------------------------------------------------------------------------------*/ 38 | 39 | /********************* 40 | * INCLUDES 41 | *********************/ 42 | 43 | #include "SHARP_MIP.h" 44 | 45 | #if USE_SHARP_MIP 46 | 47 | #include 48 | #include LV_DRV_DISP_INCLUDE 49 | #include LV_DRV_DELAY_INCLUDE 50 | 51 | /********************* 52 | * DEFINES 53 | *********************/ 54 | 55 | #define SHARP_MIP_HEADER 0 56 | #define SHARP_MIP_UPDATE_RAM_FLAG (1 << 7) /* (M0) Mode flag : H -> update memory, L -> maintain memory */ 57 | #define SHARP_MIP_COM_INVERSION_FLAG (1 << 6) /* (M1) Frame inversion flag : relevant when EXTMODE = L, */ 58 | /* H -> outputs VCOM = H, L -> outputs VCOM = L */ 59 | #define SHARP_MIP_CLEAR_SCREEN_FLAG (1 << 5) /* (M2) All clear flag : H -> clear all pixels */ 60 | 61 | /********************** 62 | * TYPEDEFS 63 | **********************/ 64 | 65 | /********************** 66 | * STATIC PROTOTYPES 67 | **********************/ 68 | 69 | /********************** 70 | * STATIC VARIABLES 71 | **********************/ 72 | 73 | #if SHARP_MIP_SOFT_COM_INVERSION 74 | static bool_t com_output_state = false; 75 | #endif 76 | 77 | /********************** 78 | * MACROS 79 | **********************/ 80 | 81 | /* 82 | * Return the draw_buf byte index corresponding to the pixel 83 | * relatives coordinates (x, y) in the area. 84 | * The area is rounded to a whole screen line. 85 | */ 86 | #define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (SHARP_MIP_HOR_RES >> 3))) + 2) 87 | 88 | /* 89 | * Return the byte bitmask of a pixel bit corresponding 90 | * to draw_buf arrangement (8 pixels per byte on lines). 91 | */ 92 | #define PIXIDX(x) SHARP_MIP_REV_BYTE(1 << ((x) & 7)) 93 | 94 | /********************** 95 | * GLOBAL FUNCTIONS 96 | **********************/ 97 | 98 | void sharp_mip_init(void) { 99 | /* These displays have nothing to initialize */ 100 | } 101 | 102 | 103 | void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { 104 | 105 | /*Return if the area is out the screen*/ 106 | if(area->y2 < 0) return; 107 | if(area->y1 > SHARP_MIP_VER_RES - 1) return; 108 | 109 | /*Truncate the area to the screen*/ 110 | uint16_t act_y1 = area->y1 < 0 ? 0 : area->y1; 111 | uint16_t act_y2 = area->y2 > SHARP_MIP_VER_RES - 1 ? SHARP_MIP_VER_RES - 1 : area->y2; 112 | 113 | uint8_t * buf = (uint8_t *) color_p; /*Get the buffer address*/ 114 | uint16_t buf_h = (act_y2 - act_y1 + 1); /*Number of buffer lines*/ 115 | uint16_t buf_size = buf_h * (2 + SHARP_MIP_HOR_RES / 8) + 2; /*Buffer size in bytes */ 116 | 117 | /* Set lines to flush dummy byte & gate address in draw_buf*/ 118 | for(uint16_t act_y = 0 ; act_y < buf_h ; act_y++) { 119 | buf[BUFIDX(0, act_y) - 1] = SHARP_MIP_REV_BYTE((act_y1 + act_y + 1)); 120 | buf[BUFIDX(0, act_y) - 2] = 0; 121 | } 122 | 123 | /* Set last dummy two bytes in draw_buf */ 124 | buf[BUFIDX(0, buf_h) - 1] = 0; 125 | buf[BUFIDX(0, buf_h) - 2] = 0; 126 | 127 | /* Set frame header in draw_buf */ 128 | buf[0] = SHARP_MIP_HEADER | 129 | SHARP_MIP_UPDATE_RAM_FLAG; 130 | 131 | /* Write the frame on display memory */ 132 | LV_DRV_DISP_SPI_CS(1); 133 | LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size); 134 | LV_DRV_DISP_SPI_CS(0); 135 | 136 | lv_disp_flush_ready(disp_drv); 137 | } 138 | 139 | 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) { 140 | (void) disp_drv; 141 | (void) buf_w; 142 | (void) opa; 143 | 144 | if (lv_color_to1(color) != 0) { 145 | buf[BUFIDX(x, y)] |= PIXIDX(x); /*Set draw_buf pixel bit to 1 for other colors than BLACK*/ 146 | } else { 147 | buf[BUFIDX(x, y)] &= ~PIXIDX(x); /*Set draw_buf pixel bit to 0 for BLACK color*/ 148 | } 149 | } 150 | 151 | void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) { 152 | (void) disp_drv; 153 | 154 | /* Round area to a whole line */ 155 | area->x1 = 0; 156 | area->x2 = SHARP_MIP_HOR_RES - 1; 157 | } 158 | 159 | #if SHARP_MIP_SOFT_COM_INVERSION 160 | void sharp_mip_com_inversion(void) { 161 | uint8_t inversion_header[2] = {0}; 162 | 163 | /* Set inversion header */ 164 | if (com_output_state) { 165 | com_output_state = false; 166 | } else { 167 | inversion_header[0] |= SHARP_MIP_COM_INVERSION_FLAG; 168 | com_output_state = true; 169 | } 170 | 171 | /* Write inversion header on display memory */ 172 | LV_DRV_DISP_SPI_CS(1); 173 | LV_DRV_DISP_SPI_WR_ARRAY(inversion_header, 2); 174 | LV_DRV_DISP_SPI_CS(0); 175 | } 176 | #endif 177 | 178 | /********************** 179 | * STATIC FUNCTIONS 180 | **********************/ 181 | 182 | #endif 183 | -------------------------------------------------------------------------------- /display/SHARP_MIP.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SHARP_MIP.h 3 | * 4 | */ 5 | 6 | #ifndef SHARP_MIP_H 7 | #define SHARP_MIP_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | 17 | #ifndef LV_DRV_NO_CONF 18 | #ifdef LV_CONF_INCLUDE_SIMPLE 19 | #include "lv_drv_conf.h" 20 | #else 21 | #include "../../lv_drv_conf.h" 22 | #endif 23 | #endif 24 | 25 | #if USE_SHARP_MIP 26 | 27 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 28 | #include "lvgl.h" 29 | #else 30 | #include "lvgl/lvgl.h" 31 | #endif 32 | 33 | 34 | /********************* 35 | * DEFINES 36 | *********************/ 37 | 38 | /********************** 39 | * TYPEDEFS 40 | **********************/ 41 | 42 | /********************** 43 | * GLOBAL PROTOTYPES 44 | **********************/ 45 | void sharp_mip_init(void); 46 | void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 47 | void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area); 48 | 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); 49 | #if SHARP_MIP_SOFT_COM_INVERSION 50 | void sharp_mip_com_inversion(void); 51 | #endif 52 | 53 | /********************** 54 | * MACROS 55 | **********************/ 56 | 57 | #endif /* USE_SHARP_MIP */ 58 | 59 | #ifdef __cplusplus 60 | } /* extern "C" */ 61 | #endif 62 | 63 | #endif /* SHARP_MIP_H */ 64 | -------------------------------------------------------------------------------- /display/SSD1963.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SSD1963.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "SSD1963.h" 10 | #if USE_SSD1963 11 | 12 | #include 13 | #include LV_DRV_DISP_INCLUDE 14 | #include LV_DRV_DELAY_INCLUDE 15 | 16 | /********************* 17 | * DEFINES 18 | *********************/ 19 | #define SSD1963_CMD_MODE 0 20 | #define SSD1963_DATA_MODE 1 21 | 22 | /********************** 23 | * TYPEDEFS 24 | **********************/ 25 | 26 | /********************** 27 | * STATIC PROTOTYPES 28 | **********************/ 29 | static inline void ssd1963_cmd_mode(void); 30 | static inline void ssd1963_data_mode(void); 31 | static inline void ssd1963_cmd(uint8_t cmd); 32 | static inline void ssd1963_data(uint8_t data); 33 | static void ssd1963_io_init(void); 34 | static void ssd1963_reset(void); 35 | static void ssd1963_set_clk(void); 36 | static void ssd1963_set_tft_spec(void); 37 | static void ssd1963_init_bl(void); 38 | 39 | /********************** 40 | * STATIC VARIABLES 41 | **********************/ 42 | static bool cmd_mode = true; 43 | 44 | /********************** 45 | * MACROS 46 | **********************/ 47 | 48 | /********************** 49 | * GLOBAL FUNCTIONS 50 | **********************/ 51 | 52 | void ssd1963_init(void) 53 | { 54 | 55 | LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); 56 | cmd_mode = true; 57 | 58 | LV_DRV_DELAY_MS(250); 59 | 60 | 61 | ssd1963_cmd(0x00E2); //PLL multiplier, set PLL clock to 120M 62 | ssd1963_data(0x0023); //N=0x36 for 6.5M, 0x23 for 10M crystal 63 | ssd1963_data(0x0002); 64 | ssd1963_data(0x0004); 65 | ssd1963_cmd(0x00E0); // PLL enable 66 | ssd1963_data(0x0001); 67 | LV_DRV_DELAY_MS(1); 68 | ssd1963_cmd(0x00E0); 69 | ssd1963_data(0x0003); // now, use PLL output as system clock 70 | LV_DRV_DELAY_MS(1); 71 | ssd1963_cmd(0x0001); // software reset 72 | LV_DRV_DELAY_MS(1); 73 | ssd1963_cmd(0x00E6); //PLL setting for PCLK, depends on resolution 74 | 75 | ssd1963_data(0x0001); //HX8257C 76 | ssd1963_data(0x0033); //HX8257C 77 | ssd1963_data(0x0033); //HX8257C 78 | 79 | 80 | ssd1963_cmd(0x00B0); //LCD SPECIFICATION 81 | ssd1963_data(0x0020); 82 | ssd1963_data(0x0000); 83 | ssd1963_data(((SSD1963_HOR_RES - 1) >> 8) & 0X00FF); //Set HDP 84 | ssd1963_data((SSD1963_HOR_RES - 1) & 0X00FF); 85 | ssd1963_data(((SSD1963_VER_RES - 1) >> 8) & 0X00FF); //Set VDP 86 | ssd1963_data((SSD1963_VER_RES - 1) & 0X00FF); 87 | ssd1963_data(0x0000); 88 | LV_DRV_DELAY_MS(1);//Delay10us(5); 89 | ssd1963_cmd(0x00B4); //HSYNC 90 | ssd1963_data((SSD1963_HT >> 8) & 0X00FF); //Set HT 91 | ssd1963_data(SSD1963_HT & 0X00FF); 92 | ssd1963_data((SSD1963_HPS >> 8) & 0X00FF); //Set HPS 93 | ssd1963_data(SSD1963_HPS & 0X00FF); 94 | ssd1963_data(SSD1963_HPW); //Set HPW 95 | ssd1963_data((SSD1963_LPS >> 8) & 0X00FF); //SetLPS 96 | ssd1963_data(SSD1963_LPS & 0X00FF); 97 | ssd1963_data(0x0000); 98 | 99 | ssd1963_cmd(0x00B6); //VSYNC 100 | ssd1963_data((SSD1963_VT >> 8) & 0X00FF); //Set VT 101 | ssd1963_data(SSD1963_VT & 0X00FF); 102 | ssd1963_data((SSD1963_VPS >> 8) & 0X00FF); //Set VPS 103 | ssd1963_data(SSD1963_VPS & 0X00FF); 104 | ssd1963_data(SSD1963_VPW); //Set VPW 105 | ssd1963_data((SSD1963_FPS >> 8) & 0X00FF); //Set FPS 106 | ssd1963_data(SSD1963_FPS & 0X00FF); 107 | 108 | ssd1963_cmd(0x00B8); 109 | ssd1963_data(0x000f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF 110 | ssd1963_data(0x0001); //GPIO0 normal 111 | 112 | ssd1963_cmd(0x00BA); 113 | ssd1963_data(0x0001); //GPIO[0] out 1 --- LCD display on/off control PIN 114 | 115 | ssd1963_cmd(0x0036); //rotation 116 | ssd1963_data(0x0008); //RGB=BGR 117 | 118 | ssd1963_cmd(0x003A); //Set the current pixel format for RGB image data 119 | ssd1963_data(0x0050); //16-bit/pixel 120 | 121 | ssd1963_cmd(0x00F0); //Pixel Data Interface Format 122 | ssd1963_data(0x0003); //16-bit(565 format) data 123 | 124 | ssd1963_cmd(0x00BC); 125 | ssd1963_data(0x0040); //contrast value 126 | ssd1963_data(0x0080); //brightness value 127 | ssd1963_data(0x0040); //saturation value 128 | ssd1963_data(0x0001); //Post Processor Enable 129 | 130 | LV_DRV_DELAY_MS(1); 131 | 132 | ssd1963_cmd(0x0029); //display on 133 | 134 | ssd1963_cmd(0x00BE); //set PWM for B/L 135 | ssd1963_data(0x0006); 136 | ssd1963_data(0x0080); 137 | ssd1963_data(0x0001); 138 | ssd1963_data(0x00f0); 139 | ssd1963_data(0x0000); 140 | ssd1963_data(0x0000); 141 | 142 | ssd1963_cmd(0x00d0); 143 | ssd1963_data(0x000d); 144 | 145 | //DisplayBacklightOn(); 146 | 147 | LV_DRV_DELAY_MS(30); 148 | } 149 | 150 | void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) 151 | { 152 | 153 | /*Return if the area is out the screen*/ 154 | if(area->x2 < 0) return; 155 | if(area->y2 < 0) return; 156 | if(area->x1 > SSD1963_HOR_RES - 1) return; 157 | if(area->y1 > SSD1963_VER_RES - 1) return; 158 | 159 | /*Truncate the area to the screen*/ 160 | int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; 161 | int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; 162 | int32_t act_x2 = area->x2 > SSD1963_HOR_RES - 1 ? SSD1963_HOR_RES - 1 : area->x2; 163 | int32_t act_y2 = area->y2 > SSD1963_VER_RES - 1 ? SSD1963_VER_RES - 1 : area->y2; 164 | 165 | //Set the rectangular area 166 | ssd1963_cmd(0x002A); 167 | ssd1963_data(act_x1 >> 8); 168 | ssd1963_data(0x00FF & act_x1); 169 | ssd1963_data(act_x2 >> 8); 170 | ssd1963_data(0x00FF & act_x2); 171 | 172 | ssd1963_cmd(0x002B); 173 | ssd1963_data(act_y1 >> 8); 174 | ssd1963_data(0x00FF & act_y1); 175 | ssd1963_data(act_y2 >> 8); 176 | ssd1963_data(0x00FF & act_y2); 177 | 178 | ssd1963_cmd(0x2c); 179 | int16_t i; 180 | uint16_t full_w = area->x2 - area->x1 + 1; 181 | 182 | ssd1963_data_mode(); 183 | LV_DRV_DISP_PAR_CS(0); 184 | #if LV_COLOR_DEPTH == 16 185 | uint16_t act_w = act_x2 - act_x1 + 1; 186 | for(i = act_y1; i <= act_y2; i++) { 187 | LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); 188 | color_p += full_w; 189 | } 190 | LV_DRV_DISP_PAR_CS(1); 191 | #else 192 | int16_t j; 193 | for(i = act_y1; i <= act_y2; i++) { 194 | for(j = 0; j <= act_x2 - act_x1 + 1; j++) { 195 | LV_DRV_DISP_PAR_WR_WORD(color_p[j]); 196 | color_p += full_w; 197 | } 198 | } 199 | #endif 200 | 201 | lv_disp_flush_ready(disp_drv); 202 | } 203 | 204 | /********************** 205 | * STATIC FUNCTIONS 206 | **********************/ 207 | 208 | static void ssd1963_io_init(void) 209 | { 210 | LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); 211 | cmd_mode = true; 212 | } 213 | 214 | static void ssd1963_reset(void) 215 | { 216 | /*Hardware reset*/ 217 | LV_DRV_DISP_RST(1); 218 | LV_DRV_DELAY_MS(50); 219 | LV_DRV_DISP_RST(0); 220 | LV_DRV_DELAY_MS(50); 221 | LV_DRV_DISP_RST(1); 222 | LV_DRV_DELAY_MS(50); 223 | 224 | /*Chip enable*/ 225 | LV_DRV_DISP_PAR_CS(0); 226 | LV_DRV_DELAY_MS(10); 227 | LV_DRV_DISP_PAR_CS(1); 228 | LV_DRV_DELAY_MS(5); 229 | 230 | /*Software reset*/ 231 | ssd1963_cmd(0x01); 232 | LV_DRV_DELAY_MS(20); 233 | 234 | ssd1963_cmd(0x01); 235 | LV_DRV_DELAY_MS(20); 236 | 237 | ssd1963_cmd(0x01); 238 | LV_DRV_DELAY_MS(20); 239 | 240 | } 241 | 242 | /** 243 | * Command mode 244 | */ 245 | static inline void ssd1963_cmd_mode(void) 246 | { 247 | if(cmd_mode == false) { 248 | LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); 249 | cmd_mode = true; 250 | } 251 | } 252 | 253 | /** 254 | * Data mode 255 | */ 256 | static inline void ssd1963_data_mode(void) 257 | { 258 | if(cmd_mode != false) { 259 | LV_DRV_DISP_CMD_DATA(SSD1963_DATA_MODE); 260 | cmd_mode = false; 261 | } 262 | } 263 | 264 | /** 265 | * Write command 266 | * @param cmd the command 267 | */ 268 | static inline void ssd1963_cmd(uint8_t cmd) 269 | { 270 | 271 | LV_DRV_DISP_PAR_CS(0); 272 | ssd1963_cmd_mode(); 273 | LV_DRV_DISP_PAR_WR_WORD(cmd); 274 | LV_DRV_DISP_PAR_CS(1); 275 | 276 | } 277 | 278 | /** 279 | * Write data 280 | * @param data the data 281 | */ 282 | static inline void ssd1963_data(uint8_t data) 283 | { 284 | 285 | LV_DRV_DISP_PAR_CS(0); 286 | ssd1963_data_mode(); 287 | LV_DRV_DISP_PAR_WR_WORD(data); 288 | LV_DRV_DISP_PAR_CS(1); 289 | 290 | } 291 | 292 | #endif 293 | -------------------------------------------------------------------------------- /display/SSD1963.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SSD1963.h 3 | * 4 | */ 5 | 6 | #ifndef SSD1963_H 7 | #define SSD1963_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_SSD1963 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | // SSD1963 command table 36 | #define CMD_NOP 0x00 //No operation 37 | #define CMD_SOFT_RESET 0x01 //Software reset 38 | #define CMD_GET_PWR_MODE 0x0A //Get the current power mode 39 | #define CMD_GET_ADDR_MODE 0x0B //Get the frame memory to the display panel read order 40 | #define CMD_GET_PIXEL_FORMAT 0x0C //Get the current pixel format 41 | #define CMD_GET_DISPLAY_MODE 0x0D //Returns the display mode 42 | #define CMD_GET_SIGNAL_MODE 0x0E // 43 | #define CMD_GET_DIAGNOSTIC 0x0F 44 | #define CMD_ENT_SLEEP 0x10 45 | #define CMD_EXIT_SLEEP 0x11 46 | #define CMD_ENT_PARTIAL_MODE 0x12 47 | #define CMD_ENT_NORMAL_MODE 0x13 48 | #define CMD_EXIT_INVERT_MODE 0x20 49 | #define CMD_ENT_INVERT_MODE 0x21 50 | #define CMD_SET_GAMMA 0x26 51 | #define CMD_BLANK_DISPLAY 0x28 52 | #define CMD_ON_DISPLAY 0x29 53 | #define CMD_SET_COLUMN 0x2A 54 | #define CMD_SET_PAGE 0x2B 55 | #define CMD_WR_MEMSTART 0x2C 56 | #define CMD_RD_MEMSTART 0x2E 57 | #define CMD_SET_PARTIAL_AREA 0x30 58 | #define CMD_SET_SCROLL_AREA 0x33 59 | #define CMD_SET_TEAR_OFF 0x34 //synchronization information is not sent from the display 60 | #define CMD_SET_TEAR_ON 0x35 //sync. information is sent from the display 61 | #define CMD_SET_ADDR_MODE 0x36 //set fram buffer read order to the display panel 62 | #define CMD_SET_SCROLL_START 0x37 63 | #define CMD_EXIT_IDLE_MODE 0x38 64 | #define CMD_ENT_IDLE_MODE 0x39 65 | #define CMD_SET_PIXEL_FORMAT 0x3A //defines how many bits per pixel is used 66 | #define CMD_WR_MEM_AUTO 0x3C 67 | #define CMD_RD_MEM_AUTO 0x3E 68 | #define CMD_SET_TEAR_SCANLINE 0x44 69 | #define CMD_GET_SCANLINE 0x45 70 | #define CMD_RD_DDB_START 0xA1 71 | #define CMD_RD_DDB_AUTO 0xA8 72 | #define CMD_SET_PANEL_MODE 0xB0 73 | #define CMD_GET_PANEL_MODE 0xB1 74 | #define CMD_SET_HOR_PERIOD 0xB4 75 | #define CMD_GET_HOR_PERIOD 0xB5 76 | #define CMD_SET_VER_PERIOD 0xB6 77 | #define CMD_GET_VER_PERIOD 0xB7 78 | #define CMD_SET_GPIO_CONF 0xB8 79 | #define CMD_GET_GPIO_CONF 0xB9 80 | #define CMD_SET_GPIO_VAL 0xBA 81 | #define CMD_GET_GPIO_STATUS 0xBB 82 | #define CMD_SET_POST_PROC 0xBC 83 | #define CMD_GET_POST_PROC 0xBD 84 | #define CMD_SET_PWM_CONF 0xBE 85 | #define CMD_GET_PWM_CONF 0xBF 86 | #define CMD_SET_LCD_GEN0 0xC0 87 | #define CMD_GET_LCD_GEN0 0xC1 88 | #define CMD_SET_LCD_GEN1 0xC2 89 | #define CMD_GET_LCD_GEN1 0xC3 90 | #define CMD_SET_LCD_GEN2 0xC4 91 | #define CMD_GET_LCD_GEN2 0xC5 92 | #define CMD_SET_LCD_GEN3 0xC6 93 | #define CMD_GET_LCD_GEN3 0xC7 94 | #define CMD_SET_GPIO0_ROP 0xC8 95 | #define CMD_GET_GPIO0_ROP 0xC9 96 | #define CMD_SET_GPIO1_ROP 0xCA 97 | #define CMD_GET_GPIO1_ROP 0xCB 98 | #define CMD_SET_GPIO2_ROP 0xCC 99 | #define CMD_GET_GPIO2_ROP 0xCD 100 | #define CMD_SET_GPIO3_ROP 0xCE 101 | #define CMD_GET_GPIO3_ROP 0xCF 102 | #define CMD_SET_ABC_DBC_CONF 0xD0 103 | #define CMD_GET_ABC_DBC_CONF 0xD1 104 | #define CMD_SET_DBC_HISTO_PTR 0xD2 105 | #define CMD_GET_DBC_HISTO_PTR 0xD3 106 | #define CMD_SET_DBC_THRES 0xD4 107 | #define CMD_GET_DBC_THRES 0xD5 108 | #define CMD_SET_ABM_TMR 0xD6 109 | #define CMD_GET_ABM_TMR 0xD7 110 | #define CMD_SET_AMB_LVL0 0xD8 111 | #define CMD_GET_AMB_LVL0 0xD9 112 | #define CMD_SET_AMB_LVL1 0xDA 113 | #define CMD_GET_AMB_LVL1 0xDB 114 | #define CMD_SET_AMB_LVL2 0xDC 115 | #define CMD_GET_AMB_LVL2 0xDD 116 | #define CMD_SET_AMB_LVL3 0xDE 117 | #define CMD_GET_AMB_LVL3 0xDF 118 | #define CMD_PLL_START 0xE0 //start the PLL 119 | #define CMD_PLL_STOP 0xE1 //disable the PLL 120 | #define CMD_SET_PLL_MN 0xE2 121 | #define CMD_GET_PLL_MN 0xE3 122 | #define CMD_GET_PLL_STATUS 0xE4 //get the current PLL status 123 | #define CMD_ENT_DEEP_SLEEP 0xE5 124 | #define CMD_SET_PCLK 0xE6 //set pixel clock (LSHIFT signal) frequency 125 | #define CMD_GET_PCLK 0xE7 //get pixel clock (LSHIFT signal) freq. settings 126 | #define CMD_SET_DATA_INTERFACE 0xF0 127 | #define CMD_GET_DATA_INTERFACE 0xF1 128 | 129 | 130 | /********************** 131 | * TYPEDEFS 132 | **********************/ 133 | 134 | /********************** 135 | * GLOBAL PROTOTYPES 136 | **********************/ 137 | void ssd1963_init(void); 138 | void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 139 | 140 | /********************** 141 | * MACROS 142 | **********************/ 143 | 144 | #endif /* USE_SSD1963 */ 145 | 146 | #ifdef __cplusplus 147 | } /* extern "C" */ 148 | #endif 149 | 150 | #endif /* SSD1963_H */ 151 | -------------------------------------------------------------------------------- /display/ST7565.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ST7565.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "ST7565.h" 10 | #if USE_ST7565 11 | 12 | #include 13 | #include 14 | #include 15 | #include "lvgl/lv_core/lv_vdb.h" 16 | #include LV_DRV_DISP_INCLUDE 17 | #include LV_DRV_DELAY_INCLUDE 18 | 19 | /********************* 20 | * DEFINES 21 | *********************/ 22 | #define ST7565_BAUD 2000000 /*< 2,5 MHz (400 ns)*/ 23 | 24 | #define ST7565_CMD_MODE 0 25 | #define ST7565_DATA_MODE 1 26 | 27 | #define ST7565_HOR_RES 128 28 | #define ST7565_VER_RES 64 29 | 30 | #define CMD_DISPLAY_OFF 0xAE 31 | #define CMD_DISPLAY_ON 0xAF 32 | 33 | #define CMD_SET_DISP_START_LINE 0x40 34 | #define CMD_SET_PAGE 0xB0 35 | 36 | #define CMD_SET_COLUMN_UPPER 0x10 37 | #define CMD_SET_COLUMN_LOWER 0x00 38 | 39 | #define CMD_SET_ADC_NORMAL 0xA0 40 | #define CMD_SET_ADC_REVERSE 0xA1 41 | 42 | #define CMD_SET_DISP_NORMAL 0xA6 43 | #define CMD_SET_DISP_REVERSE 0xA7 44 | 45 | #define CMD_SET_ALLPTS_NORMAL 0xA4 46 | #define CMD_SET_ALLPTS_ON 0xA5 47 | #define CMD_SET_BIAS_9 0xA2 48 | #define CMD_SET_BIAS_7 0xA3 49 | 50 | #define CMD_RMW 0xE0 51 | #define CMD_RMW_CLEAR 0xEE 52 | #define CMD_INTERNAL_RESET 0xE2 53 | #define CMD_SET_COM_NORMAL 0xC0 54 | #define CMD_SET_COM_REVERSE 0xC8 55 | #define CMD_SET_POWER_CONTROL 0x28 56 | #define CMD_SET_RESISTOR_RATIO 0x20 57 | #define CMD_SET_VOLUME_FIRST 0x81 58 | #define CMD_SET_VOLUME_SECOND 0x00 59 | #define CMD_SET_STATIC_OFF 0xAC 60 | #define CMD_SET_STATIC_ON 0xAD 61 | #define CMD_SET_STATIC_REG 0x00 62 | #define CMD_SET_BOOSTER_FIRST 0xF8 63 | #define CMD_SET_BOOSTER_234 0x00 64 | #define CMD_SET_BOOSTER_5 0x01 65 | #define CMD_SET_BOOSTER_6 0x03 66 | #define CMD_NOP 0xE3 67 | #define CMD_TEST 0xF0 68 | 69 | /********************** 70 | * TYPEDEFS 71 | **********************/ 72 | 73 | /********************** 74 | * STATIC PROTOTYPES 75 | **********************/ 76 | static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2); 77 | static void st7565_command(uint8_t cmd); 78 | static void st7565_data(uint8_t data); 79 | 80 | /********************** 81 | * STATIC VARIABLES 82 | **********************/ 83 | static uint8_t lcd_fb[ST7565_HOR_RES * ST7565_VER_RES / 8] = {0xAA, 0xAA}; 84 | static uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 }; 85 | 86 | /********************** 87 | * MACROS 88 | **********************/ 89 | 90 | /********************** 91 | * GLOBAL FUNCTIONS 92 | **********************/ 93 | 94 | /** 95 | * Initialize the ST7565 96 | */ 97 | void st7565_init(void) 98 | { 99 | LV_DRV_DISP_RST(1); 100 | LV_DRV_DELAY_MS(10); 101 | LV_DRV_DISP_RST(0); 102 | LV_DRV_DELAY_MS(10); 103 | LV_DRV_DISP_RST(1); 104 | LV_DRV_DELAY_MS(10); 105 | 106 | LV_DRV_DISP_SPI_CS(0); 107 | 108 | st7565_command(CMD_SET_BIAS_7); 109 | st7565_command(CMD_SET_ADC_NORMAL); 110 | st7565_command(CMD_SET_COM_NORMAL); 111 | st7565_command(CMD_SET_DISP_START_LINE); 112 | st7565_command(CMD_SET_POWER_CONTROL | 0x4); 113 | LV_DRV_DELAY_MS(50); 114 | 115 | st7565_command(CMD_SET_POWER_CONTROL | 0x6); 116 | LV_DRV_DELAY_MS(50); 117 | 118 | st7565_command(CMD_SET_POWER_CONTROL | 0x7); 119 | LV_DRV_DELAY_MS(10); 120 | 121 | st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); // Defaulted to 0x26 (but could also be between 0x20-0x27 based on display's specs) 122 | 123 | st7565_command(CMD_DISPLAY_ON); 124 | st7565_command(CMD_SET_ALLPTS_NORMAL); 125 | 126 | /*Set brightness*/ 127 | st7565_command(CMD_SET_VOLUME_FIRST); 128 | st7565_command(CMD_SET_VOLUME_SECOND | (0x18 & 0x3f)); 129 | 130 | LV_DRV_DISP_SPI_CS(1); 131 | 132 | memset(lcd_fb, 0x00, sizeof(lcd_fb)); 133 | } 134 | 135 | 136 | void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) 137 | { 138 | /*Return if the area is out the screen*/ 139 | if(x2 < 0) return; 140 | if(y2 < 0) return; 141 | if(x1 > ST7565_HOR_RES - 1) return; 142 | if(y1 > ST7565_VER_RES - 1) return; 143 | 144 | /*Truncate the area to the screen*/ 145 | int32_t act_x1 = x1 < 0 ? 0 : x1; 146 | int32_t act_y1 = y1 < 0 ? 0 : y1; 147 | int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; 148 | int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; 149 | 150 | int32_t x, y; 151 | 152 | /*Set the first row in */ 153 | 154 | /*Refresh frame buffer*/ 155 | for(y = act_y1; y <= act_y2; y++) { 156 | for(x = act_x1; x <= act_x2; x++) { 157 | if(lv_color_to1(*color_p) != 0) { 158 | lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); 159 | } else { 160 | lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); 161 | } 162 | color_p ++; 163 | } 164 | 165 | color_p += x2 - act_x2; /*Next row*/ 166 | } 167 | 168 | st7565_sync(act_x1, act_y1, act_x2, act_y2); 169 | lv_flush_ready(); 170 | } 171 | 172 | 173 | 174 | void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) 175 | { 176 | /*Return if the area is out the screen*/ 177 | if(x2 < 0) return; 178 | if(y2 < 0) return; 179 | if(x1 > ST7565_HOR_RES - 1) return; 180 | if(y1 > ST7565_VER_RES - 1) return; 181 | 182 | /*Truncate the area to the screen*/ 183 | int32_t act_x1 = x1 < 0 ? 0 : x1; 184 | int32_t act_y1 = y1 < 0 ? 0 : y1; 185 | int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; 186 | int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; 187 | 188 | int32_t x, y; 189 | uint8_t white = lv_color_to1(color); 190 | 191 | /*Refresh frame buffer*/ 192 | for(y = act_y1; y <= act_y2; y++) { 193 | for(x = act_x1; x <= act_x2; x++) { 194 | if(white != 0) { 195 | lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); 196 | } else { 197 | lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); 198 | } 199 | } 200 | } 201 | 202 | st7565_sync(act_x1, act_y1, act_x2, act_y2); 203 | } 204 | 205 | void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) 206 | { 207 | /*Return if the area is out the screen*/ 208 | if(x2 < 0) return; 209 | if(y2 < 0) return; 210 | if(x1 > ST7565_HOR_RES - 1) return; 211 | if(y1 > ST7565_VER_RES - 1) return; 212 | 213 | /*Truncate the area to the screen*/ 214 | int32_t act_x1 = x1 < 0 ? 0 : x1; 215 | int32_t act_y1 = y1 < 0 ? 0 : y1; 216 | int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; 217 | int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; 218 | 219 | int32_t x, y; 220 | 221 | /*Set the first row in */ 222 | 223 | /*Refresh frame buffer*/ 224 | for(y = act_y1; y <= act_y2; y++) { 225 | for(x = act_x1; x <= act_x2; x++) { 226 | if(lv_color_to1(*color_p) != 0) { 227 | lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); 228 | } else { 229 | lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); 230 | } 231 | color_p ++; 232 | } 233 | 234 | color_p += x2 - act_x2; /*Next row*/ 235 | } 236 | 237 | st7565_sync(act_x1, act_y1, act_x2, act_y2); 238 | } 239 | /********************** 240 | * STATIC FUNCTIONS 241 | **********************/ 242 | /** 243 | * Flush a specific part of the buffer to the display 244 | * @param x1 left coordinate of the area to flush 245 | * @param y1 top coordinate of the area to flush 246 | * @param x2 right coordinate of the area to flush 247 | * @param y2 bottom coordinate of the area to flush 248 | */ 249 | static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2) 250 | { 251 | 252 | LV_DRV_DISP_SPI_CS(0); 253 | 254 | uint8_t c, p; 255 | for(p = y1 / 8; p <= y2 / 8; p++) { 256 | st7565_command(CMD_SET_PAGE | pagemap[p]); 257 | st7565_command(CMD_SET_COLUMN_LOWER | (x1 & 0xf)); 258 | st7565_command(CMD_SET_COLUMN_UPPER | ((x1 >> 4) & 0xf)); 259 | st7565_command(CMD_RMW); 260 | 261 | for(c = x1; c <= x2; c++) { 262 | st7565_data(lcd_fb[(ST7565_HOR_RES * p) + c]); 263 | } 264 | } 265 | 266 | LV_DRV_DISP_SPI_CS(1); 267 | } 268 | 269 | /** 270 | * Write a command to the ST7565 271 | * @param cmd the command 272 | */ 273 | static void st7565_command(uint8_t cmd) 274 | { 275 | LV_DRV_DISP_CMD_DATA(ST7565_CMD_MODE); 276 | LV_DRV_DISP_SPI_WR_BYTE(cmd); 277 | } 278 | 279 | /** 280 | * Write data to the ST7565 281 | * @param data the data 282 | */ 283 | static void st7565_data(uint8_t data) 284 | { 285 | LV_DRV_DISP_CMD_DATA(ST7565_DATA_MODE); 286 | LV_DRV_DISP_SPI_WR_BYTE(data); 287 | } 288 | 289 | #endif 290 | -------------------------------------------------------------------------------- /display/ST7565.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ST7565.h 3 | * 4 | */ 5 | 6 | #ifndef ST7565_H 7 | #define ST7565_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_ST7565 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void st7565_init(void); 44 | void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); 45 | void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); 46 | void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); 47 | 48 | /********************** 49 | * MACROS 50 | **********************/ 51 | 52 | #endif /* USE_ST7565 */ 53 | 54 | #ifdef __cplusplus 55 | } /* extern "C" */ 56 | #endif 57 | 58 | #endif /* ST7565_H */ 59 | -------------------------------------------------------------------------------- /display/UC1610.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file UC1610.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "UC1610.h" 10 | 11 | #if USE_UC1610 12 | 13 | #include 14 | #include LV_DRV_DISP_INCLUDE 15 | #include LV_DRV_DELAY_INCLUDE 16 | 17 | /********************* 18 | * DEFINES 19 | *********************/ 20 | #define UC1610_CMD_MODE 0 21 | #define UC1610_DATA_MODE 1 22 | #define UC1610_RESET_MODE 0 23 | #define UC1610_SET_MODE 1 24 | 25 | /* hardware control commands */ 26 | #define UC1610_SYSTEM_RESET 0xE2 /* software reset */ 27 | #define UC1610_NOP 0xE3 28 | #define UC1610_SET_TEMP_COMP 0x24 /* set temperature compensation, default -0.05%/°C */ 29 | #define UC1610_SET_PANEL_LOADING 0x29 /* set panel loading, default 16~21 nF */ 30 | #define UC1610_SET_PUMP_CONTROL 0x2F /* default internal Vlcd (8x pump) */ 31 | #define UC1610_SET_LCD_BIAS_RATIO 0xEB /* default 11 */ 32 | #define UC1610_SET_VBIAS_POT 0x81 /* 1 byte (0~255) to follow setting the contrast, default 0x81 */ 33 | #define UC1610_SET_LINE_RATE 0xA0 /* default 12,1 Klps */ 34 | #define UC1610_SET_DISPLAY_ENABLE 0xAE /* + 1 / 0 : exit sleep mode / entering sleep mode */ 35 | #define UC1610_SET_LCD_GRAY_SHADE 0xD0 /* default 24% between the two gray shade levels */ 36 | #define UC1610_SET_COM_END 0xF1 /* set the number of used com electrodes (lines number -1) */ 37 | 38 | /* ram address control */ 39 | #define UC1610_SET_AC 0x88 /* set ram address control */ 40 | #define UC1610_AC_WA_FLAG 1 /* automatic column/page increment wrap around (1 : cycle increment) */ 41 | #define UC1610_AC_AIO_FLAG (1 << 1) /* auto increment order (0/1 : column/page increment first) */ 42 | #define UC1610_AC_PID_FLAG (1 << 2) /* page address auto increment order (0/1 : +1/-1) */ 43 | 44 | /* set cursor ram address */ 45 | #define UC1610_SET_CA_LSB 0x00 /* + 4 LSB bits */ 46 | #define UC1610_SET_CA_MSB 0x10 /* + 4 MSB bits // MSB + LSB values range : 0~159 */ 47 | #define UC1610_SET_PA 0x60 /* + 5 bits // values range : 0~26 */ 48 | 49 | /* display control commands */ 50 | #define UC1610_SET_FIXED_LINES 0x90 /* + 4 bits = 2xFL */ 51 | #define UC1610_SET_SCROLL_LINES_LSB 0x40 /* + 4 LSB bits scroll up display by N (7 bits) lines */ 52 | #define UC1610_SET_SCROLL_LINES_MSB 0x50 /* + 3 MSB bits */ 53 | #define UC1610_SET_ALL_PIXEL_ON 0xA4 /* + 1 / 0 : set all pixel on, reverse */ 54 | #define UC1610_SET_INVERSE_DISPLAY 0xA6 /* + 1 / 0 : inverse all data stored in ram, reverse */ 55 | #define UC1610_SET_MAPPING_CONTROL 0xC0 /* control mirroring */ 56 | #define UC1610_SET_MAPPING_CONTROL_LC_FLAG 1 57 | #define UC1610_SET_MAPPING_CONTROL_MX_FLAG (1 << 1) 58 | #define UC1610_SET_MAPPING_CONTROL_MY_FLAG (1 << 2) 59 | 60 | /* window program mode */ 61 | #define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 /* + 1 / 0 : enable / disable window programming mode, */ 62 | /* reset before changing boundaries */ 63 | #define UC1610_SET_WP_STARTING_CA 0xF4 /* 1 byte to follow for column address */ 64 | #define UC1610_SET_WP_ENDING_CA 0xF6 /* 1 byte to follow for column address */ 65 | #define UC1610_SET_WP_STARTING_PA 0xF5 /* 1 byte to follow for page address */ 66 | #define UC1610_SET_WP_ENDING_PA 0xF7 /* 1 byte to follow for page address */ 67 | 68 | /********************** 69 | * TYPEDEFS 70 | **********************/ 71 | 72 | /********************** 73 | * STATIC PROTOTYPES 74 | **********************/ 75 | 76 | /********************** 77 | * STATIC VARIABLES 78 | **********************/ 79 | static uint8_t cmd_buf[12]; 80 | 81 | /********************** 82 | * MACROS 83 | **********************/ 84 | 85 | /* Return the byte bitmask of a pixel color corresponding to draw_buf arrangement */ 86 | #define PIXIDX(y, c) ((c) << (((y) & 3) << 1)) 87 | 88 | /********************** 89 | * GLOBAL FUNCTIONS 90 | **********************/ 91 | 92 | void uc1610_init(void) { 93 | LV_DRV_DELAY_MS(12); 94 | 95 | /* initialization sequence */ 96 | #if UC1610_INIT_HARD_RST 97 | LV_DRV_DISP_RST(UC1610_RESET_MODE); /* hardware reset */ 98 | LV_DRV_DELAY_MS(1); 99 | LV_DRV_DISP_RST(UC1610_SET_MODE); 100 | #else 101 | cmd_buf[0] = UC1610_SYSTEM_RESET; /* software reset */ 102 | LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); 103 | LV_DRV_DISP_SPI_CS(0); 104 | LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 1); 105 | LV_DRV_DISP_SPI_CS(1); 106 | #endif 107 | 108 | LV_DRV_DELAY_MS(2); 109 | cmd_buf[0] = UC1610_SET_COM_END; /* set com end value */ 110 | cmd_buf[1] = UC1610_VER_RES - 1; 111 | cmd_buf[2] = UC1610_SET_PANEL_LOADING; 112 | cmd_buf[3] = UC1610_SET_LCD_BIAS_RATIO; 113 | cmd_buf[4] = UC1610_SET_VBIAS_POT; /* set contrast */ 114 | cmd_buf[5] = (UC1610_INIT_CONTRAST * 255) / 100; 115 | #if UC1610_TOP_VIEW 116 | cmd_buf[6] = UC1610_SET_MAPPING_CONTROL | /* top view */ 117 | UC1610_SET_MAPPING_CONTROL_MY_FLAG | 118 | UC1610_SET_MAPPING_CONTROL_MX_FLAG; 119 | #else 120 | cmd_buf[6] = UC1610_SET_MAPPING_CONTROL; /* bottom view */ 121 | #endif 122 | cmd_buf[7] = UC1610_SET_SCROLL_LINES_LSB | 0; /* set scroll line on line 0 */ 123 | cmd_buf[8] = UC1610_SET_SCROLL_LINES_MSB | 0; 124 | cmd_buf[9] = UC1610_SET_AC | UC1610_AC_WA_FLAG; /* set auto increment wrap around */ 125 | cmd_buf[10] = UC1610_SET_INVERSE_DISPLAY | 1; /* invert colors to complies lv color system */ 126 | cmd_buf[11] = UC1610_SET_DISPLAY_ENABLE | 1; /* turn display on */ 127 | 128 | LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); 129 | LV_DRV_DISP_SPI_CS(0); 130 | LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 12); 131 | LV_DRV_DISP_SPI_CS(1); 132 | } 133 | 134 | 135 | void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { 136 | /*Return if the area is out the screen*/ 137 | if(area->x2 < 0) return; 138 | if(area->y2 < 0) return; 139 | if(area->x1 > UC1610_HOR_RES - 1) return; 140 | if(area->y1 > UC1610_VER_RES - 1) return; 141 | 142 | /*Truncate the area to the screen*/ 143 | uint8_t act_x1 = area->x1 < 0 ? 0 : area->x1; 144 | uint8_t act_y1 = area->y1 < 0 ? 0 : area->y1; 145 | uint8_t act_x2 = area->x2 > UC1610_HOR_RES - 1 ? UC1610_HOR_RES - 1 : area->x2; 146 | uint8_t act_y2 = area->y2 > UC1610_VER_RES - 1 ? UC1610_VER_RES - 1 : area->y2; 147 | 148 | uint8_t * buf = (uint8_t *) color_p; 149 | uint16_t buf_size = (act_x2 - act_x1 + 1) * (((act_y2 - act_y1) >> 2) + 1); 150 | 151 | /*Set display window to fill*/ 152 | cmd_buf[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; /* before changing boundaries */ 153 | cmd_buf[1] = UC1610_SET_WP_STARTING_CA; 154 | cmd_buf[2] = act_x1; 155 | cmd_buf[3] = UC1610_SET_WP_ENDING_CA; 156 | cmd_buf[4] = act_x2; 157 | cmd_buf[5] = UC1610_SET_WP_STARTING_PA; 158 | cmd_buf[6] = act_y1 >> 2; 159 | cmd_buf[7] = UC1610_SET_WP_ENDING_PA; 160 | cmd_buf[8] = act_y2 >> 2; 161 | cmd_buf[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; /* entering window programming */ 162 | 163 | LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); 164 | LV_DRV_DISP_SPI_CS(0); 165 | LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 10); 166 | LV_DRV_DISP_SPI_CS(1); 167 | 168 | /*Flush draw_buf on display memory*/ 169 | LV_DRV_DISP_CMD_DATA(UC1610_DATA_MODE); 170 | LV_DRV_DISP_SPI_CS(0); 171 | LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size); 172 | LV_DRV_DISP_SPI_CS(1); 173 | 174 | lv_disp_flush_ready(disp_drv); 175 | } 176 | 177 | 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) { 178 | (void) disp_drv; 179 | (void) opa; 180 | 181 | uint16_t idx = x + buf_w * (y >> 2); 182 | 183 | /* Convert color to depth 2 */ 184 | #if LV_COLOR_DEPTH == 1 185 | uint8_t color2 = color.full * 3; 186 | #else 187 | uint8_t color2 = color.full >> (LV_COLOR_DEPTH - 2); 188 | #endif 189 | 190 | buf[idx] &= ~PIXIDX(y, 3); /* reset pixel color */ 191 | buf[idx] |= PIXIDX(y, color2); /* write new color */ 192 | } 193 | 194 | void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area) { 195 | (void) disp_drv; 196 | 197 | /* Round y window to display memory page size */ 198 | area->y1 = (area->y1 & (~3)); 199 | area->y2 = (area->y2 & (~3)) + 3; 200 | } 201 | 202 | /********************** 203 | * STATIC FUNCTIONS 204 | **********************/ 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /display/UC1610.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file UC1610.h 3 | * 4 | */ 5 | 6 | #ifndef UC1610_H 7 | #define UC1610_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_UC1610 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void uc1610_init(void); 44 | void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 45 | void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area); 46 | 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); 47 | 48 | /********************** 49 | * MACROS 50 | **********************/ 51 | 52 | #endif /* USE_UC1610 */ 53 | 54 | #ifdef __cplusplus 55 | } /* extern "C" */ 56 | #endif 57 | 58 | #endif /* UC1610_H */ 59 | -------------------------------------------------------------------------------- /display/drm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file drm.h 3 | * 4 | */ 5 | 6 | #ifndef DRM_H 7 | #define DRM_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_DRM 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | 44 | int drm_init(void); /*Deprecated: Use drm_disp_drv_init instead*/ 45 | int drm_disp_drv_init(lv_disp_drv_t * disp_drv); 46 | void drm_get_sizes(lv_coord_t * width, lv_coord_t * height, uint32_t * dpi); 47 | void drm_exit(void); 48 | void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); 49 | void drm_wait_vsync(lv_disp_drv_t * drv); 50 | 51 | /********************** 52 | * MACROS 53 | **********************/ 54 | 55 | #endif /*USE_DRM*/ 56 | 57 | #ifdef __cplusplus 58 | } /* extern "C" */ 59 | #endif 60 | 61 | #endif /*DRM_H*/ 62 | -------------------------------------------------------------------------------- /display/fbdev.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fbdev.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "fbdev.h" 10 | #if USE_FBDEV || USE_BSD_FBDEV 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if USE_BSD_FBDEV 21 | #include 22 | #include 23 | #include 24 | #include 25 | #else /* USE_BSD_FBDEV */ 26 | #include 27 | #endif /* USE_BSD_FBDEV */ 28 | 29 | /********************* 30 | * DEFINES 31 | *********************/ 32 | #ifndef FBDEV_PATH 33 | #define FBDEV_PATH "/dev/fb0" 34 | #endif 35 | 36 | #ifndef DIV_ROUND_UP 37 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 38 | #endif 39 | 40 | /********************** 41 | * TYPEDEFS 42 | **********************/ 43 | 44 | /********************** 45 | * STRUCTURES 46 | **********************/ 47 | 48 | struct bsd_fb_var_info{ 49 | uint32_t xoffset; 50 | uint32_t yoffset; 51 | uint32_t xres; 52 | uint32_t yres; 53 | int bits_per_pixel; 54 | }; 55 | 56 | struct bsd_fb_fix_info{ 57 | long int line_length; 58 | long int smem_len; 59 | }; 60 | 61 | /********************** 62 | * STATIC PROTOTYPES 63 | **********************/ 64 | 65 | /********************** 66 | * STATIC VARIABLES 67 | **********************/ 68 | #if USE_BSD_FBDEV 69 | static struct bsd_fb_var_info vinfo; 70 | static struct bsd_fb_fix_info finfo; 71 | #else 72 | static struct fb_var_screeninfo vinfo; 73 | static struct fb_fix_screeninfo finfo; 74 | #endif /* USE_BSD_FBDEV */ 75 | static char *fbp = 0; 76 | static long int screensize = 0; 77 | static int fbfd = 0; 78 | 79 | /********************** 80 | * MACROS 81 | **********************/ 82 | 83 | #if USE_BSD_FBDEV 84 | #define FBIOBLANK FBIO_BLANK 85 | #endif /* USE_BSD_FBDEV */ 86 | 87 | /********************** 88 | * GLOBAL FUNCTIONS 89 | **********************/ 90 | 91 | void fbdev_init(void) 92 | { 93 | // Open the file for reading and writing 94 | fbfd = open(FBDEV_PATH, O_RDWR); 95 | if(fbfd == -1) { 96 | perror("Error: cannot open framebuffer device"); 97 | return; 98 | } 99 | LV_LOG_INFO("The framebuffer device was opened successfully"); 100 | 101 | // Make sure that the display is on. 102 | if (ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) { 103 | perror("ioctl(FBIOBLANK)"); 104 | // Don't return. Some framebuffer drivers like efifb or simplefb don't implement FBIOBLANK. 105 | } 106 | 107 | #if USE_BSD_FBDEV 108 | struct fbtype fb; 109 | unsigned line_length; 110 | 111 | //Get fb type 112 | if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) { 113 | perror("ioctl(FBIOGTYPE)"); 114 | return; 115 | } 116 | 117 | //Get screen width 118 | if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) { 119 | perror("ioctl(FBIO_GETLINEWIDTH)"); 120 | return; 121 | } 122 | 123 | vinfo.xres = (unsigned) fb.fb_width; 124 | vinfo.yres = (unsigned) fb.fb_height; 125 | vinfo.bits_per_pixel = fb.fb_depth; 126 | vinfo.xoffset = 0; 127 | vinfo.yoffset = 0; 128 | finfo.line_length = line_length; 129 | finfo.smem_len = finfo.line_length * vinfo.yres; 130 | #else /* USE_BSD_FBDEV */ 131 | 132 | // Get fixed screen information 133 | if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { 134 | perror("Error reading fixed information"); 135 | return; 136 | } 137 | 138 | // Get variable screen information 139 | if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { 140 | perror("Error reading variable information"); 141 | return; 142 | } 143 | #endif /* USE_BSD_FBDEV */ 144 | 145 | LV_LOG_INFO("%dx%d, %dbpp", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); 146 | 147 | // Figure out the size of the screen in bytes 148 | screensize = finfo.smem_len; //finfo.line_length * vinfo.yres; 149 | 150 | // Map the device to memory 151 | fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); 152 | if((intptr_t)fbp == -1) { 153 | perror("Error: failed to map framebuffer device to memory"); 154 | return; 155 | } 156 | 157 | // Don't initialise the memory to retain what's currently displayed / avoid clearing the screen. 158 | // This is important for applications that only draw to a subsection of the full framebuffer. 159 | 160 | LV_LOG_INFO("The framebuffer device was mapped to memory successfully"); 161 | 162 | } 163 | 164 | void fbdev_exit(void) 165 | { 166 | close(fbfd); 167 | } 168 | 169 | /** 170 | * Flush a buffer to the marked area 171 | * @param drv pointer to driver where this function belongs 172 | * @param area an area where to copy `color_p` 173 | * @param color_p an array of pixels to copy to the `area` part of the screen 174 | */ 175 | void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p) 176 | { 177 | if(fbp == NULL || 178 | area->x2 < 0 || 179 | area->y2 < 0 || 180 | area->x1 > (int32_t)vinfo.xres - 1 || 181 | area->y1 > (int32_t)vinfo.yres - 1) { 182 | lv_disp_flush_ready(drv); 183 | return; 184 | } 185 | 186 | /*Truncate the area to the screen*/ 187 | int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; 188 | int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; 189 | int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2; 190 | int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2; 191 | 192 | 193 | lv_coord_t w = (act_x2 - act_x1 + 1); 194 | long int location = 0; 195 | long int byte_location = 0; 196 | unsigned char bit_location = 0; 197 | 198 | /*32 bit per pixel*/ 199 | if(vinfo.bits_per_pixel == 32) { 200 | uint32_t * fbp32 = (uint32_t *)fbp; 201 | int32_t y; 202 | for(y = act_y1; y <= act_y2; y++) { 203 | location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 4; 204 | memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4); 205 | color_p += w; 206 | } 207 | } 208 | /*24 bit per pixel*/ 209 | else if(vinfo.bits_per_pixel == 24 && LV_COLOR_DEPTH == 32) { 210 | uint8_t * fbp8 = (uint8_t *)fbp; 211 | lv_coord_t x; 212 | int32_t y; 213 | uint8_t *pixel; 214 | for(y = act_y1; y <= act_y2; y++) { 215 | location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 3; 216 | for (x = 0; x < w; ++x) { 217 | pixel = (uint8_t *)(&color_p[x]); 218 | fbp8[3 * (location + x)] = pixel[0]; 219 | fbp8[3 * (location + x) + 1] = pixel[1]; 220 | fbp8[3 * (location + x) + 2] = pixel[2]; 221 | } 222 | color_p += w; 223 | } 224 | } 225 | /*16 bit per pixel*/ 226 | else if(vinfo.bits_per_pixel == 16) { 227 | uint16_t * fbp16 = (uint16_t *)fbp; 228 | int32_t y; 229 | for(y = act_y1; y <= act_y2; y++) { 230 | location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2; 231 | memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2); 232 | color_p += w; 233 | } 234 | } 235 | /*8 bit per pixel*/ 236 | else if(vinfo.bits_per_pixel == 8) { 237 | uint8_t * fbp8 = (uint8_t *)fbp; 238 | int32_t y; 239 | for(y = act_y1; y <= act_y2; y++) { 240 | location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length; 241 | memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1)); 242 | color_p += w; 243 | } 244 | } 245 | /*1 bit per pixel*/ 246 | else if(vinfo.bits_per_pixel == 1) { 247 | uint8_t * fbp8 = (uint8_t *)fbp; 248 | int32_t x; 249 | int32_t y; 250 | for(y = act_y1; y <= act_y2; y++) { 251 | for(x = act_x1; x <= act_x2; x++) { 252 | location = (x + vinfo.xoffset) + (y + vinfo.yoffset) * vinfo.xres; 253 | byte_location = location / 8; /* find the byte we need to change */ 254 | bit_location = location % 8; /* inside the byte found, find the bit we need to change */ 255 | fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location); 256 | fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location; 257 | color_p++; 258 | } 259 | 260 | color_p += area->x2 - act_x2; 261 | } 262 | } else { 263 | /*Not supported bit per pixel*/ 264 | } 265 | 266 | //May be some direct update command is required 267 | //ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect)); 268 | 269 | lv_disp_flush_ready(drv); 270 | } 271 | 272 | void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *dpi) { 273 | if (width) 274 | *width = vinfo.xres; 275 | 276 | if (height) 277 | *height = vinfo.yres; 278 | 279 | if (dpi && vinfo.height) 280 | *dpi = DIV_ROUND_UP(vinfo.xres * 254, vinfo.width * 10); 281 | } 282 | 283 | void fbdev_set_offset(uint32_t xoffset, uint32_t yoffset) { 284 | vinfo.xoffset = xoffset; 285 | vinfo.yoffset = yoffset; 286 | } 287 | 288 | /********************** 289 | * STATIC FUNCTIONS 290 | **********************/ 291 | 292 | #endif 293 | -------------------------------------------------------------------------------- /display/fbdev.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fbdev.h 3 | * 4 | */ 5 | 6 | #ifndef FBDEV_H 7 | #define FBDEV_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_FBDEV || USE_BSD_FBDEV 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void fbdev_init(void); 44 | void fbdev_exit(void); 45 | void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); 46 | void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *dpi); 47 | /** 48 | * Set the X and Y offset in the variable framebuffer info. 49 | * @param xoffset horizontal offset 50 | * @param yoffset vertical offset 51 | */ 52 | void fbdev_set_offset(uint32_t xoffset, uint32_t yoffset); 53 | 54 | 55 | /********************** 56 | * MACROS 57 | **********************/ 58 | 59 | #endif /*USE_FBDEV*/ 60 | 61 | #ifdef __cplusplus 62 | } /* extern "C" */ 63 | #endif 64 | 65 | #endif /*FBDEV_H*/ 66 | -------------------------------------------------------------------------------- /display/monitor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file monitor.h 3 | * 4 | */ 5 | 6 | #ifndef MONITOR_H 7 | #define MONITOR_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_MONITOR 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void monitor_init(void); 44 | void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 45 | void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 46 | 47 | /********************** 48 | * MACROS 49 | **********************/ 50 | 51 | #endif /* USE_MONITOR */ 52 | 53 | #ifdef __cplusplus 54 | } /* extern "C" */ 55 | #endif 56 | 57 | #endif /* MONITOR_H */ 58 | -------------------------------------------------------------------------------- /docs/astyle_c: -------------------------------------------------------------------------------- 1 | --style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent= 2 | -------------------------------------------------------------------------------- /docs/astyle_h: -------------------------------------------------------------------------------- 1 | --convert-tabs --indent=spaces=4 2 | -------------------------------------------------------------------------------- /gtkdrv/README.md: -------------------------------------------------------------------------------- 1 | # Add GTK under Linux in Eclipse 2 | 3 | ## Install GDK 4 | 5 | ``` 6 | sudo apt-get install libgtk-3-dev 7 | sudo apt-get install libglib2.0-dev 8 | ``` 9 | 10 | ## Add GTK include paths and libraries 11 | 12 | In "Project properties > C/C++ Build > Settings" set the followings: 13 | 14 | - "Cross GCC Compiler > Command line pattern" 15 | - Add ` ${gtk+-cflags}` to the end (add a space between the last command and this) 16 | 17 | - "Cross GCC Compiler > Includes" 18 | - /usr/include/glib-2.0 19 | - /usr/include/gtk-3.0 20 | - /usr/include/pango-1.0 21 | - /usr/include/cairo 22 | - /usr/include/gdk-pixbuf-2.0 23 | - /usr/include/atk-1.0 24 | 25 | - "Cross GCC Linker > Command line pattern" 26 | - Add ` ${gtk+-libs}` to the end (add a space between the last command and this) 27 | 28 | 29 | - "Cross GCC Linker > Libraries" 30 | - Add `pthread` 31 | 32 | 33 | - In "C/C++ Build > Build variables" 34 | - Configuration: [All Configuration] 35 | 36 | - Add 37 | - Variable name: `gtk+-cflags` 38 | - Type: `String` 39 | - Value: `pkg-config --cflags gtk+-3.0` 40 | - Variable name: `gtk+-libs` 41 | - Type: `String` 42 | - Value: `pkg-config --libs gtk+-3.0` 43 | 44 | 45 | ## Init GDK in LVGL 46 | 47 | 1. In `main.c` `#include "lv_drivers/gtkdrv/gtkdrv.h"` 48 | 2. Enable the GTK driver in `lv_drv_conf.h` with `USE_GTK 1` 49 | 3. After `lv_init()` call `gdkdrv_init()`; 50 | 4. Add a display: 51 | ```c 52 | static lv_disp_buf_t disp_buf1; 53 | static lv_color_t buf1_1[LV_HOR_RES_MAX * LV_VER_RES_MAX]; 54 | lv_disp_buf_init(&disp_buf1, buf1_1, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX); 55 | 56 | /*Create a display*/ 57 | lv_disp_drv_t disp_drv; 58 | lv_disp_drv_init(&disp_drv); 59 | disp_drv.buffer = &disp_buf1; 60 | disp_drv.flush_cb = gtkdrv_flush_cb; 61 | ``` 62 | 5. Add mouse: 63 | ```c 64 | lv_indev_drv_t indev_drv_mouse; 65 | lv_indev_drv_init(&indev_drv_mouse); 66 | indev_drv_mouse.type = LV_INDEV_TYPE_POINTER; 67 | ``` 68 | 6. Add keyboard: 69 | ```c 70 | lv_indev_drv_t indev_drv_kb; 71 | lv_indev_drv_init(&indev_drv_kb); 72 | indev_drv_kb.type = LV_INDEV_TYPE_KEYPAD; 73 | indev_drv_kb.read_cb = lv_keyboard_read_cb; 74 | lv_indev_drv_register(&indev_drv_kb); 75 | ``` 76 | 7. Configure tick in `lv_conf.h` 77 | ```c 78 | #define LV_TICK_CUSTOM 1 79 | #if LV_TICK_CUSTOM == 1 80 | #define LV_TICK_CUSTOM_INCLUDE "lv_drivers/gtkdrv/gtkdrv.h" /*Header for the sys time function*/ 81 | #define LV_TICK_CUSTOM_SYS_TIME_EXPR (gtkdrv_tick_get()) /*Expression evaluating to current systime in ms*/ 82 | #endif /*LV_TICK_CUSTOM*/ 83 | ``` 84 | 8. Be sure `LV_COLOR_DEPTH` is `32` in `lv_conf.h` 85 | 86 | ## Run in a window 87 | Build and Run to "normally" run the UI in a window 88 | 89 | ## Run in browser 90 | With the help of `Broadway` the UI can be easily shown via a browser. 91 | 92 | 1. Open Terminal and start *Broadway* with `broadwayd :5`. Leave the terminal running. 93 | 2. Navigate to where eclipse created the binary executable (my_project/Debug) and open a terminal in that folder. 94 | In this terminal run `GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 ./my_executable` (replace *my_executable* wih name of your executable) 95 | 3. Open a web browser and go to `http://localhost:8085/` 96 | 97 | ![LVGL with GTK/GDK Broadway backend](https://github.com/lvgl/lv_drivers/blob/master/gtkdrv/broadway.png?raw=true) 98 | -------------------------------------------------------------------------------- /gtkdrv/broadway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgl/lv_drivers/ea2e4cc00d02064173d56241f16ad492692138e4/gtkdrv/broadway.png -------------------------------------------------------------------------------- /gtkdrv/gtkdrv.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gtk.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "gtkdrv.h" 10 | 11 | #if USE_GTK 12 | #define _DEFAULT_SOURCE /* needed for usleep() */ 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | /********************* 22 | * DEFINES 23 | *********************/ 24 | 25 | /********************** 26 | * TYPEDEFS 27 | **********************/ 28 | 29 | /********************** 30 | * STATIC PROTOTYPES 31 | **********************/ 32 | static void gtkdrv_handler(void * p); 33 | static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event, 34 | gpointer user_data); 35 | static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event, 36 | gpointer user_data); 37 | static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event, 38 | gpointer user_data); 39 | static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event, 40 | gpointer user_data); 41 | static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event, 42 | gpointer user_data); 43 | 44 | static void quit_handler(void); 45 | 46 | /********************** 47 | * STATIC VARIABLES 48 | **********************/ 49 | static GtkWidget *window; 50 | static GtkWidget *event_box; 51 | 52 | static GtkWidget *output_image; 53 | static GdkPixbuf *pixbuf; 54 | 55 | static unsigned char run_gtk; 56 | 57 | static lv_coord_t mouse_x; 58 | static lv_coord_t mouse_y; 59 | static lv_indev_state_t mouse_btn = LV_INDEV_STATE_REL; 60 | static lv_key_t last_key; 61 | static lv_indev_state_t last_key_state; 62 | 63 | static uint8_t fb[LV_HOR_RES_MAX * LV_VER_RES_MAX * 3]; 64 | 65 | /********************** 66 | * MACROS 67 | **********************/ 68 | 69 | /********************** 70 | * GLOBAL FUNCTIONS 71 | **********************/ 72 | 73 | void gtkdrv_init(void) 74 | { 75 | // Init GTK 76 | gtk_init(NULL, NULL); 77 | 78 | /* Or just set up the widgets in code */ 79 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 80 | gtk_window_set_default_size(GTK_WINDOW(window), LV_HOR_RES_MAX, LV_VER_RES_MAX); 81 | gtk_window_set_resizable (GTK_WINDOW(window), FALSE); 82 | output_image = gtk_image_new(); 83 | event_box = gtk_event_box_new (); // Use event_box around image, otherwise mouse position output in broadway is offset 84 | gtk_container_add(GTK_CONTAINER (event_box), output_image); 85 | gtk_container_add(GTK_CONTAINER (window), event_box); 86 | 87 | gtk_widget_add_events(event_box, GDK_BUTTON_PRESS_MASK); 88 | gtk_widget_add_events(event_box, GDK_SCROLL_MASK); 89 | gtk_widget_add_events(event_box, GDK_POINTER_MOTION_MASK); 90 | gtk_widget_add_events(window, GDK_KEY_PRESS_MASK); 91 | 92 | g_signal_connect(window, "destroy", G_CALLBACK(quit_handler), NULL); 93 | g_signal_connect(event_box, "button-press-event", G_CALLBACK(mouse_pressed), NULL); 94 | g_signal_connect(event_box, "button-release-event", G_CALLBACK(mouse_released), NULL); 95 | g_signal_connect(event_box, "motion-notify-event", G_CALLBACK(mouse_motion), NULL); 96 | g_signal_connect(window, "key_press_event", G_CALLBACK(keyboard_press), NULL); 97 | g_signal_connect(window, "key_release_event", G_CALLBACK(keyboard_release), NULL); 98 | 99 | 100 | gtk_widget_show_all(window); 101 | 102 | 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); 103 | if (pixbuf == NULL) 104 | { 105 | fprintf(stderr, "Creating pixbuf failed\n"); 106 | return; 107 | } 108 | 109 | pthread_t thread; 110 | pthread_create(&thread, NULL, gtkdrv_handler, NULL); 111 | } 112 | 113 | 114 | /*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/ 115 | uint32_t gtkdrv_tick_get(void) 116 | { 117 | static uint64_t start_ms = 0; 118 | if(start_ms == 0) { 119 | struct timeval tv_start; 120 | gettimeofday(&tv_start, NULL); 121 | start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000; 122 | } 123 | 124 | struct timeval tv_now; 125 | gettimeofday(&tv_now, NULL); 126 | uint64_t now_ms; 127 | now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000; 128 | 129 | uint32_t time_ms = now_ms - start_ms; 130 | 131 | return time_ms; 132 | } 133 | 134 | 135 | /** 136 | * Flush a buffer to the marked area 137 | * @param disp_drv pointer to driver where this function belongs 138 | * @param area an area where to copy `color_p` 139 | * @param color_p an array of pixels to copy to the `area` part of the screen 140 | */ 141 | void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) 142 | { 143 | lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res; 144 | lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res; 145 | 146 | 147 | /*Return if the area is out the screen*/ 148 | if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) { 149 | 150 | lv_disp_flush_ready(disp_drv); 151 | return; 152 | } 153 | 154 | int32_t y; 155 | int32_t x; 156 | int32_t p; 157 | for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { 158 | p = (y * disp_drv->hor_res + area->x1) * 3; 159 | for(x = area->x1; x <= area->x2 && x < disp_drv->hor_res; x++) { 160 | fb[p] = color_p->ch.red; 161 | fb[p + 1] = color_p->ch.green; 162 | fb[p + 2] = color_p->ch.blue; 163 | 164 | p += 3; 165 | color_p ++; 166 | } 167 | } 168 | 169 | /*IMPORTANT! It must be called to tell the system the flush is ready*/ 170 | lv_disp_flush_ready(disp_drv); 171 | } 172 | 173 | 174 | void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data) 175 | { 176 | data->point.x = mouse_x; 177 | data->point.y = mouse_y; 178 | data->state = mouse_btn; 179 | } 180 | 181 | 182 | void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data) 183 | { 184 | data->key = last_key; 185 | data->state = last_key_state; 186 | } 187 | 188 | 189 | 190 | 191 | /********************** 192 | * STATIC FUNCTIONS 193 | **********************/ 194 | 195 | static void gtkdrv_handler(void * p) 196 | { 197 | while(1) { 198 | gtk_image_set_from_pixbuf(GTK_IMAGE(output_image), pixbuf); // Test code 199 | 200 | /* Real code should: call gdk_pixbuf_new_from_data () with pointer to frame buffer 201 | generated by LVGL. See 202 | https://developer.gnome.org/gdk-pixbuf/2.36/gdk-pixbuf-Image-Data-in-Memory.html 203 | */ 204 | 205 | gtk_main_iteration_do(FALSE); 206 | /* Explicitly calling each iteration of the GTK main loop allows LVGL to sync frame 207 | buffer updates with GTK. It is perhaps also possible to just call gtk_main(), but not 208 | sure how sync will work then 209 | */ 210 | usleep(1*1000); 211 | } 212 | } 213 | 214 | static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event, 215 | gpointer user_data) 216 | { 217 | mouse_btn = LV_INDEV_STATE_PR; 218 | // Important, if this function returns TRUE the window cannot be moved around inside the browser 219 | // when using broadway 220 | return FALSE; 221 | } 222 | 223 | 224 | static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event, 225 | gpointer user_data) 226 | { 227 | mouse_btn = LV_INDEV_STATE_REL; 228 | // Important, if this function returns TRUE the window cannot be moved around inside the browser 229 | // when using broadway 230 | return FALSE; 231 | } 232 | 233 | /*****************************************************************************/ 234 | 235 | static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event, 236 | gpointer user_data) 237 | { 238 | mouse_x = event->x; 239 | mouse_y = event->y; 240 | // Important, if this function returns TRUE the window cannot be moved around inside the browser 241 | // when using broadway 242 | return FALSE; 243 | } 244 | 245 | 246 | static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event, 247 | gpointer user_data) 248 | { 249 | 250 | uint32_t ascii_key = event->keyval; 251 | /*Remap some key to LV_KEY_... to manage groups*/ 252 | switch(event->keyval) { 253 | case GDK_KEY_rightarrow: 254 | case GDK_KEY_Right: 255 | ascii_key = LV_KEY_RIGHT; 256 | break; 257 | 258 | case GDK_KEY_leftarrow: 259 | case GDK_KEY_Left: 260 | ascii_key = LV_KEY_LEFT; 261 | break; 262 | 263 | case GDK_KEY_uparrow: 264 | case GDK_KEY_Up: 265 | ascii_key = LV_KEY_UP; 266 | break; 267 | 268 | case GDK_KEY_downarrow: 269 | case GDK_KEY_Down: 270 | ascii_key = LV_KEY_DOWN; 271 | break; 272 | 273 | case GDK_KEY_Escape: 274 | ascii_key = LV_KEY_ESC; 275 | break; 276 | 277 | case GDK_KEY_BackSpace: 278 | ascii_key = LV_KEY_BACKSPACE; 279 | break; 280 | 281 | case GDK_KEY_Delete: 282 | ascii_key = LV_KEY_DEL; 283 | break; 284 | 285 | case GDK_KEY_Tab: 286 | ascii_key = LV_KEY_NEXT; 287 | break; 288 | 289 | case GDK_KEY_KP_Enter: 290 | case GDK_KEY_Return: 291 | case '\r': 292 | ascii_key = LV_KEY_ENTER; 293 | break; 294 | 295 | default: 296 | break; 297 | 298 | } 299 | 300 | last_key = ascii_key; 301 | last_key_state = LV_INDEV_STATE_PR; 302 | // For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey 303 | 304 | return TRUE; 305 | } 306 | 307 | static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event, 308 | gpointer user_data) 309 | { 310 | last_key = 0; 311 | last_key_state = LV_INDEV_STATE_REL; 312 | // For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey 313 | 314 | return TRUE; 315 | } 316 | 317 | static void quit_handler(void) 318 | { 319 | exit(0); 320 | run_gtk = FALSE; 321 | } 322 | #endif /*USE_GTK*/ 323 | 324 | -------------------------------------------------------------------------------- /gtkdrv/gtkdrv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gtkdrv 3 | * 4 | */ 5 | 6 | #ifndef GTKDRV_H 7 | #define GTKDRV_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_GTK 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | 33 | /********************* 34 | * DEFINES 35 | *********************/ 36 | 37 | /********************** 38 | * TYPEDEFS 39 | **********************/ 40 | 41 | /********************** 42 | * GLOBAL PROTOTYPES 43 | **********************/ 44 | void gtkdrv_init(void); 45 | uint32_t gtkdrv_tick_get(void); 46 | void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 47 | void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data); 48 | void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data); 49 | /********************** 50 | * MACROS 51 | **********************/ 52 | 53 | #endif /*USE_GTK*/ 54 | 55 | #ifdef __cplusplus 56 | } /* extern "C" */ 57 | #endif 58 | 59 | #endif /* GTKDRV_H */ 60 | -------------------------------------------------------------------------------- /indev/AD_touch.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file AD_touch.c 3 | * 4 | */ 5 | 6 | #include "AD_touch.h" 7 | 8 | #if USE_AD_TOUCH 9 | 10 | #include LV_DRV_INDEV_INCLUDE 11 | #include LV_DRV_DELAY_INCLUDE 12 | 13 | #define SAMPLE_POINTS 4 14 | 15 | #define CALIBRATIONINSET 20 // range 0 <= CALIBRATIONINSET <= 40 16 | 17 | #define RESISTIVETOUCH_AUTO_SAMPLE_MODE 18 | #define TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD 350 // between 0-0x03ff the lesser this value 19 | 20 | 21 | // Current ADC values for X and Y channels 22 | int16_t adcX = 0; 23 | int16_t adcY = 0; 24 | volatile unsigned int adcTC = 0; 25 | 26 | // coefficient values 27 | volatile long _trA; 28 | volatile long _trB; 29 | volatile long _trC; 30 | volatile long _trD; 31 | 32 | volatile int16_t xRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULX, TOUCHCAL_URX, TOUCHCAL_LRX, TOUCHCAL_LLX}; 33 | volatile int16_t yRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULY, TOUCHCAL_URY, TOUCHCAL_LRY, TOUCHCAL_LLY}; 34 | 35 | #define TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR 8 36 | 37 | // use this scale factor to avoid working in floating point numbers 38 | #define SCALE_FACTOR (1 << TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR) 39 | 40 | typedef enum { 41 | IDLE, //0 42 | SET_X, //1 43 | RUN_X, //2 44 | GET_X, //3 45 | RUN_CHECK_X, //4 46 | CHECK_X, //5 47 | SET_Y, //6 48 | RUN_Y, //7 49 | GET_Y, //8 50 | CHECK_Y, //9 51 | SET_VALUES, //10 52 | GET_POT, //11 53 | RUN_POT //12 54 | } TOUCH_STATES; 55 | 56 | volatile TOUCH_STATES state = IDLE; 57 | 58 | #define CAL_X_INSET (((GetMaxX() + 1) * (CALIBRATIONINSET >> 1)) / 100) 59 | #define CAL_Y_INSET (((GetMaxY() + 1) * (CALIBRATIONINSET >> 1)) / 100) 60 | 61 | int stat; 62 | int16_t temp_x, temp_y; 63 | 64 | 65 | static int16_t TouchGetX(void); 66 | static int16_t TouchGetRawX(void); 67 | static int16_t TouchGetY(void); 68 | static int16_t TouchGetRawY(void); 69 | static int16_t TouchDetectPosition(void); 70 | static void TouchCalculateCalPoints(void); 71 | 72 | 73 | /********************************************************************/ 74 | void ad_touch_init(void) 75 | { 76 | // Initialize ADC for auto sampling mode 77 | AD1CON1 = 0; // reset 78 | AD1CON2 = 0; // AVdd, AVss, int every conversion, MUXA only 79 | AD1CON3 = 0x1FFF; // 31 Tad auto-sample, Tad = 256*Tcy 80 | AD1CON1 = 0x80E0; // Turn on A/D module, use auto-convert 81 | 82 | 83 | ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; 84 | ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; 85 | 86 | AD1CSSL = 0; // No scanned inputs 87 | 88 | state = SET_X; // set the state of the state machine to start the sampling 89 | 90 | /*Load calibration data*/ 91 | xRawTouch[0] = TOUCHCAL_ULX; 92 | yRawTouch[0] = TOUCHCAL_ULY; 93 | xRawTouch[1] = TOUCHCAL_URX; 94 | yRawTouch[1] = TOUCHCAL_URY; 95 | xRawTouch[3] = TOUCHCAL_LLX; 96 | yRawTouch[3] = TOUCHCAL_LLY; 97 | xRawTouch[2] = TOUCHCAL_LRX; 98 | yRawTouch[2] = TOUCHCAL_LRY; 99 | 100 | TouchCalculateCalPoints(); 101 | } 102 | 103 | /*Use this in lv_indev_drv*/ 104 | bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 105 | { 106 | static int16_t last_x = 0; 107 | static int16_t last_y = 0; 108 | 109 | int16_t x, y; 110 | 111 | x = TouchGetX(); 112 | y = TouchGetY(); 113 | 114 | if((x > 0) && (y > 0)) { 115 | data->point.x = x; 116 | data->point.y = y; 117 | last_x = data->point.x; 118 | last_y = data->point.y; 119 | data->state = LV_INDEV_STATE_PR; 120 | } else { 121 | data->point.x = last_x; 122 | data->point.y = last_y; 123 | data->state = LV_INDEV_STATE_REL; 124 | } 125 | 126 | return false; 127 | } 128 | 129 | /* Call periodically (e.g. in every 1 ms) to handle reading with ADC*/ 130 | int16_t ad_touch_handler(void) 131 | { 132 | static int16_t tempX, tempY; 133 | int16_t temp; 134 | 135 | switch(state) { 136 | case IDLE: 137 | adcX = 0; 138 | adcY = 0; 139 | break; 140 | 141 | case SET_VALUES: 142 | if(!TOUCH_ADC_DONE) 143 | break; 144 | if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) { 145 | adcX = 0; 146 | adcY = 0; 147 | } else { 148 | adcX = tempX; 149 | adcY = tempY; 150 | } 151 | state = SET_X; 152 | return 1; // touch screen acquisition is done 153 | 154 | case SET_X: 155 | TOUCH_ADC_INPUT_SEL = ADC_XPOS; 156 | 157 | ResistiveTouchScreen_XPlus_Config_As_Input(); 158 | ResistiveTouchScreen_YPlus_Config_As_Input(); 159 | ResistiveTouchScreen_XMinus_Config_As_Input(); 160 | ResistiveTouchScreen_YMinus_Drive_Low(); 161 | ResistiveTouchScreen_YMinus_Config_As_Output(); 162 | 163 | ADPCFG_YPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin 164 | ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; // set to analog pin 165 | 166 | TOUCH_ADC_START = 1; // run conversion 167 | state = CHECK_X; 168 | break; 169 | 170 | case CHECK_X: 171 | case CHECK_Y: 172 | 173 | if(TOUCH_ADC_DONE == 0) { 174 | break; 175 | } 176 | 177 | if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD > (WORD)ADC1BUF0) { 178 | if(state == CHECK_X) { 179 | ResistiveTouchScreen_YPlus_Drive_High(); 180 | ResistiveTouchScreen_YPlus_Config_As_Output(); 181 | tempX = 0; 182 | state = RUN_X; 183 | } else { 184 | ResistiveTouchScreen_XPlus_Drive_High(); 185 | ResistiveTouchScreen_XPlus_Config_As_Output(); 186 | tempY = 0; 187 | state = RUN_Y; 188 | } 189 | } else { 190 | adcX = 0; 191 | adcY = 0; 192 | state = SET_X; 193 | return 1; // touch screen acquisition is done 194 | break; 195 | } 196 | 197 | case RUN_X: 198 | case RUN_Y: 199 | TOUCH_ADC_START = 1; 200 | state = (state == RUN_X) ? GET_X : GET_Y; 201 | // no break needed here since the next state is either GET_X or GET_Y 202 | break; 203 | 204 | case GET_X: 205 | case GET_Y: 206 | if(!TOUCH_ADC_DONE) 207 | break; 208 | 209 | temp = ADC1BUF0; 210 | if(state == GET_X) { 211 | if(temp != tempX) { 212 | tempX = temp; 213 | state = RUN_X; 214 | break; 215 | } 216 | } else { 217 | if(temp != tempY) { 218 | tempY = temp; 219 | state = RUN_Y; 220 | break; 221 | } 222 | } 223 | 224 | if(state == GET_X) 225 | ResistiveTouchScreen_YPlus_Config_As_Input(); 226 | else 227 | ResistiveTouchScreen_XPlus_Config_As_Input(); 228 | TOUCH_ADC_START = 1; 229 | state = (state == GET_X) ? SET_Y : SET_VALUES; 230 | break; 231 | 232 | case SET_Y: 233 | if(!TOUCH_ADC_DONE) 234 | break; 235 | 236 | if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) { 237 | adcX = 0; 238 | adcY = 0; 239 | state = SET_X; 240 | return 1; // touch screen acquisition is done 241 | break; 242 | } 243 | 244 | TOUCH_ADC_INPUT_SEL = ADC_YPOS; 245 | 246 | ResistiveTouchScreen_XPlus_Config_As_Input(); 247 | ResistiveTouchScreen_YPlus_Config_As_Input(); 248 | ResistiveTouchScreen_XMinus_Drive_Low(); 249 | ResistiveTouchScreen_XMinus_Config_As_Output(); 250 | ResistiveTouchScreen_YMinus_Config_As_Input(); 251 | 252 | ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; // set to analog pin 253 | ADPCFG_XPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin 254 | TOUCH_ADC_START = 1; // run conversion 255 | state = CHECK_Y; 256 | break; 257 | 258 | default: 259 | state = SET_X; 260 | return 1; // touch screen acquisition is done 261 | } 262 | stat = state; 263 | temp_x = adcX; 264 | temp_y = adcY; 265 | 266 | return 0; // touch screen acquisition is not done 267 | } 268 | 269 | /********************** 270 | * STATIC FUNCTIONS 271 | **********************/ 272 | 273 | /********************************************************************/ 274 | static int16_t TouchGetX(void) 275 | { 276 | long result; 277 | 278 | result = TouchGetRawX(); 279 | 280 | if(result > 0) { 281 | result = (long)((((long)_trC * result) + _trD) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR); 282 | 283 | } 284 | return ((int16_t)result); 285 | } 286 | /********************************************************************/ 287 | static int16_t TouchGetRawX(void) 288 | { 289 | #ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY 290 | return adcY; 291 | #else 292 | return adcX; 293 | #endif 294 | } 295 | 296 | /********************************************************************/ 297 | static int16_t TouchGetY(void) 298 | { 299 | 300 | long result; 301 | 302 | result = TouchGetRawY(); 303 | 304 | if(result > 0) { 305 | result = (long)((((long)_trA * result) + (long)_trB) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR); 306 | 307 | } 308 | return ((int16_t)result); 309 | } 310 | 311 | /********************************************************************/ 312 | static int16_t TouchGetRawY(void) 313 | { 314 | #ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY 315 | return adcX; 316 | #else 317 | return adcY; 318 | #endif 319 | } 320 | 321 | 322 | static void TouchCalculateCalPoints(void) 323 | { 324 | long trA, trB, trC, trD; // variables for the coefficients 325 | long trAhold, trBhold, trChold, trDhold; 326 | long test1, test2; // temp variables (must be signed type) 327 | 328 | int16_t xPoint[SAMPLE_POINTS], yPoint[SAMPLE_POINTS]; 329 | 330 | yPoint[0] = yPoint[1] = CAL_Y_INSET; 331 | yPoint[2] = yPoint[3] = (GetMaxY() - CAL_Y_INSET); 332 | xPoint[0] = xPoint[3] = CAL_X_INSET; 333 | xPoint[1] = xPoint[2] = (GetMaxX() - CAL_X_INSET); 334 | 335 | // calculate points transfer functiona 336 | // based on two simultaneous equations solve for the 337 | // constants 338 | 339 | // use sample points 1 and 4 340 | // Dy1 = aTy1 + b; Dy4 = aTy4 + b 341 | // Dx1 = cTx1 + d; Dy4 = aTy4 + b 342 | 343 | test1 = (long)yPoint[0] - (long)yPoint[3]; 344 | test2 = (long)yRawTouch[0] - (long)yRawTouch[3]; 345 | 346 | trA = ((long)((long)test1 * SCALE_FACTOR) / test2); 347 | trB = ((long)((long)yPoint[0] * SCALE_FACTOR) - (trA * (long)yRawTouch[0])); 348 | 349 | test1 = (long)xPoint[0] - (long)xPoint[2]; 350 | test2 = (long)xRawTouch[0] - (long)xRawTouch[2]; 351 | 352 | trC = ((long)((long)test1 * SCALE_FACTOR) / test2); 353 | trD = ((long)((long)xPoint[0] * SCALE_FACTOR) - (trC * (long)xRawTouch[0])); 354 | 355 | trAhold = trA; 356 | trBhold = trB; 357 | trChold = trC; 358 | trDhold = trD; 359 | 360 | // use sample points 2 and 3 361 | // Dy2 = aTy2 + b; Dy3 = aTy3 + b 362 | // Dx2 = cTx2 + d; Dy3 = aTy3 + b 363 | 364 | test1 = (long)yPoint[1] - (long)yPoint[2]; 365 | test2 = (long)yRawTouch[1] - (long)yRawTouch[2]; 366 | 367 | trA = ((long)(test1 * SCALE_FACTOR) / test2); 368 | trB = ((long)((long)yPoint[1] * SCALE_FACTOR) - (trA * (long)yRawTouch[1])); 369 | 370 | test1 = (long)xPoint[1] - (long)xPoint[3]; 371 | test2 = (long)xRawTouch[1] - (long)xRawTouch[3]; 372 | 373 | trC = ((long)((long)test1 * SCALE_FACTOR) / test2); 374 | trD = ((long)((long)xPoint[1] * SCALE_FACTOR) - (trC * (long)xRawTouch[1])); 375 | 376 | // get the average and use the average 377 | _trA = (trA + trAhold) >> 1; 378 | _trB = (trB + trBhold) >> 1; 379 | _trC = (trC + trChold) >> 1; 380 | _trD = (trD + trDhold) >> 1; 381 | } 382 | 383 | #endif 384 | -------------------------------------------------------------------------------- /indev/AD_touch.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file AD_touch.h 3 | * 4 | */ 5 | 6 | #ifndef AD_TOUCH_H 7 | #define AD_TOUCH_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_AD_TOUCH 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | #define _SUPPRESS_PLIB_WARNING 33 | #include 34 | 35 | #include "GenericTypeDefs.h" 36 | 37 | #define DISP_ORIENTATION 0 38 | #define DISP_HOR_RESOLUTION 320 39 | #define DISP_VER_RESOLUTION 240 40 | 41 | /*GetMaxX Macro*/ 42 | #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270) 43 | #define GetMaxX() (DISP_VER_RESOLUTION - 1) 44 | #elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180) 45 | #define GetMaxX() (DISP_HOR_RESOLUTION - 1) 46 | #endif 47 | 48 | /*GetMaxY Macro*/ 49 | #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270) 50 | #define GetMaxY() (DISP_HOR_RESOLUTION - 1) 51 | #elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180) 52 | #define GetMaxY() (DISP_VER_RESOLUTION - 1) 53 | #endif 54 | 55 | /********************************************************************* 56 | * HARDWARE PROFILE FOR THE RESISTIVE TOUCHSCREEN 57 | *********************************************************************/ 58 | 59 | #define TOUCH_ADC_INPUT_SEL AD1CHS 60 | 61 | // ADC Sample Start 62 | #define TOUCH_ADC_START AD1CON1bits.SAMP 63 | 64 | // ADC Status 65 | #define TOUCH_ADC_DONE AD1CON1bits.DONE 66 | 67 | #define RESISTIVETOUCH_ANALOG 1 68 | #define RESISTIVETOUCH_DIGITAL 0 69 | 70 | // ADC channel constants 71 | #define ADC_XPOS ADC_CH0_POS_SAMPLEA_AN12 72 | #define ADC_YPOS ADC_CH0_POS_SAMPLEA_AN13 73 | 74 | // ADC Port Control Bits 75 | #define ADPCFG_XPOS AD1PCFGbits.PCFG12 //XR 76 | #define ADPCFG_YPOS AD1PCFGbits.PCFG13 //YD 77 | 78 | // X port definitions 79 | #define ResistiveTouchScreen_XPlus_Drive_High() LATBbits.LATB12 = 1 80 | #define ResistiveTouchScreen_XPlus_Drive_Low() LATBbits.LATB12 = 0 //LAT_XPOS 81 | #define ResistiveTouchScreen_XPlus_Config_As_Input() TRISBbits.TRISB12 = 1 //TRIS_XPOS 82 | #define ResistiveTouchScreen_XPlus_Config_As_Output() TRISBbits.TRISB12 = 0 83 | 84 | #define ResistiveTouchScreen_XMinus_Drive_High() LATFbits.LATF0 = 1 85 | #define ResistiveTouchScreen_XMinus_Drive_Low() LATFbits.LATF0 = 0 //LAT_XNEG 86 | #define ResistiveTouchScreen_XMinus_Config_As_Input() TRISFbits.TRISF0 = 1 //TRIS_XNEG 87 | #define ResistiveTouchScreen_XMinus_Config_As_Output() TRISFbits.TRISF0 = 0 88 | 89 | // Y port definitions 90 | #define ResistiveTouchScreen_YPlus_Drive_High() LATBbits.LATB13 = 1 91 | #define ResistiveTouchScreen_YPlus_Drive_Low() LATBbits.LATB13 = 0 //LAT_YPOS 92 | #define ResistiveTouchScreen_YPlus_Config_As_Input() TRISBbits.TRISB13 = 1 //TRIS_YPOS 93 | #define ResistiveTouchScreen_YPlus_Config_As_Output() TRISBbits.TRISB13 = 0 94 | 95 | #define ResistiveTouchScreen_YMinus_Drive_High() LATFbits.LATF1 = 1 96 | #define ResistiveTouchScreen_YMinus_Drive_Low() LATFbits.LATF1 = 0 //LAT_YNEG 97 | #define ResistiveTouchScreen_YMinus_Config_As_Input() TRISFbits.TRISF1 = 1 //TRIS_YNEG 98 | #define ResistiveTouchScreen_YMinus_Config_As_Output() TRISFbits.TRISF1 = 0 99 | 100 | // Default calibration points 101 | #define TOUCHCAL_ULX 0x0348 102 | #define TOUCHCAL_ULY 0x00CC 103 | #define TOUCHCAL_URX 0x00D2 104 | #define TOUCHCAL_URY 0x00CE 105 | #define TOUCHCAL_LLX 0x034D 106 | #define TOUCHCAL_LLY 0x0335 107 | #define TOUCHCAL_LRX 0x00D6 108 | #define TOUCHCAL_LRY 0x032D 109 | 110 | void ad_touch_init(void); 111 | bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 112 | int16_t ad_touch_handler(void); 113 | 114 | #endif /* USE_AD_TOUCH */ 115 | 116 | #ifdef __cplusplus 117 | } /* extern "C" */ 118 | #endif 119 | 120 | #endif /* AD_TOUCH_H */ 121 | -------------------------------------------------------------------------------- /indev/FT5406EE8.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file FT5406EE8.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "FT5406EE8.h" 10 | #if USE_FT5406EE8 11 | 12 | #include 13 | #include 14 | #include LV_DRV_INDEV_INCLUDE 15 | #include LV_DRV_DELAY_INCLUDE 16 | 17 | /********************* 18 | * DEFINES 19 | *********************/ 20 | 21 | #define I2C_WR_BIT 0x00 22 | #define I2C_RD_BIT 0x01 23 | 24 | /*DEVICE MODES*/ 25 | #define OPERAT_MD 0x00 26 | #define TEST_MD 0x04 27 | #define SYS_INF_MD 0x01 28 | 29 | /*OPERATING MODE*/ 30 | #define DEVICE_MODE 0x00 31 | #define GEST_ID 0x01 32 | #define TD_STATUS 0x02 33 | 34 | #define FT5406EE8_FINGER_MAX 10 35 | 36 | /*Register addresses*/ 37 | #define FT5406EE8_REG_DEVICE_MODE 0x00 38 | #define FT5406EE8_REG_GEST_ID 0x01 39 | #define FT5406EE8_REG_TD_STATUS 0x02 40 | #define FT5406EE8_REG_YH 0x03 41 | #define FT5406EE8_REG_YL 0x04 42 | #define FT5406EE8_REG_XH 0x05 43 | #define FT5406EE8_REG_XL 0x06 44 | 45 | /********************** 46 | * TYPEDEFS 47 | **********************/ 48 | 49 | /********************** 50 | * STATIC PROTOTYPES 51 | **********************/ 52 | 53 | static bool ft5406ee8_get_touch_num(void); 54 | static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y); 55 | 56 | /********************** 57 | * STATIC VARIABLES 58 | **********************/ 59 | 60 | /********************** 61 | * MACROS 62 | **********************/ 63 | 64 | /********************** 65 | * GLOBAL FUNCTIONS 66 | **********************/ 67 | 68 | /** 69 | * 70 | */ 71 | void ft5406ee8_init(void) 72 | { 73 | 74 | } 75 | 76 | /** 77 | * Get the current position and state of the touchpad 78 | * @param data store the read data here 79 | * @return false: because no ore data to be read 80 | */ 81 | bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 82 | { 83 | static int16_t x_last; 84 | static int16_t y_last; 85 | int16_t x; 86 | int16_t y; 87 | bool valid = true; 88 | 89 | valid = ft5406ee8_get_touch_num(); 90 | if(valid == true) { 91 | valid = ft5406ee8_read_finger1(&x, &y); 92 | } 93 | 94 | if(valid == true) { 95 | x = (uint32_t)((uint32_t)x * 320) / 2048; 96 | y = (uint32_t)((uint32_t)y * 240) / 2048; 97 | 98 | 99 | x_last = x; 100 | y_last = y; 101 | } else { 102 | x = x_last; 103 | y = y_last; 104 | } 105 | 106 | data->point.x = x; 107 | data->point.y = y; 108 | data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; 109 | return false; 110 | } 111 | 112 | /********************** 113 | * STATIC FUNCTIONS 114 | **********************/ 115 | 116 | static bool ft5406ee8_get_touch_num(void) 117 | { 118 | bool ok = true; 119 | uint8_t t_num = 0; 120 | 121 | LV_DRV_INDEV_I2C_START; 122 | LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT); 123 | LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_TD_STATUS) 124 | LV_DRV_INDEV_I2C_RESTART; 125 | LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT); 126 | t_num = LV_DRV_INDEV_I2C_READ(0); 127 | 128 | /* Error if not touched or too much finger */ 129 | if(t_num > FT5406EE8_FINGER_MAX || t_num == 0) { 130 | ok = false; 131 | } 132 | 133 | return ok; 134 | } 135 | 136 | /** 137 | * Read the x and y coordinated 138 | * @param x store the x coordinate here 139 | * @param y store the y coordinate here 140 | * @return false: not valid point; true: valid point 141 | */ 142 | static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y) 143 | { 144 | uint8_t temp_xH = 0; 145 | uint8_t temp_xL = 0; 146 | uint8_t temp_yH = 0; 147 | uint8_t temp_yL = 0; 148 | 149 | /*Read Y High and low byte*/ 150 | LV_DRV_INDEV_I2C_START; 151 | LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT); 152 | LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_YH) 153 | LV_DRV_INDEV_I2C_RESTART; 154 | LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT); 155 | temp_yH = LV_DRV_INDEV_I2C_READ(1); 156 | temp_yL = LV_DRV_INDEV_I2C_READ(1); 157 | 158 | /*The upper two bit must be 2 on valid press*/ 159 | if(((temp_yH >> 6) & 0xFF) != 2) { 160 | (void) LV_DRV_INDEV_I2C_READ(0); /*Dummy read to close read sequence*/ 161 | *x = 0; 162 | *y = 0; 163 | return false; 164 | } 165 | 166 | /*Read X High and low byte*/ 167 | temp_xH = LV_DRV_INDEV_I2C_READ(1); 168 | temp_xL = LV_DRV_INDEV_I2C_READ(0); 169 | 170 | /*Save the result*/ 171 | *x = (temp_xH & 0x0F) << 8; 172 | *x += temp_xL; 173 | *y = (temp_yH & 0x0F) << 8; 174 | *y += temp_yL; 175 | 176 | return true; 177 | } 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /indev/FT5406EE8.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file FT5406EE8.h 3 | * 4 | */ 5 | 6 | #ifndef FT5406EE8_H 7 | #define FT5406EE8_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_FT5406EE8 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void ft5406ee8_init(void); 44 | bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 45 | 46 | /********************** 47 | * MACROS 48 | **********************/ 49 | 50 | #endif /* USE_FT5406EE8 */ 51 | 52 | #ifdef __cplusplus 53 | } /* extern "C" */ 54 | #endif 55 | 56 | #endif /* FT5406EE8_H */ 57 | -------------------------------------------------------------------------------- /indev/XPT2046.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file XPT2046.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "XPT2046.h" 10 | #if USE_XPT2046 11 | 12 | #include 13 | #include LV_DRV_INDEV_INCLUDE 14 | #include LV_DRV_DELAY_INCLUDE 15 | 16 | /********************* 17 | * DEFINES 18 | *********************/ 19 | #define CMD_X_READ 0b10010000 20 | #define CMD_Y_READ 0b11010000 21 | 22 | /********************** 23 | * TYPEDEFS 24 | **********************/ 25 | 26 | /********************** 27 | * STATIC PROTOTYPES 28 | **********************/ 29 | static void xpt2046_corr(int16_t * x, int16_t * y); 30 | static void xpt2046_avg(int16_t * x, int16_t * y); 31 | 32 | /********************** 33 | * STATIC VARIABLES 34 | **********************/ 35 | int16_t avg_buf_x[XPT2046_AVG]; 36 | int16_t avg_buf_y[XPT2046_AVG]; 37 | uint8_t avg_last; 38 | 39 | /********************** 40 | * MACROS 41 | **********************/ 42 | 43 | /********************** 44 | * GLOBAL FUNCTIONS 45 | **********************/ 46 | 47 | /** 48 | * Initialize the XPT2046 49 | */ 50 | void xpt2046_init(void) 51 | { 52 | 53 | } 54 | 55 | /** 56 | * Get the current position and state of the touchpad 57 | * @param data store the read data here 58 | * @return void 59 | */ 60 | void xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 61 | { 62 | static int16_t last_x = 0; 63 | static int16_t last_y = 0; 64 | uint8_t buf; 65 | 66 | int16_t x = 0; 67 | int16_t y = 0; 68 | 69 | uint8_t irq = LV_DRV_INDEV_IRQ_READ; 70 | 71 | if(irq == 0) { 72 | LV_DRV_INDEV_SPI_CS(0); 73 | 74 | LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_X_READ); /*Start x read*/ 75 | 76 | buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read x MSB*/ 77 | x = buf << 8; 78 | buf = LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_Y_READ); /*Until x LSB converted y command can be sent*/ 79 | x += buf; 80 | 81 | buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y MSB*/ 82 | y = buf << 8; 83 | 84 | buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y LSB*/ 85 | y += buf; 86 | 87 | /*Normalize Data*/ 88 | x = x >> 3; 89 | y = y >> 3; 90 | xpt2046_corr(&x, &y); 91 | xpt2046_avg(&x, &y); 92 | 93 | last_x = x; 94 | last_y = y; 95 | data->state = LV_INDEV_STATE_PR; 96 | 97 | LV_DRV_INDEV_SPI_CS(1); 98 | } else { 99 | x = last_x; 100 | y = last_y; 101 | avg_last = 0; 102 | data->state = LV_INDEV_STATE_REL; 103 | } 104 | 105 | data->point.x = x; 106 | data->point.y = y; 107 | 108 | data->continue_reading = false; /* No more data to be read */ 109 | } 110 | 111 | /********************** 112 | * STATIC FUNCTIONS 113 | **********************/ 114 | static void xpt2046_corr(int16_t * x, int16_t * y) 115 | { 116 | #if XPT2046_XY_SWAP != 0 117 | int16_t swap_tmp; 118 | swap_tmp = *x; 119 | *x = *y; 120 | *y = swap_tmp; 121 | #endif 122 | 123 | if((*x) > XPT2046_X_MIN)(*x) -= XPT2046_X_MIN; 124 | else(*x) = 0; 125 | 126 | if((*y) > XPT2046_Y_MIN)(*y) -= XPT2046_Y_MIN; 127 | else(*y) = 0; 128 | 129 | (*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) / 130 | (XPT2046_X_MAX - XPT2046_X_MIN); 131 | 132 | (*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) / 133 | (XPT2046_Y_MAX - XPT2046_Y_MIN); 134 | 135 | #if XPT2046_X_INV != 0 136 | (*x) = XPT2046_HOR_RES - (*x); 137 | #endif 138 | 139 | #if XPT2046_Y_INV != 0 140 | (*y) = XPT2046_VER_RES - (*y); 141 | #endif 142 | 143 | 144 | } 145 | 146 | 147 | static void xpt2046_avg(int16_t * x, int16_t * y) 148 | { 149 | /*Shift out the oldest data*/ 150 | uint8_t i; 151 | for(i = XPT2046_AVG - 1; i > 0 ; i--) { 152 | avg_buf_x[i] = avg_buf_x[i - 1]; 153 | avg_buf_y[i] = avg_buf_y[i - 1]; 154 | } 155 | 156 | /*Insert the new point*/ 157 | avg_buf_x[0] = *x; 158 | avg_buf_y[0] = *y; 159 | if(avg_last < XPT2046_AVG) avg_last++; 160 | 161 | /*Sum the x and y coordinates*/ 162 | int32_t x_sum = 0; 163 | int32_t y_sum = 0; 164 | for(i = 0; i < avg_last ; i++) { 165 | x_sum += avg_buf_x[i]; 166 | y_sum += avg_buf_y[i]; 167 | } 168 | 169 | /*Normalize the sums*/ 170 | (*x) = (int32_t)x_sum / avg_last; 171 | (*y) = (int32_t)y_sum / avg_last; 172 | } 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /indev/XPT2046.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file XPT2046.h 3 | * 4 | */ 5 | 6 | #ifndef XPT2046_H 7 | #define XPT2046_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_XPT2046 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void xpt2046_init(void); 44 | void xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 45 | 46 | /********************** 47 | * MACROS 48 | **********************/ 49 | 50 | #endif /* USE_XPT2046 */ 51 | 52 | #ifdef __cplusplus 53 | } /* extern "C" */ 54 | #endif 55 | 56 | #endif /* XPT2046_H */ 57 | -------------------------------------------------------------------------------- /indev/evdev.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file evdev.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "evdev.h" 10 | #if USE_EVDEV != 0 || USE_BSD_EVDEV 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #if USE_BSD_EVDEV 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | #if USE_XKB 23 | #include "xkb.h" 24 | #endif /* USE_XKB */ 25 | 26 | /********************** 27 | * STATIC VARIABLES 28 | **********************/ 29 | 30 | evdev_device_t global_dsc; 31 | 32 | /********************** 33 | * STATIC FUNCTIONS 34 | **********************/ 35 | 36 | static int _evdev_process_key(uint16_t code, bool pressed) 37 | { 38 | #if USE_XKB 39 | return xkb_process_key(code, pressed); 40 | #else 41 | LV_UNUSED(pressed); 42 | switch(code) { 43 | case KEY_UP: 44 | return LV_KEY_UP; 45 | case KEY_DOWN: 46 | return LV_KEY_DOWN; 47 | case KEY_RIGHT: 48 | return LV_KEY_RIGHT; 49 | case KEY_LEFT: 50 | return LV_KEY_LEFT; 51 | case KEY_ESC: 52 | return LV_KEY_ESC; 53 | case KEY_DELETE: 54 | return LV_KEY_DEL; 55 | case KEY_BACKSPACE: 56 | return LV_KEY_BACKSPACE; 57 | case KEY_ENTER: 58 | return LV_KEY_ENTER; 59 | case KEY_NEXT: 60 | case KEY_TAB: 61 | return LV_KEY_NEXT; 62 | case KEY_PREVIOUS: 63 | return LV_KEY_PREV; 64 | case KEY_HOME: 65 | return LV_KEY_HOME; 66 | case KEY_END: 67 | return LV_KEY_END; 68 | default: 69 | return 0; 70 | } 71 | #endif /*USE_XKB*/ 72 | } 73 | 74 | static int _evdev_calibrate(int v, int in_min, int in_max, int out_min, int out_max) 75 | { 76 | if(in_min != in_max) v = (v - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 77 | return LV_CLAMP(out_min, v, out_max); 78 | } 79 | 80 | static lv_point_t _evdev_process_pointer(lv_indev_drv_t * drv, int x, int y) 81 | { 82 | evdev_device_t * dsc = drv->user_data ? drv->user_data : &global_dsc; 83 | 84 | int swapped_x = dsc->swap_axes ? y : x; 85 | int swapped_y = dsc->swap_axes ? x : y; 86 | 87 | int offset_x = 0; /*Not lv_disp_get_offset_x(drv->disp) for bc*/ 88 | int offset_y = 0; /*Not lv_disp_get_offset_y(drv->disp) for bc*/ 89 | int width = lv_disp_get_hor_res(drv->disp); 90 | int height = lv_disp_get_ver_res(drv->disp); 91 | 92 | lv_point_t p; 93 | p.x = _evdev_calibrate(swapped_x, dsc->hor_min, dsc->hor_max, offset_x, offset_x + width - 1); 94 | p.y = _evdev_calibrate(swapped_y, dsc->ver_min, dsc->ver_max, offset_y, offset_y + height - 1); 95 | return p; 96 | } 97 | 98 | /********************** 99 | * GLOBAL FUNCTIONS 100 | **********************/ 101 | 102 | void evdev_init() 103 | { 104 | evdev_device_init(&global_dsc); 105 | #ifdef EVDEV_SWAP_AXES 106 | evdev_device_set_swap_axes(&global_dsc, EVDEV_SWAP_AXES); 107 | #endif 108 | #if EVDEV_CALIBRATE 109 | evdev_device_set_calibration(&global_dsc, EVDEV_HOR_MIN, EVDEV_VER_MIN, EVDEV_HOR_MAX, EVDEV_VER_MAX); 110 | #endif 111 | evdev_device_set_file(&global_dsc, EVDEV_NAME); 112 | } 113 | 114 | void evdev_device_init(evdev_device_t * dsc) 115 | { 116 | lv_memset(dsc, 0, sizeof(evdev_device_t)); 117 | dsc->fd = -1; 118 | 119 | #if USE_XKB 120 | xkb_init(); 121 | #endif 122 | } 123 | 124 | bool evdev_set_file(const char * dev_path) 125 | { 126 | return evdev_device_set_file(&global_dsc, dev_path); 127 | } 128 | 129 | bool evdev_device_set_file(evdev_device_t * dsc, const char * dev_path) 130 | { 131 | /*Reset state*/ 132 | dsc->root_x = 0; 133 | dsc->root_y = 0; 134 | dsc->key = 0; 135 | dsc->state = LV_INDEV_STATE_RELEASED; 136 | 137 | /*Close previous*/ 138 | if(dsc->fd >= 0) { 139 | close(dsc->fd); 140 | dsc->fd = -1; 141 | } 142 | if(!dev_path) return false; 143 | 144 | /*Open new*/ 145 | dsc->fd = open(dev_path, O_RDONLY | O_NOCTTY | O_CLOEXEC); 146 | if(dsc->fd < 0) { 147 | LV_LOG_ERROR("open failed: %s", strerror(errno)); 148 | return false; 149 | } 150 | if(fcntl(dsc->fd, F_SETFL, O_NONBLOCK) < 0) { 151 | LV_LOG_ERROR("fcntl failed: %s", strerror(errno)); 152 | close(dsc->fd); 153 | dsc->fd = -1; 154 | return false; 155 | } 156 | 157 | return true; 158 | } 159 | 160 | void evdev_device_set_swap_axes(evdev_device_t * dsc, bool swap_axes) 161 | { 162 | dsc->swap_axes = swap_axes; 163 | } 164 | 165 | void evdev_device_set_calibration(evdev_device_t * dsc, int ver_min, int hor_min, int ver_max, int hor_max) 166 | { 167 | dsc->ver_min = ver_min; 168 | dsc->hor_min = hor_min; 169 | dsc->ver_max = ver_max; 170 | dsc->hor_max = hor_max; 171 | } 172 | 173 | void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data) 174 | { 175 | evdev_device_t * dsc = drv->user_data ? drv->user_data : &global_dsc; 176 | if(dsc->fd < 0) return; 177 | 178 | /*Update dsc with buffered events*/ 179 | struct input_event in = { 0 }; 180 | while(read(dsc->fd, &in, sizeof(in)) > 0) { 181 | if(in.type == EV_REL) { 182 | if(in.code == REL_X) dsc->root_x += in.value; 183 | else if(in.code == REL_Y) dsc->root_y += in.value; 184 | } 185 | else if(in.type == EV_ABS) { 186 | if(in.code == ABS_X || in.code == ABS_MT_POSITION_X) dsc->root_x = in.value; 187 | else if(in.code == ABS_Y || in.code == ABS_MT_POSITION_Y) dsc->root_y = in.value; 188 | else if(in.code == ABS_MT_TRACKING_ID) { 189 | if(in.value == -1) dsc->state = LV_INDEV_STATE_RELEASED; 190 | else if(in.value == 0) dsc->state = LV_INDEV_STATE_PRESSED; 191 | } 192 | } 193 | else if(in.type == EV_KEY) { 194 | if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) { 195 | if(in.value == 0) dsc->state = LV_INDEV_STATE_RELEASED; 196 | else if(in.value == 1) dsc->state = LV_INDEV_STATE_PRESSED; 197 | } 198 | else { 199 | dsc->key = _evdev_process_key(in.code, in.value != 0); 200 | if(dsc->key) { 201 | dsc->state = in.value ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; 202 | data->continue_reading = true; /*Keep following events in buffer for now*/ 203 | break; 204 | } 205 | } 206 | } 207 | } 208 | 209 | /*Process and store in data*/ 210 | switch(drv->type) { 211 | case LV_INDEV_TYPE_KEYPAD: 212 | data->state = dsc->state; 213 | data->key = dsc->key; 214 | break; 215 | case LV_INDEV_TYPE_POINTER: 216 | data->state = dsc->state; 217 | data->point = _evdev_process_pointer(drv, dsc->root_x, dsc->root_y); 218 | break; 219 | default: 220 | break; 221 | } 222 | } 223 | 224 | #endif /*USE_EVDEV*/ 225 | -------------------------------------------------------------------------------- /indev/evdev.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file evdev.h 3 | * 4 | */ 5 | 6 | #ifndef EVDEV_H 7 | #define EVDEV_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_EVDEV || USE_BSD_EVDEV 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************** 33 | * TYPEDEFS 34 | **********************/ 35 | 36 | typedef struct { 37 | /*Device*/ 38 | int fd; 39 | /*Config*/ 40 | bool swap_axes; 41 | int ver_min; 42 | int hor_min; 43 | int ver_max; 44 | int hor_max; 45 | /*State*/ 46 | int root_x; 47 | int root_y; 48 | int key; 49 | lv_indev_state_t state; 50 | } evdev_device_t; 51 | 52 | /********************** 53 | * GLOBAL PROTOTYPES 54 | **********************/ 55 | 56 | /** 57 | * Initialize the global evdev device, as configured with EVDEV_NAME, 58 | * EVDEV_SWAP_AXES, and EVDEV_CALIBRATE. 59 | */ 60 | void evdev_init(); 61 | /** 62 | * Initialize an evdev device. 63 | * @param dsc evdev device 64 | */ 65 | void evdev_device_init(evdev_device_t * dsc); 66 | 67 | /** 68 | * Reconfigure the path for the global evdev device. 69 | * @param dev_path device path, e.g., /dev/input/event0, or NULL to close 70 | * @return whether the device was successfully opened 71 | */ 72 | bool evdev_set_file(const char * dev_path); 73 | /** 74 | * Configure or reconfigure the path for an evdev device. 75 | * @param dsc evdev device 76 | * @param dev_path device path, e.g., /dev/input/event0, or NULL to close 77 | * @return whether the device was successfully opened 78 | */ 79 | bool evdev_device_set_file(evdev_device_t * dsc, const char * dev_path); 80 | 81 | /** 82 | * Configure whether pointer coordinates of an evdev device sould be swapped. 83 | * Default to false. 84 | * @param dsc evdev device 85 | * @param swap_axes whether to swap x and y axes 86 | */ 87 | void evdev_device_set_swap_axes(evdev_device_t * dsc, bool swap_axes); 88 | 89 | /** 90 | * Configure a coordinate transformation for an evdev device. Applied after 91 | * axis swap, if any. Defaults to no transformation. 92 | * @param dsc evdev device 93 | * @param hor_min horizontal pointer coordinate mapped to 0 94 | * @param ver_min vertical pointer coordinate mapped to 0 95 | * @param ver_min pointer coordinate mapped to horizontal max of display 96 | * @param ver_max pointer coordinate mapped to vertical max of display 97 | */ 98 | void evdev_device_set_calibration(evdev_device_t * dsc, int hor_min, int ver_min, int hor_max, int ver_max); 99 | 100 | /** 101 | * Read callback for the input driver. 102 | * @param drv input driver where drv->user_data is NULL for the global evdev 103 | * device or an evdev_device_t pointer. 104 | * @param data destination for input events 105 | */ 106 | void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data); 107 | 108 | #endif /* USE_EVDEV */ 109 | 110 | #ifdef __cplusplus 111 | } /* extern "C" */ 112 | #endif 113 | 114 | #endif /* EVDEV_H */ 115 | -------------------------------------------------------------------------------- /indev/keyboard.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file keyboard.h 3 | * 4 | */ 5 | 6 | #ifndef KEYBOARD_H 7 | #define KEYBOARD_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_KEYBOARD 25 | 26 | #warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c" 27 | 28 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 29 | #include "lvgl.h" 30 | #else 31 | #include "lvgl/lvgl.h" 32 | #endif 33 | 34 | #if USE_SDL_GPU 35 | #include "../sdl/sdl_gpu.h" 36 | #else 37 | #include "../sdl/sdl.h" 38 | #endif 39 | 40 | /********************* 41 | * DEFINES 42 | *********************/ 43 | 44 | /********************** 45 | * TYPEDEFS 46 | **********************/ 47 | 48 | /********************** 49 | * GLOBAL PROTOTYPES 50 | **********************/ 51 | 52 | /** 53 | * Initialize the keyboard 54 | */ 55 | static inline void keyboard_init(void) 56 | { 57 | /*Nothing to do*/ 58 | } 59 | 60 | /** 61 | * Get the last pressed or released character from the PC's keyboard 62 | * @param indev_drv pointer to the related input device driver 63 | * @param data store the read data here 64 | */ 65 | static inline void keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 66 | { 67 | sdl_keyboard_read(indev_drv, data); 68 | } 69 | 70 | 71 | /********************** 72 | * MACROS 73 | **********************/ 74 | 75 | #endif /*USE_KEYBOARD*/ 76 | 77 | #ifdef __cplusplus 78 | } /* extern "C" */ 79 | #endif 80 | 81 | #endif /*KEYBOARD_H*/ 82 | -------------------------------------------------------------------------------- /indev/libinput_drv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file libinput.h 3 | * 4 | */ 5 | 6 | #ifndef LVGL_LIBINPUT_H 7 | #define LVGL_LIBINPUT_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_LIBINPUT || USE_BSD_LIBINPUT 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | #include 33 | 34 | #if USE_XKB 35 | #include "xkb.h" 36 | #endif /* USE_XKB */ 37 | 38 | /********************* 39 | * DEFINES 40 | *********************/ 41 | 42 | /********************** 43 | * TYPEDEFS 44 | **********************/ 45 | typedef enum { 46 | LIBINPUT_CAPABILITY_NONE = 0, 47 | LIBINPUT_CAPABILITY_KEYBOARD = 1U << 0, 48 | LIBINPUT_CAPABILITY_POINTER = 1U << 1, 49 | LIBINPUT_CAPABILITY_TOUCH = 1U << 2 50 | } libinput_capability; 51 | 52 | typedef struct { 53 | int fd; 54 | struct pollfd fds[1]; 55 | 56 | int button; 57 | int key_val; 58 | lv_point_t most_recent_touch_point; 59 | 60 | struct libinput *libinput_context; 61 | struct libinput_device *libinput_device; 62 | 63 | #if USE_XKB 64 | xkb_drv_state_t xkb_state; 65 | #endif /* USE_XKB */ 66 | } libinput_drv_state_t; 67 | 68 | /********************** 69 | * GLOBAL PROTOTYPES 70 | **********************/ 71 | 72 | /** 73 | * Determine the capabilities of a specific libinput device. 74 | * @param device the libinput device to query 75 | * @return the supported input capabilities 76 | */ 77 | libinput_capability libinput_query_capability(struct libinput_device *device); 78 | /** 79 | * Find connected input device with specific capabilities 80 | * @param capabilities required device capabilities 81 | * @param force_rescan erase the device cache (if any) and rescan the file system for available devices 82 | * @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found. 83 | * The pointer is safe to use until the next forceful device search. 84 | */ 85 | char *libinput_find_dev(libinput_capability capabilities, bool force_rescan); 86 | /** 87 | * Find connected input devices with specific capabilities 88 | * @param capabilities required device capabilities 89 | * @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are 90 | * safe to use until the next forceful device search. 91 | * @param count maximum number of devices to find (the devices array should be at least this long) 92 | * @param force_rescan erase the device cache (if any) and rescan the file system for available devices 93 | * @return number of devices that were found 94 | */ 95 | size_t libinput_find_devs(libinput_capability capabilities, char **found, size_t count, bool force_rescan); 96 | /** 97 | * Prepare for reading input via libinput using the default driver state. Use this function if you only want 98 | * to connect a single device. 99 | */ 100 | void libinput_init(void); 101 | /** 102 | * Prepare for reading input via libinput using a specific driver state. Use this function if you want to 103 | * connect multiple devices. 104 | * @param state driver state to initialize 105 | * @param path input device node path (e.g. /dev/input/event0) 106 | */ 107 | void libinput_init_state(libinput_drv_state_t *state, char* path); 108 | /** 109 | * De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to 110 | * reuse an existing driver state. 111 | * @param state driver state to de-initialize 112 | */ 113 | void libinput_deinit_state(libinput_drv_state_t *state); 114 | /** 115 | * Reconfigure the device file for libinput using the default driver state. Use this function if you only want 116 | * to connect a single device. 117 | * @param dev_name input device node path (e.g. /dev/input/event0) 118 | * @return true: the device file set complete 119 | * false: the device file doesn't exist current system 120 | */ 121 | bool libinput_set_file(char* dev_name); 122 | /** 123 | * Reconfigure the device file for libinput using a specific driver state. Use this function if you want to 124 | * connect multiple devices. 125 | * @param state the driver state to configure 126 | * @param dev_name input device node path (e.g. /dev/input/event0) 127 | * @return true: the device file set complete 128 | * false: the device file doesn't exist current system 129 | */ 130 | bool libinput_set_file_state(libinput_drv_state_t *state, char* dev_name); 131 | /** 132 | * Read available input events via libinput using the default driver state. Use this function if you only want 133 | * to connect a single device. 134 | * @param indev_drv driver object itself 135 | * @param data store the libinput data here 136 | */ 137 | void libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 138 | /** 139 | * Read available input events via libinput using a specific driver state. Use this function if you want to 140 | * connect multiple devices. 141 | * @param state the driver state to use 142 | * @param indev_drv driver object itself 143 | * @param data store the libinput data here 144 | */ 145 | void libinput_read_state(libinput_drv_state_t * state, lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 146 | 147 | /********************** 148 | * MACROS 149 | **********************/ 150 | 151 | #endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */ 152 | 153 | #ifdef __cplusplus 154 | } /* extern "C" */ 155 | #endif 156 | 157 | #endif /* LVGL_LIBINPUT_H */ 158 | -------------------------------------------------------------------------------- /indev/mouse.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mouse.h 3 | * 4 | */ 5 | 6 | #ifndef MOUSE_H 7 | #define MOUSE_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_MOUSE 25 | 26 | #warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c" 27 | 28 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 29 | #include "lvgl.h" 30 | #else 31 | #include "lvgl/lvgl.h" 32 | #endif 33 | 34 | #if USE_SDL_GPU 35 | #include "../sdl/sdl_gpu.h" 36 | #else 37 | #include "../sdl/sdl.h" 38 | #endif 39 | 40 | /********************* 41 | * DEFINES 42 | *********************/ 43 | 44 | /********************** 45 | * TYPEDEFS 46 | **********************/ 47 | 48 | /********************** 49 | * GLOBAL PROTOTYPES 50 | **********************/ 51 | 52 | 53 | /** 54 | * Initialize the mouse 55 | */ 56 | static inline void mouse_init(void) 57 | { 58 | /*Nothing to do*/ 59 | } 60 | 61 | /** 62 | * Get the current position and state of the mouse 63 | * @param indev_drv pointer to the related input device driver 64 | * @param data store the mouse data here 65 | */ 66 | void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 67 | { 68 | sdl_mouse_read(indev_drv, data); 69 | } 70 | 71 | /********************** 72 | * MACROS 73 | **********************/ 74 | 75 | #endif /* USE_MOUSE */ 76 | 77 | #ifdef __cplusplus 78 | } /* extern "C" */ 79 | #endif 80 | 81 | #endif /* MOUSE_H */ 82 | -------------------------------------------------------------------------------- /indev/mousewheel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mousewheel.h 3 | * 4 | */ 5 | 6 | #ifndef MOUSEWHEEL_H 7 | #define MOUSEWHEEL_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_MOUSEWHEEL 25 | 26 | #warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c" 27 | 28 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 29 | #include "lvgl.h" 30 | #else 31 | #include "lvgl/lvgl.h" 32 | #endif 33 | 34 | #if USE_SDL_GPU 35 | #include "../sdl/sdl_gpu.h" 36 | #else 37 | #include "../sdl/sdl.h" 38 | #endif 39 | 40 | /********************* 41 | * DEFINES 42 | *********************/ 43 | 44 | /********************** 45 | * TYPEDEFS 46 | **********************/ 47 | 48 | /********************** 49 | * GLOBAL PROTOTYPES 50 | **********************/ 51 | 52 | /** 53 | * Initialize the encoder 54 | */ 55 | static inline void mousewheel_init(void) 56 | { 57 | /*Nothing to do*/ 58 | } 59 | 60 | /** 61 | * Get encoder (i.e. mouse wheel) ticks difference and pressed state 62 | * @param indev_drv pointer to the related input device driver 63 | * @param data store the read data here 64 | */ 65 | static inline void mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 66 | { 67 | sdl_mousewheel_read(indev_drv, data); 68 | } 69 | 70 | /********************** 71 | * MACROS 72 | **********************/ 73 | 74 | #endif /*USE_MOUSEWHEEL*/ 75 | 76 | #ifdef __cplusplus 77 | } /* extern "C" */ 78 | #endif 79 | 80 | #endif /*MOUSEWHEEL_H*/ 81 | -------------------------------------------------------------------------------- /indev/xkb.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file xkb.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "xkb.h" 10 | #if USE_XKB 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /********************* 19 | * DEFINES 20 | *********************/ 21 | 22 | /********************** 23 | * TYPEDEFS 24 | **********************/ 25 | 26 | /********************** 27 | * STATIC PROTOTYPES 28 | **********************/ 29 | 30 | /********************** 31 | * STATIC VARIABLES 32 | **********************/ 33 | static struct xkb_context *context = NULL; 34 | static xkb_drv_state_t default_state = { .keymap = NULL, .state = NULL }; 35 | 36 | /********************** 37 | * MACROS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL FUNCTIONS 42 | **********************/ 43 | 44 | /** 45 | * Initialise the XKB system using the default driver state. Use this function if you only want 46 | * to connect a single device. 47 | * @return true if the initialisation was successful 48 | */ 49 | bool xkb_init(void) { 50 | return xkb_init_state(&default_state); 51 | } 52 | 53 | /** 54 | * Initialise the XKB system using a specific driver state. Use this function if you want to 55 | * connect multiple devices. 56 | * @param state XKB driver state to use 57 | * @return true if the initialisation was successful 58 | */ 59 | bool xkb_init_state(xkb_drv_state_t *state) { 60 | if (!context) { 61 | context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); 62 | if (!context) { 63 | perror("could not create new XKB context"); 64 | return false; 65 | } 66 | } 67 | 68 | #ifdef XKB_KEY_MAP 69 | struct xkb_rule_names names = XKB_KEY_MAP; 70 | return xkb_set_keymap_state(state, names); 71 | #else 72 | return false; /* Keymap needs to be set manually using xkb_set_keymap_state to complete initialisation */ 73 | #endif 74 | } 75 | 76 | /** 77 | * De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to 78 | * reuse an existing driver state. 79 | * @param state XKB driver state to use 80 | */ 81 | void xkb_deinit_state(xkb_drv_state_t *state) { 82 | if (state->state) { 83 | xkb_state_unref(state->state); 84 | state->state = NULL; 85 | } 86 | 87 | if (state->keymap) { 88 | xkb_keymap_unref(state->keymap); 89 | state->keymap = NULL; 90 | } 91 | } 92 | 93 | /** 94 | * Set a new keymap to be used for processing future key events using the default driver state. Use 95 | * this function if you only want to connect a single device. 96 | * @param names XKB rule names structure (use NULL components for default values) 97 | * @return true if creating the keymap and associated state succeeded 98 | */ 99 | bool xkb_set_keymap(struct xkb_rule_names names) { 100 | return xkb_set_keymap_state(&default_state, names); 101 | } 102 | 103 | /** 104 | * Set a new keymap to be used for processing future key events using a specific driver state. Use 105 | * this function if you want to connect multiple devices. 106 | * @param state XKB driver state to use 107 | * @param names XKB rule names structure (use NULL components for default values) 108 | * @return true if creating the keymap and associated state succeeded 109 | */ 110 | bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names) { 111 | if (state->keymap) { 112 | xkb_keymap_unref(state->keymap); 113 | state->keymap = NULL; 114 | } 115 | 116 | state->keymap = xkb_keymap_new_from_names(context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); 117 | if (!state->keymap) { 118 | perror("could not create XKB keymap"); 119 | return false; 120 | } 121 | 122 | if (state->state) { 123 | xkb_state_unref(state->state); 124 | state->state = NULL; 125 | } 126 | 127 | state->state = xkb_state_new(state->keymap); 128 | if (!state->state) { 129 | perror("could not create XKB state"); 130 | return false; 131 | } 132 | 133 | return true; 134 | } 135 | 136 | /** 137 | * Process an evdev scancode using the default driver state. Use this function if you only want to 138 | * connect a single device. 139 | * @param scancode evdev scancode to process 140 | * @param down true if the key was pressed, false if it was releases 141 | * @return the (first) UTF-8 character produced by the event or 0 if no output was produced 142 | */ 143 | uint32_t xkb_process_key(uint32_t scancode, bool down) { 144 | return xkb_process_key_state(&default_state, scancode, down); 145 | } 146 | 147 | /** 148 | * Process an evdev scancode using a specific driver state. Use this function if you want to connect 149 | * multiple devices. 150 | * @param state XKB driver state to use 151 | * @param scancode evdev scancode to process 152 | * @param down true if the key was pressed, false if it was releases 153 | * @return the (first) UTF-8 character produced by the event or 0 if no output was produced 154 | */ 155 | uint32_t xkb_process_key_state(xkb_drv_state_t *state, uint32_t scancode, bool down) { 156 | /* Offset the evdev scancode by 8, see https://xkbcommon.org/doc/current/xkbcommon_8h.html#ac29aee92124c08d1953910ab28ee1997 */ 157 | xkb_keycode_t keycode = scancode + 8; 158 | 159 | uint32_t result = 0; 160 | 161 | switch (xkb_state_key_get_one_sym(state->state, keycode)) { 162 | case XKB_KEY_BackSpace: 163 | result = LV_KEY_BACKSPACE; 164 | break; 165 | case XKB_KEY_Return: 166 | case XKB_KEY_KP_Enter: 167 | result = LV_KEY_ENTER; 168 | break; 169 | case XKB_KEY_Prior: 170 | case XKB_KEY_KP_Prior: 171 | result = LV_KEY_PREV; 172 | break; 173 | case XKB_KEY_Next: 174 | case XKB_KEY_KP_Next: 175 | result = LV_KEY_NEXT; 176 | break; 177 | case XKB_KEY_Up: 178 | case XKB_KEY_KP_Up: 179 | result = LV_KEY_UP; 180 | break; 181 | case XKB_KEY_Left: 182 | case XKB_KEY_KP_Left: 183 | result = LV_KEY_LEFT; 184 | break; 185 | case XKB_KEY_Right: 186 | case XKB_KEY_KP_Right: 187 | result = LV_KEY_RIGHT; 188 | break; 189 | case XKB_KEY_Down: 190 | case XKB_KEY_KP_Down: 191 | result = LV_KEY_DOWN; 192 | break; 193 | case XKB_KEY_Tab: 194 | case XKB_KEY_KP_Tab: 195 | result = LV_KEY_NEXT; 196 | break; 197 | case XKB_KEY_ISO_Left_Tab: /* Sent on SHIFT + TAB */ 198 | result = LV_KEY_PREV; 199 | break; 200 | default: 201 | break; 202 | } 203 | 204 | if (result == 0) { 205 | char buffer[4] = { 0, 0, 0, 0 }; 206 | int size = xkb_state_key_get_utf8(state->state, keycode, NULL, 0) + 1; 207 | if (size > 1) { 208 | xkb_state_key_get_utf8(state->state, keycode, buffer, size); 209 | memcpy(&result, buffer, 4); 210 | } 211 | } 212 | 213 | xkb_state_update_key(state->state, keycode, down ? XKB_KEY_DOWN : XKB_KEY_UP); 214 | 215 | return result; 216 | } 217 | 218 | /********************** 219 | * STATIC FUNCTIONS 220 | **********************/ 221 | 222 | #endif /* USE_XKB */ 223 | -------------------------------------------------------------------------------- /indev/xkb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file xkb.h 3 | * 4 | */ 5 | 6 | #ifndef XKB_H 7 | #define XKB_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_XKB 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | struct xkb_rule_names; 40 | 41 | typedef struct { 42 | struct xkb_keymap *keymap; 43 | struct xkb_state *state; 44 | } xkb_drv_state_t; 45 | 46 | /********************** 47 | * GLOBAL PROTOTYPES 48 | **********************/ 49 | 50 | /** 51 | * Initialise the XKB system using the default driver state. Use this function if you only want 52 | * to connect a single device. 53 | * @return true if the initialisation was successful 54 | */ 55 | bool xkb_init(void); 56 | /** 57 | * Initialise the XKB system using a specific driver state. Use this function if you want to 58 | * connect multiple devices. 59 | * @param state XKB driver state to use 60 | * @return true if the initialisation was successful 61 | */ 62 | bool xkb_init_state(xkb_drv_state_t *state); 63 | /** 64 | * De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to 65 | * reuse an existing driver state. 66 | * @param state XKB driver state to use 67 | */ 68 | void xkb_deinit_state(xkb_drv_state_t *state); 69 | /** 70 | * Set a new keymap to be used for processing future key events using the default driver state. Use 71 | * this function if you only want to connect a single device. 72 | * @param names XKB rule names structure (use NULL components for default values) 73 | * @return true if creating the keymap and associated state succeeded 74 | */ 75 | bool xkb_set_keymap(struct xkb_rule_names names); 76 | /** 77 | * Set a new keymap to be used for processing future key events using a specific driver state. Use 78 | * this function if you want to connect multiple devices. 79 | * @param state XKB driver state to use 80 | * @param names XKB rule names structure (use NULL components for default values) 81 | * @return true if creating the keymap and associated state succeeded 82 | */ 83 | bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names); 84 | /** 85 | * Process an evdev scancode using the default driver state. Use this function if you only want to 86 | * connect a single device. 87 | * @param scancode evdev scancode to process 88 | * @param down true if the key was pressed, false if it was releases 89 | * @return the (first) UTF-8 character produced by the event or 0 if no output was produced 90 | */ 91 | uint32_t xkb_process_key(uint32_t scancode, bool down); 92 | /** 93 | * Process an evdev scancode using a specific driver state. Use this function if you want to connect 94 | * multiple devices. 95 | * @param state XKB driver state to use 96 | * @param scancode evdev scancode to process 97 | * @param down true if the key was pressed, false if it was releases 98 | * @return the (first) UTF-8 character produced by the event or 0 if no output was produced 99 | */ 100 | uint32_t xkb_process_key_state(xkb_drv_state_t *state, uint32_t scancode, bool down); 101 | 102 | /********************** 103 | * MACROS 104 | **********************/ 105 | 106 | #endif /* USE_XKB */ 107 | 108 | #ifdef __cplusplus 109 | } /* extern "C" */ 110 | #endif 111 | 112 | #endif /* XKB_H */ 113 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lv_drivers", 3 | "version": "9.0.0-dev", 4 | "keywords": "littlevgl, lvgl, driver, display, touchpad", 5 | "description": "Drivers for LittlevGL graphics library.", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/littlevgl/lv_drivers.git" 9 | }, 10 | "build": { 11 | "includeDir": "." 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lv-drivers.pc.in: -------------------------------------------------------------------------------- 1 | prefix="@CMAKE_INSTALL_PREFIX@" 2 | includedir="${prefix}/@INC_INSTALL_DIR@" 3 | libdir=${prefix}/lib 4 | 5 | Name: lv-drivers 6 | Description: Display controller and touchpad driver that can be directly used with LVGL 7 | URL: https://lvgl.io/ 8 | Version: 9.0.0 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -llv_drivers 11 | Requires: lvgl 12 | -------------------------------------------------------------------------------- /lv_drivers.mk: -------------------------------------------------------------------------------- 1 | LV_DRIVERS_PATH ?= ${shell pwd}/lv_drivers 2 | 3 | CSRCS += $(shell find $(LV_DRIVERS_PATH) -type f -name '*.c') 4 | CFLAGS += "-I$(LV_DRIVERS_PATH)" 5 | 6 | -------------------------------------------------------------------------------- /sdl/sdl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sdl.h 3 | * 4 | */ 5 | 6 | #ifndef SDL_H 7 | #define SDL_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_MONITOR || USE_SDL 25 | 26 | #include "sdl_common.h" 27 | 28 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 29 | #include "lvgl.h" 30 | #else 31 | #include "lvgl/lvgl.h" 32 | #endif 33 | 34 | /********************* 35 | * DEFINES 36 | *********************/ 37 | 38 | /********************** 39 | * TYPEDEFS 40 | **********************/ 41 | 42 | /********************** 43 | * GLOBAL PROTOTYPES 44 | **********************/ 45 | 46 | /** 47 | * Initialize SDL to be used as display, mouse and mouse wheel drivers. 48 | */ 49 | void sdl_init(void); 50 | 51 | /** 52 | * Flush a buffer to the marked area 53 | * @param disp_drv pointer to driver where this function belongs 54 | * @param area an area where to copy `color_p` 55 | * @param color_p an array of pixels to copy to the `area` part of the screen 56 | */ 57 | void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 58 | 59 | /** 60 | * Flush a buffer to the marked area 61 | * @param disp_drv pointer to driver where this function belongs 62 | * @param area an area where to copy `color_p` 63 | * @param color_p an array of pixels to copy to the `area` part of the screen 64 | */ 65 | void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 66 | 67 | /** 68 | * Get the current position and state of the mouse 69 | * @param indev_drv pointer to the related input device driver 70 | * @param data store the mouse data here 71 | */ 72 | void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 73 | 74 | /** 75 | * Get encoder (i.e. mouse wheel) ticks difference and pressed state 76 | * @param indev_drv pointer to the related input device driver 77 | * @param data store the read data here 78 | */ 79 | void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 80 | 81 | /** 82 | * Get input from the keyboard. 83 | * @param indev_drv pointer to the related input device driver 84 | * @param data store the red data here 85 | */ 86 | void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 87 | 88 | /*For backward compatibility. Will be removed.*/ 89 | #define monitor_init sdl_init 90 | #define monitor_flush sdl_display_flush 91 | #define monitor_flush2 sdl_display_flush2 92 | 93 | /********************** 94 | * MACROS 95 | **********************/ 96 | 97 | #endif /* USE_MONITOR || USE_SDL */ 98 | 99 | #ifdef __cplusplus 100 | } /* extern "C" */ 101 | #endif 102 | 103 | #endif /* SDL_H */ 104 | -------------------------------------------------------------------------------- /sdl/sdl_common.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mariotaku on 2021/10/14. 3 | // 4 | 5 | #include "sdl_common.h" 6 | 7 | #if USE_SDL || USE_SDL_GPU 8 | #include "sdl_common_internal.h" 9 | 10 | /********************* 11 | * DEFINES 12 | *********************/ 13 | 14 | #ifndef KEYBOARD_BUFFER_SIZE 15 | #define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE 16 | #endif 17 | 18 | /********************** 19 | * STATIC PROTOTYPES 20 | **********************/ 21 | 22 | 23 | /********************** 24 | * STATIC VARIABLES 25 | **********************/ 26 | 27 | volatile bool sdl_quit_qry = false; 28 | 29 | static bool left_button_down = false; 30 | static int16_t last_x = 0; 31 | static int16_t last_y = 0; 32 | 33 | static int16_t wheel_diff = 0; 34 | static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED; 35 | 36 | static char buf[KEYBOARD_BUFFER_SIZE]; 37 | 38 | /********************** 39 | * GLOBAL FUNCTIONS 40 | **********************/ 41 | /** 42 | * Get the current position and state of the mouse 43 | * @param indev_drv pointer to the related input device driver 44 | * @param data store the mouse data here 45 | */ 46 | void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 47 | { 48 | (void) indev_drv; /*Unused*/ 49 | 50 | /*Store the collected data*/ 51 | data->point.x = last_x; 52 | data->point.y = last_y; 53 | data->state = left_button_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; 54 | } 55 | 56 | 57 | /** 58 | * Get encoder (i.e. mouse wheel) ticks difference and pressed state 59 | * @param indev_drv pointer to the related input device driver 60 | * @param data store the read data here 61 | */ 62 | void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 63 | { 64 | (void) indev_drv; /*Unused*/ 65 | 66 | data->state = wheel_state; 67 | data->enc_diff = wheel_diff; 68 | wheel_diff = 0; 69 | } 70 | 71 | /** 72 | * Get input from the keyboard. 73 | * @param indev_drv pointer to the related input device driver 74 | * @param data store the red data here 75 | */ 76 | void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) 77 | { 78 | (void) indev_drv; /*Unused*/ 79 | 80 | static bool dummy_read = false; 81 | const size_t len = strlen(buf); 82 | 83 | /*Send a release manually*/ 84 | if (dummy_read) { 85 | dummy_read = false; 86 | data->state = LV_INDEV_STATE_RELEASED; 87 | data->continue_reading = len > 0; 88 | } 89 | /*Send the pressed character*/ 90 | else if (len > 0) { 91 | dummy_read = true; 92 | data->state = LV_INDEV_STATE_PRESSED; 93 | data->key = buf[0]; 94 | memmove(buf, buf + 1, len); 95 | data->continue_reading = true; 96 | } 97 | } 98 | 99 | /********************** 100 | * STATIC FUNCTIONS 101 | **********************/ 102 | 103 | int quit_filter(void * userdata, SDL_Event * event) 104 | { 105 | (void)userdata; 106 | 107 | if(event->type == SDL_QUIT) { 108 | sdl_quit_qry = true; 109 | } 110 | 111 | return 1; 112 | } 113 | 114 | void mouse_handler(SDL_Event * event) 115 | { 116 | switch(event->type) { 117 | case SDL_MOUSEBUTTONUP: 118 | if(event->button.button == SDL_BUTTON_LEFT) 119 | left_button_down = false; 120 | break; 121 | case SDL_MOUSEBUTTONDOWN: 122 | if(event->button.button == SDL_BUTTON_LEFT) { 123 | left_button_down = true; 124 | last_x = event->motion.x / SDL_ZOOM; 125 | last_y = event->motion.y / SDL_ZOOM; 126 | } 127 | break; 128 | case SDL_MOUSEMOTION: 129 | last_x = event->motion.x / SDL_ZOOM; 130 | last_y = event->motion.y / SDL_ZOOM; 131 | break; 132 | 133 | case SDL_FINGERUP: 134 | left_button_down = false; 135 | last_x = SDL_HOR_RES * event->tfinger.x / SDL_ZOOM; 136 | last_y = SDL_VER_RES * event->tfinger.y / SDL_ZOOM; 137 | break; 138 | case SDL_FINGERDOWN: 139 | left_button_down = true; 140 | last_x = SDL_HOR_RES * event->tfinger.x / SDL_ZOOM; 141 | last_y = SDL_VER_RES * event->tfinger.y / SDL_ZOOM; 142 | break; 143 | case SDL_FINGERMOTION: 144 | last_x = SDL_HOR_RES * event->tfinger.x / SDL_ZOOM; 145 | last_y = SDL_VER_RES * event->tfinger.y / SDL_ZOOM; 146 | break; 147 | } 148 | 149 | } 150 | 151 | 152 | /** 153 | * It is called periodically from the SDL thread to check mouse wheel state 154 | * @param event describes the event 155 | */ 156 | void mousewheel_handler(SDL_Event * event) 157 | { 158 | switch(event->type) { 159 | case SDL_MOUSEWHEEL: 160 | // Scroll down (y = -1) means positive encoder turn, 161 | // so invert it 162 | #ifdef __EMSCRIPTEN__ 163 | /*Escripten scales it wrong*/ 164 | if(event->wheel.y < 0) wheel_diff++; 165 | if(event->wheel.y > 0) wheel_diff--; 166 | #else 167 | wheel_diff = -event->wheel.y; 168 | #endif 169 | break; 170 | case SDL_MOUSEBUTTONDOWN: 171 | if(event->button.button == SDL_BUTTON_MIDDLE) { 172 | wheel_state = LV_INDEV_STATE_PRESSED; 173 | } 174 | break; 175 | case SDL_MOUSEBUTTONUP: 176 | if(event->button.button == SDL_BUTTON_MIDDLE) { 177 | wheel_state = LV_INDEV_STATE_RELEASED; 178 | } 179 | break; 180 | default: 181 | break; 182 | } 183 | } 184 | 185 | 186 | /** 187 | * Called periodically from the SDL thread, store text input or control characters in the buffer. 188 | * @param event describes the event 189 | */ 190 | void keyboard_handler(SDL_Event * event) 191 | { 192 | /* We only care about SDL_KEYDOWN and SDL_TEXTINPUT events */ 193 | switch(event->type) { 194 | case SDL_KEYDOWN: /*Button press*/ 195 | { 196 | const uint32_t ctrl_key = keycode_to_ctrl_key(event->key.keysym.sym); 197 | if (ctrl_key == '\0') 198 | return; 199 | const size_t len = strlen(buf); 200 | if (len < KEYBOARD_BUFFER_SIZE - 1) { 201 | buf[len] = ctrl_key; 202 | buf[len + 1] = '\0'; 203 | } 204 | break; 205 | } 206 | case SDL_TEXTINPUT: /*Text input*/ 207 | { 208 | const size_t len = strlen(buf) + strlen(event->text.text); 209 | if (len < KEYBOARD_BUFFER_SIZE - 1) 210 | strcat(buf, event->text.text); 211 | } 212 | break; 213 | default: 214 | break; 215 | 216 | } 217 | } 218 | 219 | 220 | /** 221 | * Convert a SDL key code to it's LV_KEY_* counterpart or return '\0' if it's not a control character. 222 | * @param sdl_key the key code 223 | * @return LV_KEY_* control character or '\0' 224 | */ 225 | uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key) 226 | { 227 | /*Remap some key to LV_KEY_... to manage groups*/ 228 | 229 | SDL_Keymod mode = SDL_GetModState(); 230 | 231 | switch(sdl_key) { 232 | case SDLK_RIGHT: 233 | case SDLK_KP_PLUS: 234 | return LV_KEY_RIGHT; 235 | 236 | case SDLK_LEFT: 237 | case SDLK_KP_MINUS: 238 | return LV_KEY_LEFT; 239 | 240 | case SDLK_UP: 241 | return LV_KEY_UP; 242 | 243 | case SDLK_DOWN: 244 | return LV_KEY_DOWN; 245 | 246 | case SDLK_ESCAPE: 247 | return LV_KEY_ESC; 248 | 249 | case SDLK_BACKSPACE: 250 | return LV_KEY_BACKSPACE; 251 | 252 | case SDLK_DELETE: 253 | return LV_KEY_DEL; 254 | 255 | case SDLK_KP_ENTER: 256 | case '\r': 257 | return LV_KEY_ENTER; 258 | 259 | case SDLK_TAB: 260 | return (mode & KMOD_SHIFT)? LV_KEY_PREV: LV_KEY_NEXT; 261 | 262 | case SDLK_PAGEDOWN: 263 | return LV_KEY_NEXT; 264 | 265 | case SDLK_PAGEUP: 266 | return LV_KEY_PREV; 267 | 268 | default: 269 | return '\0'; 270 | } 271 | } 272 | 273 | #endif /* USE_SDL || USD_SDL_GPU */ 274 | -------------------------------------------------------------------------------- /sdl/sdl_common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sdl_common.h 3 | * 4 | */ 5 | 6 | #ifndef SDL_COMMON_H 7 | #define SDL_COMMON_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 25 | #include "lvgl.h" 26 | #else 27 | #include "lvgl/lvgl.h" 28 | #endif 29 | 30 | #if USE_SDL || USE_SDL_GPU 31 | 32 | #ifndef SDL_INCLUDE_PATH 33 | #define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH 34 | #endif 35 | 36 | #ifndef SDL_ZOOM 37 | #define SDL_ZOOM MONITOR_ZOOM 38 | #endif 39 | 40 | /********************* 41 | * DEFINES 42 | *********************/ 43 | 44 | /********************** 45 | * TYPEDEFS 46 | **********************/ 47 | 48 | /********************** 49 | * GLOBAL PROTOTYPES 50 | **********************/ 51 | extern volatile bool sdl_quit_qry; 52 | 53 | /** 54 | * Initialize SDL to be used as display, mouse and mouse wheel drivers. 55 | */ 56 | void sdl_init(void); 57 | 58 | /** 59 | * Flush a buffer to the marked area 60 | * @param drv pointer to driver where this function belongs 61 | * @param area an area where to copy `color_p` 62 | * @param color_p an array of pixel to copy to the `area` part of the screen 63 | */ 64 | void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 65 | 66 | /** 67 | * Get the current position and state of the mouse 68 | * @param indev_drv pointer to the related input device driver 69 | * @param data store the mouse data here 70 | */ 71 | void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 72 | 73 | /** 74 | * Get encoder (i.e. mouse wheel) ticks difference and pressed state 75 | * @param indev_drv pointer to the related input device driver 76 | * @param data store the read data here 77 | */ 78 | void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 79 | 80 | /** 81 | * Get input from the keyboard. 82 | * @param indev_drv pointer to the related input device driver 83 | * @param data store the red data here 84 | */ 85 | void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 86 | 87 | #endif /* USE_SDL || USE_SDL_GPU */ 88 | 89 | #ifdef __cplusplus 90 | } /* extern "C" */ 91 | #endif 92 | 93 | #endif /* SDL_COMMON_H */ 94 | -------------------------------------------------------------------------------- /sdl/sdl_common_internal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sdl_common_internal.h 3 | * Provides SDL related functions which are only used internal. 4 | * 5 | */ 6 | 7 | #ifndef SDL_COMMON_INTERNAL_H 8 | #define SDL_COMMON_INTERNAL_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | /********************* 15 | * INCLUDES 16 | *********************/ 17 | #include "sdl_common.h" 18 | 19 | #if USE_SDL || USE_SDL_GPU 20 | 21 | #include SDL_INCLUDE_PATH 22 | 23 | /********************** 24 | * GLOBAL PROTOTYPES 25 | **********************/ 26 | int quit_filter(void * userdata, SDL_Event * event); 27 | 28 | void mouse_handler(SDL_Event * event); 29 | void mousewheel_handler(SDL_Event * event); 30 | uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key); 31 | void keyboard_handler(SDL_Event * event); 32 | 33 | #endif /* USE_SDL || USE_SDL_GPU */ 34 | 35 | #ifdef __cplusplus 36 | } /* extern "C" */ 37 | #endif 38 | 39 | #endif /* SDL_COMMON_INTERNAL_H */ 40 | -------------------------------------------------------------------------------- /sdl/sdl_gpu.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sdl_gpu.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "sdl_gpu.h" 10 | #if USE_SDL_GPU 11 | 12 | #if LV_USE_DRAW_SDL == 0 13 | # error "LV_USE_DRAW_SDL must be enabled" 14 | #endif 15 | 16 | #if USE_KEYBOARD 17 | # warning "KEYBOARD is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c" 18 | #endif 19 | 20 | #if USE_MOUSE 21 | # warning "MOUSE is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c" 22 | #endif 23 | 24 | #if USE_MOUSEWHEEL 25 | # warning "MOUSEWHEEL is deprecated, use SDL instead that. See lv_drivers/sdl/sdl.c" 26 | #endif 27 | 28 | #if USE_MONITOR 29 | # error "Cannot enable both MONITOR and SDL at the same time. " 30 | #endif 31 | 32 | #include "sdl_common_internal.h" 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include SDL_INCLUDE_PATH 38 | 39 | /********************* 40 | * DEFINES 41 | *********************/ 42 | #ifndef KEYBOARD_BUFFER_SIZE 43 | #define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE 44 | #endif 45 | 46 | /********************** 47 | * TYPEDEFS 48 | **********************/ 49 | typedef struct { 50 | lv_draw_sdl_drv_param_t drv_param; 51 | SDL_Window * window; 52 | SDL_Texture * texture; 53 | }monitor_t; 54 | 55 | /********************** 56 | * STATIC PROTOTYPES 57 | **********************/ 58 | static void window_create(monitor_t * m); 59 | static void window_update(lv_disp_drv_t *disp_drv, void * buf); 60 | static void monitor_sdl_clean_up(void); 61 | static void sdl_event_handler(lv_timer_t * t); 62 | 63 | /*********************** 64 | * GLOBAL PROTOTYPES 65 | ***********************/ 66 | 67 | static volatile bool sdl_inited = false; 68 | 69 | 70 | /********************** 71 | * MACROS 72 | **********************/ 73 | 74 | /********************** 75 | * GLOBAL FUNCTIONS 76 | **********************/ 77 | 78 | void sdl_init(void) 79 | { 80 | /*Initialize the SDL*/ 81 | SDL_Init(SDL_INIT_VIDEO); 82 | 83 | SDL_SetEventFilter(quit_filter, NULL); 84 | 85 | sdl_inited = true; 86 | 87 | SDL_StartTextInput(); 88 | 89 | lv_timer_create(sdl_event_handler, 1, NULL); 90 | } 91 | 92 | void sdl_disp_drv_init(lv_disp_drv_t * disp_drv, lv_coord_t hor_res, lv_coord_t ver_res) 93 | { 94 | monitor_t *m = lv_malloc(sizeof(monitor_t)); 95 | window_create(m); 96 | lv_disp_drv_init(disp_drv); 97 | disp_drv->direct_mode = 1; 98 | disp_drv->flush_cb = monitor_flush; 99 | disp_drv->hor_res = hor_res; 100 | disp_drv->ver_res = ver_res; 101 | lv_disp_draw_buf_t *disp_buf = lv_malloc(sizeof(lv_disp_draw_buf_t)); 102 | lv_disp_draw_buf_init(disp_buf, m->texture, NULL, hor_res * ver_res); 103 | disp_drv->draw_buf = disp_buf; 104 | disp_drv->antialiasing = 1; 105 | disp_drv->user_data = &m->drv_param; 106 | } 107 | 108 | /** 109 | * Flush a buffer to the marked area 110 | * @param disp_drv pointer to driver where this function belongs 111 | * @param area an area where to copy `color_p` 112 | * @param color_p an array of pixels to copy to the `area` part of the screen 113 | */ 114 | void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) 115 | { 116 | lv_coord_t hres = disp_drv->hor_res; 117 | lv_coord_t vres = disp_drv->ver_res; 118 | 119 | // printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2); 120 | 121 | /*Return if the area is out the screen*/ 122 | if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) { 123 | lv_disp_flush_ready(disp_drv); 124 | return; 125 | } 126 | 127 | /* TYPICALLY YOU DO NOT NEED THIS 128 | * If it was the last part to refresh update the texture of the window.*/ 129 | if(lv_disp_flush_is_last(disp_drv)) { 130 | window_update(disp_drv, color_p); 131 | } 132 | 133 | /*IMPORTANT! It must be called to tell the system the flush is ready*/ 134 | lv_disp_flush_ready(disp_drv); 135 | 136 | } 137 | 138 | void sdl_display_resize(lv_disp_t *disp, int width, int height) 139 | { 140 | lv_disp_drv_t *driver = disp->driver; 141 | SDL_Renderer *renderer = ((lv_draw_sdl_drv_param_t *) driver->user_data)->renderer; 142 | if (driver->draw_buf->buf1) { 143 | SDL_DestroyTexture(driver->draw_buf->buf1); 144 | } 145 | SDL_Texture *texture = lv_draw_sdl_create_screen_texture(renderer, width, height); 146 | lv_disp_draw_buf_init(driver->draw_buf, texture, NULL, width * height); 147 | driver->hor_res = (lv_coord_t) width; 148 | driver->ver_res = (lv_coord_t) height; 149 | SDL_RendererInfo renderer_info; 150 | SDL_GetRendererInfo(renderer, &renderer_info); 151 | SDL_assert(renderer_info.flags & SDL_RENDERER_TARGETTEXTURE); 152 | SDL_SetRenderTarget(renderer, texture); 153 | lv_disp_drv_update(disp, driver); 154 | } 155 | 156 | 157 | /********************** 158 | * STATIC FUNCTIONS 159 | **********************/ 160 | 161 | 162 | /** 163 | * SDL main thread. All SDL related task have to be handled here! 164 | * It initializes SDL, handles drawing and the mouse. 165 | */ 166 | 167 | static void sdl_event_handler(lv_timer_t * t) 168 | { 169 | (void)t; 170 | 171 | /*Refresh handling*/ 172 | SDL_Event event; 173 | while(SDL_PollEvent(&event)) { 174 | mouse_handler(&event); 175 | mousewheel_handler(&event); 176 | keyboard_handler(&event); 177 | 178 | switch (event.type) { 179 | case SDL_WINDOWEVENT: { 180 | SDL_Window * window = SDL_GetWindowFromID(event.window.windowID); 181 | switch (event.window.event) { 182 | #if SDL_VERSION_ATLEAST(2, 0, 5) 183 | case SDL_WINDOWEVENT_TAKE_FOCUS: 184 | #endif 185 | case SDL_WINDOWEVENT_EXPOSED: 186 | for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; cur = lv_disp_get_next(cur)) { 187 | window_update(cur->driver, cur->driver->draw_buf->buf_act); 188 | } 189 | break; 190 | case SDL_WINDOWEVENT_SIZE_CHANGED: { 191 | for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; cur = lv_disp_get_next(cur)) { 192 | lv_draw_sdl_drv_param_t *param = cur->driver->user_data; 193 | SDL_Renderer *renderer = SDL_GetRenderer(window); 194 | if (param->renderer != renderer) continue; 195 | int w, h; 196 | SDL_GetWindowSize(window, &w, &h); 197 | sdl_display_resize(cur, w, h); 198 | } 199 | break; 200 | } 201 | case SDL_WINDOWEVENT_CLOSE: { 202 | for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; ) { 203 | lv_disp_t * tmp = cur; 204 | cur = lv_disp_get_next(tmp); 205 | monitor_t * m = tmp->driver->user_data; 206 | SDL_Renderer *renderer = SDL_GetRenderer(window); 207 | if (m->drv_param.renderer != renderer) continue; 208 | SDL_DestroyTexture(tmp->driver->draw_buf->buf1); 209 | SDL_DestroyRenderer(m->drv_param.renderer); 210 | lv_disp_remove(tmp); 211 | } 212 | 213 | break; 214 | } 215 | default: 216 | break; 217 | } 218 | break; 219 | } 220 | } 221 | } 222 | 223 | /*Run until quit event not arrives*/ 224 | if(sdl_quit_qry) { 225 | monitor_sdl_clean_up(); 226 | exit(0); 227 | } 228 | } 229 | 230 | static void monitor_sdl_clean_up(void) 231 | { 232 | for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; ) { 233 | lv_disp_t * tmp = cur; 234 | monitor_t * m = tmp->driver->user_data; 235 | SDL_DestroyTexture(tmp->driver->draw_buf->buf1); 236 | SDL_DestroyRenderer(m->drv_param.renderer); 237 | cur = lv_disp_get_next(cur); 238 | lv_disp_remove(tmp); 239 | } 240 | 241 | SDL_Quit(); 242 | } 243 | 244 | static void window_create(monitor_t * m) 245 | { 246 | // SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1"); 247 | m->window = SDL_CreateWindow("TFT Simulator", 248 | SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 249 | SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM, SDL_WINDOW_RESIZABLE); 250 | 251 | m->drv_param.renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_ACCELERATED); 252 | 253 | m->texture = lv_draw_sdl_create_screen_texture(m->drv_param.renderer, SDL_HOR_RES, SDL_VER_RES); 254 | /* For first frame */ 255 | SDL_SetRenderTarget(m->drv_param.renderer, m->texture); 256 | } 257 | 258 | static void window_update(lv_disp_drv_t *disp_drv, void * buf) 259 | { 260 | SDL_Renderer *renderer = ((lv_draw_sdl_drv_param_t *) disp_drv->user_data)->renderer; 261 | SDL_Texture *texture = buf; 262 | SDL_SetRenderTarget(renderer, NULL); 263 | SDL_RenderClear(renderer); 264 | #if LV_COLOR_SCREEN_TRANSP 265 | SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff); 266 | SDL_Rect r; 267 | r.x = 0; r.y = 0; r.w = SDL_HOR_RES; r.h = SDL_VER_RES; 268 | SDL_RenderDrawRect(renderer, &r); 269 | #endif 270 | 271 | /*Update the renderer with the texture containing the rendered image*/ 272 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 273 | SDL_RenderSetClipRect(renderer, NULL); 274 | SDL_RenderCopy(renderer, texture, NULL, NULL); 275 | SDL_RenderPresent(renderer); 276 | SDL_SetRenderTarget(renderer, texture); 277 | } 278 | 279 | #endif /*USE_SDL_GPU*/ 280 | -------------------------------------------------------------------------------- /sdl/sdl_gpu.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sdl_gpu.h 3 | * 4 | */ 5 | 6 | #ifndef SDL_GPU_H 7 | #define SDL_GPU_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_SDL_GPU 25 | 26 | #include "sdl_common.h" 27 | 28 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 29 | #include "lvgl.h" 30 | #else 31 | #include "lvgl/lvgl.h" 32 | #endif 33 | 34 | /********************* 35 | * DEFINES 36 | *********************/ 37 | 38 | /********************** 39 | * TYPEDEFS 40 | **********************/ 41 | 42 | /********************** 43 | * GLOBAL PROTOTYPES 44 | **********************/ 45 | 46 | /** 47 | * Initialize SDL to be used as display, mouse and mouse wheel drivers. 48 | */ 49 | void sdl_init(void); 50 | 51 | void sdl_disp_drv_init(lv_disp_drv_t * disp_drv, lv_coord_t hor_res, lv_coord_t ver_res); 52 | 53 | /** 54 | * Flush a buffer to the marked area 55 | * @param disp_drv pointer to driver where this function belongs 56 | * @param area an area where to copy `color_p` 57 | * @param color_p an array of pixels to copy to the `area` part of the screen 58 | */ 59 | void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); 60 | 61 | /** 62 | * Get the current position and state of the mouse 63 | * @param indev_drv pointer to the related input device driver 64 | * @param data store the mouse data here 65 | */ 66 | void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 67 | 68 | /** 69 | * Get encoder (i.e. mouse wheel) ticks difference and pressed state 70 | * @param indev_drv pointer to the related input device driver 71 | * @param data store the read data here 72 | */ 73 | void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 74 | 75 | /** 76 | * Get input from the keyboard. 77 | * @param indev_drv pointer to the related input device driver 78 | * @param data store the red data here 79 | */ 80 | void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); 81 | 82 | /*For backward compatibility. Will be removed.*/ 83 | #define monitor_init sdl_init 84 | #define monitor_flush sdl_display_flush 85 | 86 | /********************** 87 | * MACROS 88 | **********************/ 89 | 90 | #endif /* USE_SDL_GPU */ 91 | 92 | #ifdef __cplusplus 93 | } /* extern "C" */ 94 | #endif 95 | 96 | #endif /* SDL_GPU_H */ 97 | -------------------------------------------------------------------------------- /wayland/.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles/ 3 | Makefile 4 | cmake_install.cmake 5 | /protocols 6 | -------------------------------------------------------------------------------- /wayland/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12) 2 | project(lv_wayland) 3 | 4 | find_package(PkgConfig) 5 | pkg_check_modules(wayland-client REQUIRED wayland-client) 6 | pkg_check_modules(wayland-cursor REQUIRED wayland-cursor) 7 | pkg_check_modules(xkbcommon REQUIRED xkbcommon) 8 | 9 | # Wayland protocols 10 | find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner) 11 | pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.25) 12 | pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir) 13 | 14 | macro(wayland_generate protocol_xml_file output_dir target) 15 | get_filename_component(output_file_base ${protocol_xml_file} NAME_WE) 16 | set(output_file_noext "${output_dir}/wayland-${output_file_base}-client-protocol") 17 | add_custom_command(OUTPUT "${output_file_noext}.h" 18 | COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_xml_file}" "${output_file_noext}.h" 19 | DEPENDS "${protocol_xml_file}" 20 | VERBATIM) 21 | 22 | add_custom_command(OUTPUT "${output_file_noext}.c" 23 | COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_xml_file}" "${output_file_noext}.c" 24 | DEPENDS "${protocol_xml_file}" 25 | VERBATIM) 26 | 27 | if(NOT EXISTS ${protocol_xml_file}) 28 | message("Protocol XML file not found: " ${protocol_xml_file}) 29 | else() 30 | set_property(TARGET ${target} APPEND PROPERTY SOURCES "${output_file_noext}.h" "${output_file_noext}.c") 31 | endif() 32 | endmacro() 33 | 34 | set(WAYLAND_PROTOCOLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/protocols") 35 | file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR}) 36 | 37 | add_custom_target(generate_protocols ALL) 38 | 39 | wayland_generate("${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml" ${WAYLAND_PROTOCOLS_DIR} generate_protocols) 40 | -------------------------------------------------------------------------------- /wayland/README.md: -------------------------------------------------------------------------------- 1 | # Wayland display and input driver 2 | 3 | Wayland display and input driver, with support for keyboard, pointer (i.e. mouse) and touchscreen. 4 | Keyboard support is based on libxkbcommon. 5 | 6 | Following shell are supported: 7 | 8 | * wl_shell (deprecated) 9 | * xdg_shell 10 | 11 | > xdg_shell requires an extra build step; see section _Generate protocols_ below. 12 | 13 | 14 | Basic client-side window decorations (simple title bar, minimize and close buttons) 15 | are supported, while integration with desktop environments is not. 16 | 17 | 18 | ## Install headers and libraries 19 | 20 | ### Ubuntu 21 | 22 | ``` 23 | sudo apt-get install libwayland-dev libxkbcommon-dev libwayland-bin wayland-protocols 24 | ``` 25 | 26 | ### Fedora 27 | 28 | ``` 29 | sudo dnf install wayland-devel libxkbcommon-devel wayland-utils wayland-protocols-devel 30 | ``` 31 | 32 | 33 | ## Generate protocols 34 | 35 | Support for non-basic shells (i.e. other than _wl_shell_) requires additional 36 | source files to be generated before the first build of the project. To do so, 37 | navigate to the _wayland_ folder (the one which includes this file) and issue 38 | the following commands: 39 | 40 | ``` 41 | cmake . 42 | make 43 | ``` 44 | 45 | 46 | ## Build configuration under Eclipse 47 | 48 | In "Project properties > C/C++ Build > Settings" set the followings: 49 | 50 | - "Cross GCC Compiler > Command line pattern" 51 | - Add ` ${wayland-cflags}` and ` ${xkbcommon-cflags}` to the end (add a space between the last command and this) 52 | 53 | 54 | - "Cross GCC Linker > Command line pattern" 55 | - Add ` ${wayland-libs}` and ` ${xkbcommon-libs}` to the end (add a space between the last command and this) 56 | 57 | 58 | - In "C/C++ Build > Build variables" 59 | - Configuration: [All Configuration] 60 | 61 | - Add 62 | - Variable name: `wayland-cflags` 63 | - Type: `String` 64 | - Value: `pkg-config --cflags wayland-client` 65 | - Variable name: `wayland-libs` 66 | - Type: `String` 67 | - Value: `pkg-config --libs wayland-client` 68 | - Variable name: `xkbcommon-cflags` 69 | - Type: `String` 70 | - Value: `pkg-config --cflags xkbcommon` 71 | - Variable name: `xkbcommon-libs` 72 | - Type: `String` 73 | - Value: `pkg-config --libs xkbcommon` 74 | 75 | 76 | ## Init Wayland in LVGL 77 | 78 | 1. In `main.c` `#incude "lv_drivers/wayland/wayland.h"` 79 | 2. Enable the Wayland driver in `lv_drv_conf.h` with `USE_WAYLAND 1` and 80 | configure its features below, enabling at least support for one shell. 81 | 3. `LV_COLOR_DEPTH` should be set either to `32` or `16` in `lv_conf.h`; 82 | support for `8` and `1` depends on target platform. 83 | 4. After `lv_init()` call `lv_wayland_init()`. 84 | 5. Add a display (or more than one) using `lv_wayland_create_window()`, 85 | possibly with a close callback to track the status of each display: 86 | ```c 87 | #define H_RES (800) 88 | #define V_RES (480) 89 | 90 | /* Create a display */ 91 | lv_disp_t * disp = lv_wayland_create_window(H_RES, V_RES, "Window Title", close_cb); 92 | ``` 93 | As part of the above call, the Wayland driver will register four input devices 94 | for each display: 95 | - a KEYPAD connected to Wayland keyboard events 96 | - a POINTER connected to Wayland touch events 97 | - a POINTER connected to Wayland pointer events 98 | - a ENCODER connected to Wayland pointer axis events 99 | Handles for input devices of each display can be get using respectively 100 | `lv_wayland_get_indev_keyboard()`, `lv_wayland_get_indev_touchscreen()`, 101 | `lv_wayland_get_indev_pointer()` and `lv_wayland_get_indev_pointeraxis()`, using 102 | `disp` as argument. 103 | 5. After `lv_deinit()` (if used), or in any case during de-initialization, call 104 | `lv_wayland_deinit()`. 105 | 106 | ### Fullscreen mode 107 | 108 | In order to set one window as fullscreen or restore it as a normal one, 109 | call the `lv_wayland_window_set_fullscreen()` function respectively with `true` 110 | or `false` as `fullscreen` argument. 111 | 112 | ### Disable window client-side decoration at runtime 113 | 114 | Even when client-side decorations are enabled at compile time, they can be 115 | disabled at runtime setting the `LV_WAYLAND_DISABLE_WINDOWDECORATION` 116 | environment variable to `1`. 117 | 118 | ### Event-driven timer handler 119 | 120 | Set `LV_WAYLAND_TIMER_HANDLER` in `lv_drv_conf.h` and call `lv_wayland_timer_handler()` 121 | in your timer loop (in place of `lv_timer_handler()`). 122 | 123 | You can now sleep/wait until the next timer/event is ready, e.g.: 124 | ``` 125 | /* [After initialization and display creation] */ 126 | #include 127 | #include 128 | #include 129 | 130 | struct pollfd pfd; 131 | uint32_t time_till_next; 132 | int sleep; 133 | 134 | pfd.fd = lv_wayland_get_fd(); 135 | pfd.events = POLLIN; 136 | 137 | while (1) { 138 | /* Handle any Wayland/LVGL timers/events */ 139 | time_till_next = lv_wayland_timer_handler(); 140 | 141 | /* Run until the last window closes */ 142 | if (!lv_wayland_window_is_open(NULL)) { 143 | break; 144 | } 145 | 146 | /* Wait for something interesting to happen */ 147 | if (time_till_next == LV_NO_TIMER_READY) { 148 | sleep = -1; 149 | } else if (time_till_next > INT_MAX) { 150 | sleep = INT_MAX; 151 | } else { 152 | sleep = time_till_next; 153 | } 154 | 155 | while ((poll(&pfd, 1, sleep) < 0) && (errno == EINTR)); 156 | } 157 | ``` 158 | -------------------------------------------------------------------------------- /wayland/smm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file smm.h 3 | * 4 | */ 5 | #ifndef SMM_H 6 | #define SMM_H 7 | #include 8 | #include 9 | 10 | #define SMM_FD_NAME "lvgl-wayland" 11 | #define SMM_POOL_TAGS (1) 12 | #define SMM_BUFFER_TAGS (2) 13 | #define SMM_GROUP_TAGS (1) 14 | 15 | #define SMM_POOL_PROPERTIES(p) ((const struct smm_pool_properties *)(p)) 16 | #define SMM_BUFFER_PROPERTIES(b) ((const struct smm_buffer_properties *)(b)) 17 | #define SMM_GROUP_PROPERTIES(g) ((const struct smm_group_properties *)(g)) 18 | #define SMM_TAG(o, n, v) \ 19 | do { \ 20 | void **smm_tag = (void **)((char *)o + (n * sizeof(void *))); \ 21 | *smm_tag = (v); \ 22 | } while(0) 23 | 24 | typedef void smm_pool_t; 25 | typedef void smm_buffer_t; 26 | typedef void smm_group_t; 27 | 28 | struct smm_events { 29 | void *ctx; 30 | bool (*new_pool)(void *ctx, smm_pool_t *pool); 31 | void (*expand_pool)(void *ctx, smm_pool_t *pool); 32 | void (*free_pool)(void *ctx, smm_pool_t *pool); 33 | bool (*new_buffer)(void *ctx, smm_buffer_t *buf); 34 | bool (*init_buffer)(void *ctx, smm_buffer_t *buf); 35 | void (*free_buffer)(void *ctx, smm_buffer_t *buf); 36 | }; 37 | 38 | struct smm_pool_properties { 39 | void *tag[SMM_POOL_TAGS]; 40 | size_t size; 41 | int fd; 42 | }; 43 | 44 | struct smm_buffer_properties { 45 | void *tag[SMM_BUFFER_TAGS]; 46 | smm_group_t *const group; 47 | smm_pool_t *const pool; 48 | size_t offset; 49 | }; 50 | 51 | struct smm_group_properties { 52 | void *tag[SMM_GROUP_TAGS]; 53 | }; 54 | 55 | void smm_init(struct smm_events *evs); 56 | void smm_setctx(void *ctx); 57 | void smm_deinit(void); 58 | smm_group_t *smm_create(void); 59 | void smm_resize(smm_group_t *grp, size_t sz); 60 | void smm_destroy(smm_group_t *grp); 61 | smm_buffer_t *smm_acquire(smm_group_t *grp); 62 | void *smm_map(smm_buffer_t *buf); 63 | void smm_release(smm_buffer_t *buf); 64 | smm_buffer_t *smm_latest(smm_group_t *grp); 65 | smm_buffer_t *smm_next(smm_buffer_t *buf); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /wayland/wayland.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file wayland 3 | * 4 | */ 5 | 6 | #ifndef WAYLAND_H 7 | #define WAYLAND_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_WAYLAND 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | #if LV_USE_USER_DATA == 0 33 | #error "Support for user data is required by wayland driver. Set LV_USE_USER_DATA to 1 in lv_conf.h" 34 | #endif 35 | 36 | 37 | /********************* 38 | * DEFINES 39 | *********************/ 40 | 41 | /********************** 42 | * TYPEDEFS 43 | **********************/ 44 | 45 | typedef bool (*lv_wayland_display_close_f_t)(lv_disp_t * disp); 46 | 47 | /********************** 48 | * GLOBAL PROTOTYPES 49 | **********************/ 50 | void lv_wayland_init(void); 51 | void lv_wayland_deinit(void); 52 | int lv_wayland_get_fd(void); 53 | lv_disp_t * lv_wayland_create_window(lv_coord_t hor_res, lv_coord_t ver_res, char *title, 54 | lv_wayland_display_close_f_t close_cb); 55 | void lv_wayland_close_window(lv_disp_t * disp); 56 | bool lv_wayland_window_is_open(lv_disp_t * disp); 57 | void lv_wayland_window_set_fullscreen(lv_disp_t * disp, bool fullscreen); 58 | lv_indev_t * lv_wayland_get_pointer(lv_disp_t * disp); 59 | lv_indev_t * lv_wayland_get_pointeraxis(lv_disp_t * disp); 60 | lv_indev_t * lv_wayland_get_keyboard(lv_disp_t * disp); 61 | lv_indev_t * lv_wayland_get_touchscreen(lv_disp_t * disp); 62 | #ifdef LV_WAYLAND_TIMER_HANDLER 63 | uint32_t lv_wayland_timer_handler(void); 64 | #endif 65 | 66 | /********************** 67 | * MACROS 68 | **********************/ 69 | 70 | #endif /* USE_WAYLAND */ 71 | 72 | #ifdef __cplusplus 73 | } /* extern "C" */ 74 | #endif 75 | 76 | #endif /* WAYLAND_H */ 77 | -------------------------------------------------------------------------------- /win32drv/win32drv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file win32drv.h 3 | * 4 | */ 5 | 6 | #ifndef LV_WIN32DRV_H 7 | #define LV_WIN32DRV_H 8 | 9 | /********************* 10 | * INCLUDES 11 | *********************/ 12 | 13 | #ifndef LV_DRV_NO_CONF 14 | #ifdef LV_CONF_INCLUDE_SIMPLE 15 | #include "lv_drv_conf.h" 16 | #else 17 | #include "../../lv_drv_conf.h" 18 | #endif 19 | #endif 20 | 21 | #if USE_WIN32DRV 22 | 23 | #if LV_USE_USER_DATA == 0 24 | #error "Support for user data is required by new Win32 driver. Set LV_USE_USER_DATA to 1 in lv_conf.h" 25 | #endif 26 | 27 | #include 28 | 29 | #if _MSC_VER >= 1200 30 | // Disable compilation warnings. 31 | #pragma warning(push) 32 | // nonstandard extension used : bit field types other than int 33 | #pragma warning(disable:4214) 34 | // 'conversion' conversion from 'type1' to 'type2', possible loss of data 35 | #pragma warning(disable:4244) 36 | #endif 37 | 38 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 39 | #include "lvgl.h" 40 | #else 41 | #include "lvgl/lvgl.h" 42 | #endif 43 | 44 | #if _MSC_VER >= 1200 45 | // Restore compilation warnings. 46 | #pragma warning(pop) 47 | #endif 48 | 49 | /********************* 50 | * DEFINES 51 | *********************/ 52 | 53 | #define LVGL_SIMULATOR_WINDOW_CLASS L"LVGL.SimulatorWindow" 54 | 55 | /********************** 56 | * TYPEDEFS 57 | **********************/ 58 | 59 | typedef struct _lv_win32_keyboard_queue_item_t 60 | { 61 | SLIST_ENTRY ItemEntry; 62 | uint32_t key; 63 | lv_indev_state_t state; 64 | } lv_win32_keyboard_queue_item_t; 65 | 66 | typedef struct _lv_win32_window_context_t 67 | { 68 | lv_disp_t* display_device_object; 69 | lv_indev_t* mouse_device_object; 70 | lv_indev_t* mousewheel_device_object; 71 | lv_indev_t* keyboard_device_object; 72 | 73 | lv_coord_t display_hor_res; 74 | lv_coord_t display_ver_res; 75 | uint32_t display_dpi; 76 | HDC display_framebuffer_context_handle; 77 | uint32_t* display_framebuffer_base; 78 | size_t display_framebuffer_size; 79 | lv_disp_draw_buf_t display_buffer; 80 | lv_disp_drv_t display_driver; 81 | 82 | lv_indev_state_t mouse_state; 83 | lv_point_t mouse_point; 84 | lv_indev_drv_t mouse_driver; 85 | 86 | lv_indev_state_t mousewheel_state; 87 | int16_t mousewheel_enc_diff; 88 | lv_indev_drv_t mousewheel_driver; 89 | 90 | CRITICAL_SECTION keyboard_mutex; 91 | PSLIST_HEADER keyboard_queue; 92 | uint16_t keyboard_utf16_high_surrogate; 93 | uint16_t keyboard_utf16_low_surrogate; 94 | lv_indev_drv_t keyboard_driver; 95 | } lv_win32_window_context_t; 96 | 97 | /********************** 98 | * GLOBAL PROTOTYPES 99 | **********************/ 100 | 101 | EXTERN_C bool lv_win32_quit_signal; 102 | 103 | EXTERN_C lv_indev_t* lv_win32_pointer_device_object; 104 | EXTERN_C lv_indev_t* lv_win32_keypad_device_object; 105 | EXTERN_C lv_indev_t* lv_win32_encoder_device_object; 106 | 107 | EXTERN_C void lv_win32_add_all_input_devices_to_group( 108 | lv_group_t* group); 109 | 110 | EXTERN_C lv_win32_window_context_t* lv_win32_get_window_context( 111 | HWND window_handle); 112 | 113 | EXTERN_C bool lv_win32_init_window_class(); 114 | 115 | EXTERN_C HWND lv_win32_create_display_window( 116 | const wchar_t* window_title, 117 | lv_coord_t hor_res, 118 | lv_coord_t ver_res, 119 | HINSTANCE instance_handle, 120 | HICON icon_handle, 121 | int show_window_mode); 122 | 123 | EXTERN_C bool lv_win32_init( 124 | HINSTANCE instance_handle, 125 | int show_window_mode, 126 | lv_coord_t hor_res, 127 | lv_coord_t ver_res, 128 | HICON icon_handle); 129 | 130 | /********************** 131 | * MACROS 132 | **********************/ 133 | 134 | #endif /*USE_WIN32DRV*/ 135 | 136 | #endif /*LV_WIN32DRV_H*/ 137 | -------------------------------------------------------------------------------- /win_drv.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file win_drv.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "win_drv.h" 10 | #if USE_WINDOWS 11 | 12 | #include 13 | #include 14 | #include "lvgl/lvgl.h" 15 | 16 | #if LV_COLOR_DEPTH < 16 17 | #error Windows driver only supports true RGB colors at this time 18 | #endif 19 | 20 | /********************** 21 | * DEFINES 22 | **********************/ 23 | 24 | #define WINDOW_STYLE (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME)) 25 | 26 | /********************** 27 | * TYPEDEFS 28 | **********************/ 29 | 30 | /********************** 31 | * STATIC PROTOTYPES 32 | **********************/ 33 | static void do_register(void); 34 | static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p); 35 | static void win_drv_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); 36 | static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); 37 | static void win_drv_read(lv_indev_t *drv, lv_indev_data_t * data); 38 | static void msg_handler(void *param); 39 | 40 | static COLORREF lv_color_to_colorref(const lv_color_t color); 41 | 42 | static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 43 | 44 | 45 | /********************** 46 | * GLOBAL VARIABLES 47 | **********************/ 48 | 49 | bool lv_win_exit_flag = false; 50 | lv_disp_t *lv_windows_disp; 51 | 52 | /********************** 53 | * STATIC VARIABLES 54 | **********************/ 55 | static HWND hwnd; 56 | static uint32_t *fbp = NULL; /* Raw framebuffer memory */ 57 | static bool mouse_pressed; 58 | static int mouse_x, mouse_y; 59 | 60 | 61 | /********************** 62 | * MACROS 63 | **********************/ 64 | 65 | /********************** 66 | * GLOBAL FUNCTIONS 67 | **********************/ 68 | const char g_szClassName[] = "LVGL"; 69 | 70 | HWND windrv_init(void) 71 | { 72 | WNDCLASSEX wc; 73 | RECT winrect; 74 | HICON lvgl_icon; 75 | 76 | //Step 1: Registering the Window Class 77 | wc.cbSize = sizeof(WNDCLASSEX); 78 | wc.style = 0; 79 | wc.lpfnWndProc = WndProc; 80 | wc.cbClsExtra = 0; 81 | wc.cbWndExtra = 0; 82 | wc.hInstance = GetModuleHandle(NULL); 83 | lvgl_icon = (HICON) LoadImage( NULL, "lvgl_icon.bmp", IMAGE_ICON, 0, 0, LR_LOADFROMFILE); 84 | 85 | if(lvgl_icon == NULL) 86 | lvgl_icon = LoadIcon(NULL, IDI_APPLICATION); 87 | 88 | wc.hIcon = lvgl_icon; 89 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 90 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 91 | wc.lpszMenuName = NULL; 92 | wc.lpszClassName = g_szClassName; 93 | wc.hIconSm = lvgl_icon; 94 | 95 | if(!RegisterClassEx(&wc)) 96 | { 97 | return NULL; 98 | } 99 | 100 | winrect.left = 0; 101 | winrect.right = WINDOW_HOR_RES - 1; 102 | winrect.top = 0; 103 | winrect.bottom = WINDOW_VER_RES - 1; 104 | AdjustWindowRectEx(&winrect, WINDOW_STYLE, FALSE, WS_EX_CLIENTEDGE); 105 | OffsetRect(&winrect, -winrect.left, -winrect.top); 106 | // Step 2: Creating the Window 107 | hwnd = CreateWindowEx( 108 | WS_EX_CLIENTEDGE, 109 | g_szClassName, 110 | "LVGL Simulator", 111 | WINDOW_STYLE, 112 | CW_USEDEFAULT, CW_USEDEFAULT, winrect.right, winrect.bottom, 113 | NULL, NULL, GetModuleHandle(NULL), NULL); 114 | 115 | if(hwnd == NULL) 116 | { 117 | return NULL; 118 | } 119 | 120 | ShowWindow(hwnd, SW_SHOWDEFAULT); 121 | UpdateWindow(hwnd); 122 | 123 | 124 | lv_task_create(msg_handler, 0, LV_TASK_PRIO_HIGHEST, NULL); 125 | lv_win_exit_flag = false; 126 | do_register(); 127 | } 128 | 129 | /********************** 130 | * STATIC FUNCTIONS 131 | **********************/ 132 | 133 | static void do_register(void) 134 | { 135 | static lv_disp_draw_buf_t disp_buf_1; 136 | static lv_color_t buf1_1[WINDOW_HOR_RES * 100]; /*A buffer for 10 rows*/ 137 | lv_disp_draw_buf_init(&disp_draw_buf_1, buf1_1, NULL, WINDOW_HOR_RES * 100); /*Initialize the display buffer*/ 138 | 139 | 140 | /*----------------------------------- 141 | * Register the display in LVGLGL 142 | *----------------------------------*/ 143 | 144 | static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ 145 | lv_disp_drv_init(&disp_drv); /*Basic initialization*/ 146 | 147 | /*Set up the functions to access to your display*/ 148 | 149 | /*Set the resolution of the display*/ 150 | disp_drv.hor_res = WINDOW_HOR_RES; 151 | disp_drv.ver_res = WINDOW_VER_RES; 152 | 153 | /*Used to copy the buffer's content to the display*/ 154 | disp_drv.flush_cb = win_drv_flush; 155 | 156 | /*Set a display buffer*/ 157 | disp_drv.draw_buf = &disp_buf_1; 158 | 159 | /*Finally register the driver*/ 160 | lv_windows_disp = lv_disp_drv_register(&disp_drv); 161 | static lv_indev_drv_t indev_drv; 162 | lv_indev_drv_init(&indev_drv); 163 | indev_drv.type = LV_INDEV_TYPE_POINTER; 164 | indev_drv.read_cb = win_drv_read; 165 | lv_indev_drv_register(&indev_drv); 166 | } 167 | 168 | static void msg_handler(void *param) 169 | { 170 | (void)param; 171 | 172 | MSG msg; 173 | BOOL bRet; 174 | if( (bRet = PeekMessage( &msg, NULL, 0, 0, TRUE )) != 0) 175 | { 176 | if (bRet == -1) 177 | { 178 | return; 179 | } 180 | else 181 | { 182 | TranslateMessage(&msg); 183 | DispatchMessage(&msg); 184 | } 185 | if(msg.message == WM_QUIT) 186 | lv_win_exit_flag = true; 187 | } 188 | } 189 | 190 | static void win_drv_read(lv_indev_t *drv, lv_indev_data_t * data) 191 | { 192 | data->state = mouse_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; 193 | data->point.x = mouse_x; 194 | data->point.y = mouse_y; 195 | } 196 | 197 | static void on_paint(void) 198 | { 199 | HBITMAP bmp = CreateBitmap(WINDOW_HOR_RES, WINDOW_VER_RES, 1, 32, fbp); 200 | PAINTSTRUCT ps; 201 | 202 | HDC hdc = BeginPaint(hwnd, &ps); 203 | 204 | HDC hdcMem = CreateCompatibleDC(hdc); 205 | HBITMAP hbmOld = SelectObject(hdcMem, bmp); 206 | 207 | BitBlt(hdc, 0, 0, WINDOW_HOR_RES, WINDOW_VER_RES, hdcMem, 0, 0, SRCCOPY); 208 | 209 | SelectObject(hdcMem, hbmOld); 210 | DeleteDC(hdcMem); 211 | 212 | EndPaint(hwnd, &ps); 213 | DeleteObject(bmp); 214 | 215 | } 216 | /** 217 | * Flush a buffer to the marked area 218 | * @param x1 left coordinate 219 | * @param y1 top coordinate 220 | * @param x2 right coordinate 221 | * @param y2 bottom coordinate 222 | * @param color_p an array of colors 223 | */ 224 | static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p) 225 | { 226 | win_drv_map(area->x1, area->y1, area->x2, area->y2, color_p); 227 | lv_disp_flush_ready(drv); 228 | } 229 | 230 | /** 231 | * Put a color map to the marked area 232 | * @param x1 left coordinate 233 | * @param y1 top coordinate 234 | * @param x2 right coordinate 235 | * @param y2 bottom coordinate 236 | * @param color_p an array of colors 237 | */ 238 | static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) 239 | { 240 | for(int y = y1; y <= y2; y++) 241 | { 242 | for(int x = x1; x <= x2; x++) 243 | { 244 | fbp[y*WINDOW_HOR_RES+x] = lv_color_to32(*color_p); 245 | color_p++; 246 | } 247 | } 248 | InvalidateRect(hwnd, NULL, FALSE); 249 | UpdateWindow(hwnd); 250 | } 251 | 252 | static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 253 | { 254 | HDC hdc; 255 | PAINTSTRUCT ps; 256 | switch(msg) { 257 | case WM_CREATE: 258 | fbp = malloc(4*WINDOW_HOR_RES*WINDOW_VER_RES); 259 | if(fbp == NULL) 260 | return 1; 261 | SetTimer(hwnd, 0, 10, (TIMERPROC)lv_task_handler); 262 | SetTimer(hwnd, 1, 25, NULL); 263 | 264 | return 0; 265 | case WM_MOUSEMOVE: 266 | case WM_LBUTTONDOWN: 267 | case WM_LBUTTONUP: 268 | mouse_x = GET_X_LPARAM(lParam); 269 | mouse_y = GET_Y_LPARAM(lParam); 270 | if(msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { 271 | mouse_pressed = (msg == WM_LBUTTONDOWN); 272 | } 273 | return 0; 274 | case WM_CLOSE: 275 | free(fbp); 276 | fbp = NULL; 277 | DestroyWindow(hwnd); 278 | return 0; 279 | case WM_PAINT: 280 | on_paint(); 281 | return 0; 282 | case WM_TIMER: 283 | lv_tick_inc(25); 284 | return 0; 285 | case WM_DESTROY: 286 | PostQuitMessage(0); 287 | return 0; 288 | default: 289 | break; 290 | } 291 | return DefWindowProc(hwnd, msg, wParam, lParam); 292 | } 293 | static COLORREF lv_color_to_colorref(const lv_color_t color) 294 | { 295 | uint32_t raw_color = lv_color_to32(color); 296 | lv_color32_t tmp; 297 | tmp.full = raw_color; 298 | uint32_t colorref = RGB(tmp.ch.red, tmp.ch.green, tmp.ch.blue); 299 | return colorref; 300 | } 301 | #endif 302 | 303 | 304 | 305 | -------------------------------------------------------------------------------- /win_drv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fbdev.h 3 | * 4 | */ 5 | 6 | #ifndef WINDRV_H 7 | #define WINDRV_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_WINDOWS 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | #include 33 | 34 | /********************* 35 | * DEFINES 36 | *********************/ 37 | 38 | /********************** 39 | * TYPEDEFS 40 | **********************/ 41 | 42 | /********************** 43 | * GLOBAL PROTOTYPES 44 | **********************/ 45 | extern bool lv_win_exit_flag; 46 | extern lv_disp_t *lv_windows_disp; 47 | 48 | HWND windrv_init(void); 49 | 50 | /********************** 51 | * MACROS 52 | **********************/ 53 | 54 | #endif /*USE_WINDOWS*/ 55 | 56 | #ifdef __cplusplus 57 | } /* extern "C" */ 58 | #endif 59 | 60 | #endif /*WIN_DRV_H*/ 61 | -------------------------------------------------------------------------------- /x11/x11.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file x11.c 3 | * 4 | */ 5 | 6 | /********************* 7 | * INCLUDES 8 | *********************/ 9 | #include "x11.h" 10 | #if USE_X11 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /********************* 18 | * DEFINES 19 | *********************/ 20 | #ifndef KEYBOARD_BUFFER_SIZE 21 | #define KEYBOARD_BUFFER_SIZE 64 22 | #endif 23 | 24 | #define MIN(A, B) ((A) < (B) ? (A) : (B)) 25 | #define MAX(A, B) ((A) > (B) ? (A) : (B)) 26 | 27 | #ifndef X11_OPTIMIZED_SCREEN_UPDATE 28 | #define X11_OPTIMIZED_SCREEN_UPDATE 1 29 | #endif 30 | 31 | /********************** 32 | * TYPEDEFS 33 | **********************/ 34 | 35 | /********************** 36 | * STATIC VARIABLES 37 | **********************/ 38 | static Display* display = NULL; 39 | static Window window = (XID)-1; 40 | static GC gc = NULL; 41 | static XImage* ximage = NULL; 42 | static lv_timer_t* timer = NULL; 43 | 44 | static char kb_buffer[KEYBOARD_BUFFER_SIZE]; 45 | static lv_point_t mouse_pos = { 0, 0 }; 46 | static bool left_mouse_btn = false; 47 | static bool right_mouse_btn = false; 48 | static bool wheel_mouse_btn = false; 49 | static int16_t wheel_cnt = 0; 50 | 51 | /********************** 52 | * MACROS 53 | **********************/ 54 | 55 | /********************** 56 | * STATIC FUNCTIONS 57 | **********************/ 58 | static int predicate(Display* disp, XEvent* evt, XPointer arg) { return 1; } 59 | 60 | static void x11_event_handler(lv_timer_t * t) 61 | { 62 | XEvent myevent; 63 | KeySym mykey; 64 | int n; 65 | 66 | /* handle all outstanding X events */ 67 | while (XCheckIfEvent(display, &myevent, predicate, NULL)) { 68 | switch(myevent.type) 69 | { 70 | case Expose: 71 | if(myevent.xexpose.count==0) 72 | { 73 | XPutImage(display, window, gc, ximage, 0, 0, 0, 0, LV_HOR_RES, LV_VER_RES); 74 | } 75 | break; 76 | case MotionNotify: 77 | mouse_pos.x = myevent.xmotion.x; 78 | mouse_pos.y = myevent.xmotion.y; 79 | break; 80 | case ButtonPress: 81 | switch (myevent.xbutton.button) 82 | { 83 | case Button1: 84 | left_mouse_btn = true; 85 | break; 86 | case Button2: 87 | wheel_mouse_btn = true; 88 | break; 89 | case Button3: 90 | right_mouse_btn = true; 91 | break; 92 | case Button4: 93 | wheel_cnt--; // Scrolled up 94 | break; 95 | case Button5: 96 | wheel_cnt++; // Scrolled down 97 | break; 98 | default: 99 | LV_LOG_WARN("unhandled button press : %d", myevent.xbutton.button); 100 | } 101 | break; 102 | case ButtonRelease: 103 | switch (myevent.xbutton.button) 104 | { 105 | case Button1: 106 | left_mouse_btn = false; 107 | break; 108 | case Button2: 109 | wheel_mouse_btn = false; 110 | break; 111 | case Button3: 112 | right_mouse_btn = false; 113 | break; 114 | } 115 | break; 116 | case KeyPress: 117 | n = XLookupString(&myevent.xkey, &kb_buffer[0], sizeof(kb_buffer), &mykey, NULL); 118 | kb_buffer[n] = '\0'; 119 | break; 120 | case KeyRelease: 121 | break; 122 | default: 123 | LV_LOG_WARN("unhandled x11 event: %d", myevent.type); 124 | } 125 | } 126 | } 127 | 128 | static void lv_x11_hide_cursor() 129 | { 130 | XColor black = { .red = 0, .green = 0, .blue = 0 }; 131 | char empty_data[] = { 0 }; 132 | 133 | Pixmap empty_bitmap = XCreateBitmapFromData(display, window, empty_data, 1, 1); 134 | Cursor inv_cursor = XCreatePixmapCursor(display, empty_bitmap, empty_bitmap, &black, &black, 0, 0); 135 | XDefineCursor(display, window, inv_cursor); 136 | XFreeCursor(display, inv_cursor); 137 | XFreePixmap(display, empty_bitmap); 138 | } 139 | 140 | 141 | /********************** 142 | * GLOBAL FUNCTIONS 143 | **********************/ 144 | 145 | void lv_x11_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) 146 | { 147 | #if X11_OPTIMIZED_SCREEN_UPDATE 148 | static const lv_area_t inv_area = { .x1 = 0xFFFF, 149 | .x2 = 0, 150 | .y1 = 0xFFFF, 151 | .y2 = 0 152 | }; 153 | static lv_area_t upd_area = inv_area; 154 | 155 | /* build display update area until lv_disp_flush_is_last */ 156 | upd_area.x1 = MIN(upd_area.x1, area->x1); 157 | upd_area.x2 = MAX(upd_area.x2, area->x2); 158 | upd_area.y1 = MIN(upd_area.y1, area->y1); 159 | upd_area.y2 = MAX(upd_area.y2, area->y2); 160 | #endif // X11_OPTIMIZED_SCREEN_UPDATE 161 | 162 | for (lv_coord_t y = area->y1; y <= area->y2; y++) 163 | { 164 | uint32_t dst_offs = area->x1 + y * LV_HOR_RES; 165 | uint32_t* dst_data = &((uint32_t*)ximage->data)[dst_offs]; 166 | for (lv_coord_t x = area->x1; x <= area->x2; x++, color_p++, dst_data++) 167 | { 168 | *dst_data = lv_color_to32(*color_p); 169 | } 170 | } 171 | 172 | if (lv_disp_flush_is_last(disp_drv)) 173 | { 174 | #if X11_OPTIMIZED_SCREEN_UPDATE 175 | /* refresh collected display update area only */ 176 | lv_coord_t upd_w = upd_area.x2 - upd_area.x1 + 1; 177 | lv_coord_t upd_h = upd_area.y2 - upd_area.y1 + 1; 178 | XPutImage(display, window, gc, ximage, upd_area.x1, upd_area.y1, upd_area.x1, upd_area.y1, upd_w, upd_h); 179 | /* invalidate collected area */ 180 | upd_area = inv_area; 181 | #else 182 | /* refresh full display */ 183 | XPutImage(display, window, gc, ximage, 0, 0, 0, 0, LV_HOR_RES, LV_VER_RES); 184 | #endif 185 | } 186 | lv_disp_flush_ready(disp_drv); 187 | } 188 | 189 | void lv_x11_get_pointer(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) 190 | { 191 | (void) indev_drv; // Unused 192 | 193 | data->point = mouse_pos; 194 | data->state = left_mouse_btn ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; 195 | 196 | } 197 | 198 | void lv_x11_get_mousewheel(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) 199 | { 200 | (void) indev_drv; // Unused 201 | 202 | data->state = wheel_mouse_btn ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; 203 | data->enc_diff = wheel_cnt; 204 | wheel_cnt = 0; 205 | } 206 | 207 | void lv_x11_get_keyboard(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) 208 | { 209 | (void) indev_drv; // Unused 210 | 211 | size_t len = strlen(kb_buffer); 212 | if (len > 0) 213 | { 214 | data->state = LV_INDEV_STATE_PRESSED; 215 | data->key = kb_buffer[0]; 216 | memmove(kb_buffer, kb_buffer + 1, len); 217 | data->continue_reading = (len > 0); 218 | } 219 | else 220 | { 221 | data->state = LV_INDEV_STATE_RELEASED; 222 | } 223 | } 224 | 225 | void lv_x11_init(char const* title, lv_coord_t width, lv_coord_t height) 226 | { 227 | /* setup display/screen */ 228 | display = XOpenDisplay(NULL); 229 | int screen = DefaultScreen(display); 230 | 231 | /* drawing contexts for an window */ 232 | unsigned long myforeground = BlackPixel(display, screen); 233 | unsigned long mybackground = WhitePixel(display, screen); 234 | 235 | /* create window */ 236 | window = XCreateSimpleWindow(display, DefaultRootWindow(display), 237 | 0, 0, width, height, 238 | 0, myforeground, mybackground); 239 | 240 | /* window manager properties (yes, use of StdProp is obsolete) */ 241 | XSetStandardProperties(display, window, title, NULL, None, NULL, 0, NULL); 242 | 243 | /* allow receiving mouse and keyboard events */ 244 | XSelectInput(display, window, PointerMotionMask|ButtonPressMask|ButtonReleaseMask|KeyPressMask|KeyReleaseMask|ExposureMask); 245 | 246 | /* graphics context */ 247 | gc = XCreateGC(display, window, 0, 0); 248 | 249 | lv_x11_hide_cursor(); 250 | 251 | /* create cache XImage */ 252 | Visual* visual = XDefaultVisual(display, screen); 253 | int dplanes = DisplayPlanes(display, screen); 254 | ximage = XCreateImage(display, visual, dplanes, ZPixmap, 0, 255 | malloc(width * height * sizeof(uint32_t)), width, height, 32, 0); 256 | 257 | timer = lv_timer_create(x11_event_handler, 10, NULL); 258 | 259 | /* finally bring window on top of the other windows */ 260 | XMapRaised(display, window); 261 | } 262 | 263 | void lv_x11_deinit(void) 264 | { 265 | lv_timer_del(timer); 266 | 267 | free(ximage->data); 268 | 269 | XDestroyImage(ximage); 270 | ximage = NULL; 271 | 272 | XFreeGC(display, gc); 273 | gc = NULL; 274 | XDestroyWindow(display, window); 275 | window = (XID)-1; 276 | 277 | XCloseDisplay(display); 278 | display = NULL; 279 | } 280 | 281 | #endif // USE_X11 282 | -------------------------------------------------------------------------------- /x11/x11.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file x11.h 3 | * 4 | */ 5 | 6 | #ifndef X11_H 7 | #define X11_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /********************* 14 | * INCLUDES 15 | *********************/ 16 | #ifndef LV_DRV_NO_CONF 17 | #ifdef LV_CONF_INCLUDE_SIMPLE 18 | #include "lv_drv_conf.h" 19 | #else 20 | #include "../../lv_drv_conf.h" 21 | #endif 22 | #endif 23 | 24 | #if USE_X11 25 | 26 | #ifdef LV_LVGL_H_INCLUDE_SIMPLE 27 | #include "lvgl.h" 28 | #else 29 | #include "lvgl/lvgl.h" 30 | #endif 31 | 32 | /********************* 33 | * DEFINES 34 | *********************/ 35 | 36 | /********************** 37 | * TYPEDEFS 38 | **********************/ 39 | 40 | /********************** 41 | * GLOBAL PROTOTYPES 42 | **********************/ 43 | void lv_x11_init(char const* title, lv_coord_t width, lv_coord_t height); 44 | void lv_x11_deinit(void); 45 | void lv_x11_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); 46 | void lv_x11_get_pointer(lv_indev_drv_t *indev_drv, lv_indev_data_t *data); 47 | void lv_x11_get_mousewheel(lv_indev_drv_t *indev_drv, lv_indev_data_t *data); 48 | void lv_x11_get_keyboard(lv_indev_drv_t *indev_drv, lv_indev_data_t *data); 49 | 50 | /********************** 51 | * MACROS 52 | **********************/ 53 | 54 | #endif /* USE_X11 */ 55 | 56 | #ifdef __cplusplus 57 | } /* extern "C" */ 58 | #endif 59 | 60 | #endif /* X11_H */ 61 | --------------------------------------------------------------------------------