lib: add lv_drivers v8.3.0 as a subtree module
git subtree add --prefix=lib/lv_drivers --squash \ https://github.com/lvgl/lv_drivers v8.3.0add-custom-font
commit
68dd23525e
@ -0,0 +1,12 @@
|
|||||||
|
# Comment to a new issue.
|
||||||
|
pullRequestOpened: |
|
||||||
|
Thank you for raising your pull request.
|
||||||
|
|
||||||
|
To ensure that all licensing criteria is met all repositories of the LVGL project apply a process called DCO (Developer's Certificate of Origin).
|
||||||
|
|
||||||
|
The text of DCO can be read here: https://developercertificate.org/
|
||||||
|
For a more detailed description see the [Documentation](https://docs.lvgl.io/latest/en/html/contributing/index.html#developer-certification-of-origin-dco) site.
|
||||||
|
|
||||||
|
By contributing to any repositories of the LVGL project you state that your contribution corresponds with the DCO.
|
||||||
|
|
||||||
|
No further action is required if your contribution fulfills the DCO. If you are not sure about it feel free to ask us in a comment.
|
@ -0,0 +1,17 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 21
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 7
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- architecture
|
||||||
|
- pinned
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: stale
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue or pull request has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
@ -0,0 +1,2 @@
|
|||||||
|
**/*.o
|
||||||
|
**/*.d
|
@ -0,0 +1,58 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.12.4)
|
||||||
|
|
||||||
|
project(lv_drivers HOMEPAGE_URL https://github.com/lvgl/lv_drivers/)
|
||||||
|
|
||||||
|
# Option to build as shared library (as opposed to static), default: OFF
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared as library (as opposed to static)" OFF)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCES ./*.c)
|
||||||
|
|
||||||
|
if (BUILD_SHARED_LIBS)
|
||||||
|
add_library(lv_drivers SHARED ${SOURCES})
|
||||||
|
else()
|
||||||
|
add_library(lv_drivers STATIC ${SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(lvgl_drivers ALIAS lv_drivers)
|
||||||
|
add_library(lvgl::drivers ALIAS lv_drivers)
|
||||||
|
|
||||||
|
target_include_directories(lv_drivers SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(PKG_WAYLAND wayland-client wayland-cursor wayland-protocols xkbcommon)
|
||||||
|
target_link_libraries(lv_drivers PUBLIC lvgl ${PKG_WAYLAND_LIBRARIES})
|
||||||
|
|
||||||
|
if("${LIB_INSTALL_DIR}" STREQUAL "")
|
||||||
|
set(LIB_INSTALL_DIR "lib")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("${INC_INSTALL_DIR}" STREQUAL "")
|
||||||
|
set(INC_INSTALL_DIR "include/lvgl/lv_drivers")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY "${CMAKE_SOURCE_DIR}/"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
|
||||||
|
FILES_MATCHING
|
||||||
|
PATTERN "*.h"
|
||||||
|
PATTERN ".git*" EXCLUDE
|
||||||
|
PATTERN "CMakeFiles" EXCLUDE
|
||||||
|
PATTERN "docs" EXCLUDE
|
||||||
|
PATTERN "lib" EXCLUDE)
|
||||||
|
|
||||||
|
file(GLOB LV_DRIVERS_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_drv_conf.h")
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
lv_drivers
|
||||||
|
PROPERTIES OUTPUT_NAME lv_drivers
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||||
|
PUBLIC_HEADER "${LV_DRIVERS_PUBLIC_HEADERS}")
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS lv_drivers
|
||||||
|
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
|
||||||
|
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
|
||||||
|
RUNTIME DESTINATION "${LIB_INSTALL_DIR}"
|
||||||
|
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
|
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 LittlevGL
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -0,0 +1,7 @@
|
|||||||
|
# Display and Touch pad drivers
|
||||||
|
|
||||||
|
Display controller and touchpad driver to can be directly used with [LittlevGL](https://littlevgl.com).
|
||||||
|
|
||||||
|
To learn more about using drivers in LittlevGL visit the [Porting guide](https://docs.lvgl.io/latest/en/html/porting/index.html).
|
||||||
|
|
||||||
|
If you used a new display or touchpad driver with LittlevGL please share it with other people!
|
@ -0,0 +1,597 @@
|
|||||||
|
/**
|
||||||
|
* @file GC9A01.c
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "GC9A01.h"
|
||||||
|
#if USE_GC9A01
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#ifndef GC9A01_XSTART
|
||||||
|
#define GC9A01_XSTART 0
|
||||||
|
#endif
|
||||||
|
#ifndef GC9A01_YSTART
|
||||||
|
#define GC9A01_YSTART 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GC9A01_CMD_MODE 0
|
||||||
|
#define GC9A01_DATA_MODE 1
|
||||||
|
|
||||||
|
#define GC9A01_HOR_RES 240
|
||||||
|
#define GC9A01_VER_RES 240
|
||||||
|
|
||||||
|
/* GC9A01 Commands that we know of. Limited documentation */
|
||||||
|
#define GC9A01_INVOFF 0x20
|
||||||
|
#define GC9A01_INVON 0x21
|
||||||
|
#define GC9A01_DISPON 0x29
|
||||||
|
#define GC9A01_CASET 0x2A
|
||||||
|
#define GC9A01_RASET 0x2B
|
||||||
|
#define GC9A01_RAMWR 0x2C
|
||||||
|
#define GC9A01_COLMOD 0x3A
|
||||||
|
#define GC9A01_MADCTL 0x36
|
||||||
|
#define GC9A01_MADCTL_MY 0x80
|
||||||
|
#define GC9A01_MADCTL_MX 0x40
|
||||||
|
#define GC9A01_MADCTL_MV 0x20
|
||||||
|
#define GC9A01_MADCTL_RGB 0x00
|
||||||
|
#define GC9A01_DISFNCTRL 0xB6
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/* Init script function */
|
||||||
|
struct GC9A01_function {
|
||||||
|
uint16_t cmd;
|
||||||
|
uint16_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Init script commands */
|
||||||
|
enum GC9A01_cmd {
|
||||||
|
GC9A01_START,
|
||||||
|
GC9A01_END,
|
||||||
|
GC9A01_CMD,
|
||||||
|
GC9A01_DATA,
|
||||||
|
GC9A01_DELAY
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void GC9A01_command(uint8_t cmd);
|
||||||
|
static void GC9A01_data(uint8_t data);
|
||||||
|
static void GC9A01_set_addr_win(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
// Documentation on op codes for GC9A01 are very hard to find.
|
||||||
|
// Will document should they be found.
|
||||||
|
static struct GC9A01_function GC9A01_cfg_script[] = {
|
||||||
|
{ GC9A01_START, GC9A01_START},
|
||||||
|
{ GC9A01_CMD, 0xEF},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xEB},
|
||||||
|
{ GC9A01_DATA, 0x14},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xFE}, // Inter Register Enable1
|
||||||
|
{ GC9A01_CMD, 0xEF}, // Inter Register Enable2
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xEB},
|
||||||
|
{ GC9A01_DATA, 0x14},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x84},
|
||||||
|
{ GC9A01_DATA, 0x40},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x85},
|
||||||
|
{ GC9A01_DATA, 0xFF},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x86},
|
||||||
|
{ GC9A01_DATA, 0xFF},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x87},
|
||||||
|
{ GC9A01_DATA, 0xFF},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x88},
|
||||||
|
{ GC9A01_DATA, 0x0A},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x89},
|
||||||
|
{ GC9A01_DATA, 0x21},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x8A},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x8B},
|
||||||
|
{ GC9A01_DATA, 0x80},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x8C},
|
||||||
|
{ GC9A01_DATA, 0x01},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x8D},
|
||||||
|
{ GC9A01_DATA, 0x01},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x8E},
|
||||||
|
{ GC9A01_DATA, 0xFF},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x8F},
|
||||||
|
{ GC9A01_DATA, 0xFF},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, GC9A01_DISFNCTRL}, // Display Function Control
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, GC9A01_MADCTL}, // Memory Access Control
|
||||||
|
{ GC9A01_DATA, 0x48}, // Set the display direction 0,1,2,3 four directions
|
||||||
|
|
||||||
|
{ GC9A01_CMD, GC9A01_COLMOD}, // COLMOD: Pixel Format Set
|
||||||
|
{ GC9A01_DATA, 0x05}, // 16 Bits per pixel
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x90},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xBD},
|
||||||
|
{ GC9A01_DATA, 0x06},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xBC},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xFF},
|
||||||
|
{ GC9A01_DATA, 0x60},
|
||||||
|
{ GC9A01_DATA, 0x01},
|
||||||
|
{ GC9A01_DATA, 0x04},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xC3}, // Power Control 2
|
||||||
|
{ GC9A01_DATA, 0x13},
|
||||||
|
{ GC9A01_CMD, 0xC4}, // Power Control 3
|
||||||
|
{ GC9A01_DATA, 0x13},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xC9}, // Power Control 4
|
||||||
|
{ GC9A01_DATA, 0x22},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xBE},
|
||||||
|
{ GC9A01_DATA, 0x11},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xE1},
|
||||||
|
{ GC9A01_DATA, 0x10},
|
||||||
|
{ GC9A01_DATA, 0x0E},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xDF},
|
||||||
|
{ GC9A01_DATA, 0x21},
|
||||||
|
{ GC9A01_DATA, 0x0C},
|
||||||
|
{ GC9A01_DATA, 0x02},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xF0}, // SET_GAMMA1
|
||||||
|
{ GC9A01_DATA, 0x45},
|
||||||
|
{ GC9A01_DATA, 0x09},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x26},
|
||||||
|
{ GC9A01_DATA, 0x2A},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xF1}, // SET_GAMMA2
|
||||||
|
{ GC9A01_DATA, 0x43},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x72},
|
||||||
|
{ GC9A01_DATA, 0x36},
|
||||||
|
{ GC9A01_DATA, 0x37},
|
||||||
|
{ GC9A01_DATA, 0x6F},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xF2}, // SET_GAMMA3
|
||||||
|
{ GC9A01_DATA, 0x45},
|
||||||
|
{ GC9A01_DATA, 0x09},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x26},
|
||||||
|
{ GC9A01_DATA, 0x2A},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xF3}, // SET_GAMMA4
|
||||||
|
{ GC9A01_DATA, 0x43},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x72},
|
||||||
|
{ GC9A01_DATA, 0x36},
|
||||||
|
{ GC9A01_DATA, 0x37},
|
||||||
|
{ GC9A01_DATA, 0x6F},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xED},
|
||||||
|
{ GC9A01_DATA, 0x1B},
|
||||||
|
{ GC9A01_DATA, 0x0B},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xAE},
|
||||||
|
{ GC9A01_DATA, 0x77},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xCD},
|
||||||
|
{ GC9A01_DATA, 0x63},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x07},
|
||||||
|
{ GC9A01_DATA, 0x07},
|
||||||
|
{ GC9A01_DATA, 0x04},
|
||||||
|
{ GC9A01_DATA, 0x0E},
|
||||||
|
{ GC9A01_DATA, 0x0F},
|
||||||
|
{ GC9A01_DATA, 0x09},
|
||||||
|
{ GC9A01_DATA, 0x07},
|
||||||
|
{ GC9A01_DATA, 0x08},
|
||||||
|
{ GC9A01_DATA, 0x03},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0xE8},
|
||||||
|
{ GC9A01_DATA, 0x34},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x62},
|
||||||
|
{ GC9A01_DATA, 0x18},
|
||||||
|
{ GC9A01_DATA, 0x0D},
|
||||||
|
{ GC9A01_DATA, 0x71},
|
||||||
|
{ GC9A01_DATA, 0xED},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x18},
|
||||||
|
{ GC9A01_DATA, 0x0F},
|
||||||
|
{ GC9A01_DATA, 0x71},
|
||||||
|
{ GC9A01_DATA, 0xEF},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x63},
|
||||||
|
{ GC9A01_DATA, 0x18},
|
||||||
|
{ GC9A01_DATA, 0x11},
|
||||||
|
{ GC9A01_DATA, 0x71},
|
||||||
|
{ GC9A01_DATA, 0xF1},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x18},
|
||||||
|
{ GC9A01_DATA, 0x13},
|
||||||
|
{ GC9A01_DATA, 0x71},
|
||||||
|
{ GC9A01_DATA, 0xF3},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
{ GC9A01_DATA, 0x70},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x64},
|
||||||
|
{ GC9A01_DATA, 0x28},
|
||||||
|
{ GC9A01_DATA, 0x29},
|
||||||
|
{ GC9A01_DATA, 0xF1},
|
||||||
|
{ GC9A01_DATA, 0x01},
|
||||||
|
{ GC9A01_DATA, 0xF1},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x07},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x66},
|
||||||
|
{ GC9A01_DATA, 0x3C},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0xCD},
|
||||||
|
{ GC9A01_DATA, 0x67},
|
||||||
|
{ GC9A01_DATA, 0x45},
|
||||||
|
{ GC9A01_DATA, 0x45},
|
||||||
|
{ GC9A01_DATA, 0x10},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x67},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x3C},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x01},
|
||||||
|
{ GC9A01_DATA, 0x54},
|
||||||
|
{ GC9A01_DATA, 0x10},
|
||||||
|
{ GC9A01_DATA, 0x32},
|
||||||
|
{ GC9A01_DATA, 0x98},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x74},
|
||||||
|
{ GC9A01_DATA, 0x10},
|
||||||
|
{ GC9A01_DATA, 0x85},
|
||||||
|
{ GC9A01_DATA, 0x80},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
{ GC9A01_DATA, 0x4E},
|
||||||
|
{ GC9A01_DATA, 0x00},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x98},
|
||||||
|
{ GC9A01_DATA, 0x3E},
|
||||||
|
{ GC9A01_DATA, 0x07},
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x35}, // Tearing Effect Line ON
|
||||||
|
{ GC9A01_CMD, 0x21}, // Display Inversion ON
|
||||||
|
|
||||||
|
{ GC9A01_CMD, 0x11}, // Sleep Out Mode
|
||||||
|
{ GC9A01_DELAY, 120},
|
||||||
|
{ GC9A01_CMD, GC9A01_DISPON}, // Display ON
|
||||||
|
{ GC9A01_DELAY, 255},
|
||||||
|
{ GC9A01_END, GC9A01_END},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a command to the GC9A01
|
||||||
|
* @param cmd the command
|
||||||
|
*/
|
||||||
|
static void GC9A01_command(uint8_t cmd)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(GC9A01_CMD_MODE);
|
||||||
|
LV_DRV_DISP_SPI_WR_BYTE(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data to the GC9A01
|
||||||
|
* @param data the data
|
||||||
|
*/
|
||||||
|
static void GC9A01_data(uint8_t data)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(GC9A01_DATA_MODE);
|
||||||
|
LV_DRV_DISP_SPI_WR_BYTE(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GC9A01_data_array(uint8_t *buf, uint32_t len)
|
||||||
|
{
|
||||||
|
uint8_t *pt = buf;
|
||||||
|
|
||||||
|
for (uint32_t lp = 0; lp < len; lp++, pt++)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_SPI_WR_BYTE(*pt);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GC9A01_databuf(uint32_t len, uint8_t *buf)
|
||||||
|
{
|
||||||
|
uint32_t byte_left = len;
|
||||||
|
uint8_t *pt = buf;
|
||||||
|
|
||||||
|
while (byte_left)
|
||||||
|
{
|
||||||
|
if (byte_left > 64)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY((char*)pt, 64);
|
||||||
|
byte_left = byte_left - 64;
|
||||||
|
pt = pt + 64;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY((char*)pt, byte_left);
|
||||||
|
byte_left=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hard reset of the tft controller
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
static void GC9A01_hard_reset( void )
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_SPI_CS(0); // Low to listen to us
|
||||||
|
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
LV_DRV_DISP_RST(0);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration of the tft controller
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
static void GC9A01_run_cfg_script(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int end_script = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
switch (GC9A01_cfg_script[i].cmd)
|
||||||
|
{
|
||||||
|
case GC9A01_START:
|
||||||
|
break;
|
||||||
|
case GC9A01_CMD:
|
||||||
|
GC9A01_command( GC9A01_cfg_script[i].data & 0xFF );
|
||||||
|
break;
|
||||||
|
case GC9A01_DATA:
|
||||||
|
GC9A01_data( GC9A01_cfg_script[i].data & 0xFF );
|
||||||
|
break;
|
||||||
|
case GC9A01_DELAY:
|
||||||
|
LV_DRV_DELAY_MS(GC9A01_cfg_script[i].data);
|
||||||
|
break;
|
||||||
|
case GC9A01_END:
|
||||||
|
end_script = 1;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (!end_script);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
|
||||||
|
// Rudimentary clipping
|
||||||
|
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
|
||||||
|
if((y+h-1) >= GC9A01_VER_RES) h = GC9A01_VER_RES - y;
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(0); // Listen to us
|
||||||
|
|
||||||
|
GC9A01_set_addr_win(x, y, x, y + h - 1);
|
||||||
|
|
||||||
|
uint8_t hi = color >> 8, lo = color;
|
||||||
|
|
||||||
|
while (h--) {
|
||||||
|
GC9A01_data(hi);
|
||||||
|
GC9A01_data(lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
|
||||||
|
// Rudimentary clipping
|
||||||
|
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
|
||||||
|
if((x+w-1) >= GC9A01_HOR_RES) w = GC9A01_HOR_RES - x;
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(0); // Listen to us
|
||||||
|
|
||||||
|
GC9A01_set_addr_win(x, y, x + w - 1, y);
|
||||||
|
|
||||||
|
uint8_t hi = color >> 8, lo = color;
|
||||||
|
|
||||||
|
while (w--) {
|
||||||
|
GC9A01_data(hi);
|
||||||
|
GC9A01_data(lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
|
||||||
|
uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_invertDisplay(bool i)
|
||||||
|
{
|
||||||
|
GC9A01_command(i ? GC9A01_INVON : GC9A01_INVOFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||||
|
{
|
||||||
|
if((x < 0) ||(x >= GC9A01_HOR_RES) || (y < 0) || (y >= GC9A01_VER_RES)) return;
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(0); // Listen to us
|
||||||
|
GC9A01_set_addr_win(x, y, x, y);
|
||||||
|
|
||||||
|
uint8_t hi = color >> 8, lo = color;
|
||||||
|
|
||||||
|
GC9A01_data(hi);
|
||||||
|
GC9A01_data(lo);
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_fillScreen(uint16_t color) {
|
||||||
|
GC9A01_fillRect(0, 0, GC9A01_HOR_RES, GC9A01_VER_RES, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill a rectangle
|
||||||
|
void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||||
|
// rudimentary clipping (drawChar w/big text requires this)
|
||||||
|
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
|
||||||
|
if((x + w - 1) >= GC9A01_HOR_RES) w = GC9A01_HOR_RES - x;
|
||||||
|
if((y + h - 1) >= GC9A01_VER_RES) h = GC9A01_VER_RES - y;
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(0); // Listen to us
|
||||||
|
|
||||||
|
GC9A01_set_addr_win(x, y, x + w - 1, y + h - 1);
|
||||||
|
|
||||||
|
uint8_t hi = color >> 8, lo = color;
|
||||||
|
|
||||||
|
for (y = h; y > 0; y--)
|
||||||
|
{
|
||||||
|
for (x = w; x > 0; x--)
|
||||||
|
{
|
||||||
|
GC9A01_data(hi);
|
||||||
|
GC9A01_data(lo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_setRotation(uint8_t m) {
|
||||||
|
|
||||||
|
GC9A01_command(GC9A01_MADCTL);
|
||||||
|
m %= 4; // can't be higher than 3
|
||||||
|
switch (m) {
|
||||||
|
case 0:
|
||||||
|
GC9A01_data(GC9A01_MADCTL_MX | GC9A01_MADCTL_MY | GC9A01_MADCTL_RGB);
|
||||||
|
|
||||||
|
// _xstart = _colstart;
|
||||||
|
// _ystart = _rowstart;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
GC9A01_data(GC9A01_MADCTL_MY | GC9A01_MADCTL_MV | GC9A01_MADCTL_RGB);
|
||||||
|
|
||||||
|
// _ystart = _colstart;
|
||||||
|
// _xstart = _rowstart;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
GC9A01_data(GC9A01_MADCTL_RGB);
|
||||||
|
|
||||||
|
// _xstart = _colstart;
|
||||||
|
// _ystart = _rowstart;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
GC9A01_data(GC9A01_MADCTL_MX | GC9A01_MADCTL_MV | GC9A01_MADCTL_RGB);
|
||||||
|
|
||||||
|
// _ystart = _colstart;
|
||||||
|
// _xstart = _rowstart;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the GC9A01
|
||||||
|
*/
|
||||||
|
int GC9A01_init(void)
|
||||||
|
{
|
||||||
|
GC9A01_hard_reset();
|
||||||
|
GC9A01_run_cfg_script();
|
||||||
|
|
||||||
|
// GC9A01_fillScreen(0x0000); // Black
|
||||||
|
// GC9A01_fillScreen(0xFFFF); // White
|
||||||
|
GC9A01_fillScreen(0xAAAA); // ?
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GC9A01_set_addr_win(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
|
||||||
|
{
|
||||||
|
uint16_t x_start = x0 + GC9A01_XSTART, x_end = x1 + GC9A01_XSTART;
|
||||||
|
uint16_t y_start = y0 + GC9A01_YSTART, y_end = y1 + GC9A01_YSTART;
|
||||||
|
|
||||||
|
GC9A01_command(GC9A01_CASET); // Column addr set
|
||||||
|
GC9A01_data(x_start >> 8);
|
||||||
|
GC9A01_data(x_start & 0xFF); // XSTART
|
||||||
|
GC9A01_data(x_end >> 8);
|
||||||
|
GC9A01_data(x_end & 0xFF); // XEND
|
||||||
|
|
||||||
|
GC9A01_command(GC9A01_RASET); // Row addr set
|
||||||
|
GC9A01_data(y_start >> 8);
|
||||||
|
GC9A01_data(y_start & 0xFF); // YSTART
|
||||||
|
GC9A01_data(y_end >> 8);
|
||||||
|
GC9A01_data(y_end & 0xFF); // YEND
|
||||||
|
|
||||||
|
GC9A01_command(GC9A01_RAMWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GC9A01_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t *color_p)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_SPI_CS(0); // Listen to us
|
||||||
|
|
||||||
|
GC9A01_set_addr_win(area->x1, area->y1, area->x2, area->y2);
|
||||||
|
int32_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;
|
||||||
|
|
||||||
|
LV_DRV_DISP_CMD_DATA(GC9A01_DATA_MODE);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY((char*)color_p, len);
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
lv_disp_flush_ready(disp_drv); /* Indicate you are ready with the flushing*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* @file GC9A01.h
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef GC9A01_H
|
||||||
|
#define GC9A01_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_GC9A01
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LV_COLOR_DEPTH != 16
|
||||||
|
#error "GC9A01 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LV_COLOR_16_SWAP != 1
|
||||||
|
#error "GC9A01 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
int GC9A01_init(void);
|
||||||
|
void GC9A01_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void GC9A01_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
|
||||||
|
void GC9A01_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p);
|
||||||
|
void GC9A01_setRotation(uint8_t m);
|
||||||
|
void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||||
|
void GC9A01_fillScreen(uint16_t color);
|
||||||
|
uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
void GC9A01_invertDisplay(bool i);
|
||||||
|
void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||||
|
void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||||
|
void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_GC9A01 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GC9A01_H */
|
||||||
|
|
@ -0,0 +1,432 @@
|
|||||||
|
/**
|
||||||
|
* @file ILI9341.c
|
||||||
|
*
|
||||||
|
* ILI9341.pdf [ILI9341_DS_V1.13_20110805]
|
||||||
|
*
|
||||||
|
* [references]
|
||||||
|
* - https://www.newhavendisplay.com/app_notes/ILI9341.pdf
|
||||||
|
* - Linux Source [v5.9-rc4] "drivers/staging/fbtft/fb_ili9341.c"
|
||||||
|
* - https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp
|
||||||
|
* - https://os.mbed.com/users/dreschpe/code/SPI_TFT_ILI9341
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "ILI9341.h"
|
||||||
|
#if USE_ILI9341 != 0
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define ILI9341_CMD_MODE 0
|
||||||
|
#define ILI9341_DATA_MODE 1
|
||||||
|
|
||||||
|
#define ILI9341_TFTWIDTH 240
|
||||||
|
#define ILI9341_TFTHEIGHT 320
|
||||||
|
|
||||||
|
/* Level 1 Commands -------------- [section] Description */
|
||||||
|
|
||||||
|
#define ILI9341_NOP 0x00 /* [8.2.1 ] No Operation / Terminate Frame Memory Write */
|
||||||
|
#define ILI9341_SWRESET 0x01 /* [8.2.2 ] Software Reset */
|
||||||
|
#define ILI9341_RDDIDIF 0x04 /* [8.2.3 ] Read Display Identification Information */
|
||||||
|
#define ILI9341_RDDST 0x09 /* [8.2.4 ] Read Display Status */
|
||||||
|
#define ILI9341_RDDPM 0x0A /* [8.2.5 ] Read Display Power Mode */
|
||||||
|
#define ILI9341_RDDMADCTL 0x0B /* [8.2.6 ] Read Display MADCTL */
|
||||||
|
#define ILI9341_RDDCOLMOD 0x0C /* [8.2.7 ] Read Display Pixel Format */
|
||||||
|
#define ILI9341_RDDIM 0x0D /* [8.2.8 ] Read Display Image Mode */
|
||||||
|
#define ILI9341_RDDSM 0x0E /* [8.2.9 ] Read Display Signal Mode */
|
||||||
|
#define ILI9341_RDDSDR 0x0F /* [8.2.10] Read Display Self-Diagnostic Result */
|
||||||
|
#define ILI9341_SLPIN 0x10 /* [8.2.11] Enter Sleep Mode */
|
||||||
|
#define ILI9341_SLPOUT 0x11 /* [8.2.12] Leave Sleep Mode */
|
||||||
|
#define ILI9341_PTLON 0x12 /* [8.2.13] Partial Display Mode ON */
|
||||||
|
#define ILI9341_NORON 0x13 /* [8.2.14] Normal Display Mode ON */
|
||||||
|
#define ILI9341_DINVOFF 0x20 /* [8.2.15] Display Inversion OFF */
|
||||||
|
#define ILI9341_DINVON 0x21 /* [8.2.16] Display Inversion ON */
|
||||||
|
#define ILI9341_GAMSET 0x26 /* [8.2.17] Gamma Set */
|
||||||
|
#define ILI9341_DISPOFF 0x28 /* [8.2.18] Display OFF*/
|
||||||
|
#define ILI9341_DISPON 0x29 /* [8.2.19] Display ON*/
|
||||||
|
#define ILI9341_CASET 0x2A /* [8.2.20] Column Address Set */
|
||||||
|
#define ILI9341_PASET 0x2B /* [8.2.21] Page Address Set */
|
||||||
|
#define ILI9341_RAMWR 0x2C /* [8.2.22] Memory Write */
|
||||||
|
#define ILI9341_RGBSET 0x2D /* [8.2.23] Color Set (LUT for 16-bit to 18-bit color depth conversion) */
|
||||||
|
#define ILI9341_RAMRD 0x2E /* [8.2.24] Memory Read */
|
||||||
|
#define ILI9341_PTLAR 0x30 /* [8.2.25] Partial Area */
|
||||||
|
#define ILI9341_VSCRDEF 0x33 /* [8.2.26] Veritcal Scrolling Definition */
|
||||||
|
#define ILI9341_TEOFF 0x34 /* [8.2.27] Tearing Effect Line OFF */
|
||||||
|
#define ILI9341_TEON 0x35 /* [8.2.28] Tearing Effect Line ON */
|
||||||
|
#define ILI9341_MADCTL 0x36 /* [8.2.29] Memory Access Control */
|
||||||
|
#define MADCTL_MY 0x80 /* MY row address order */
|
||||||
|
#define MADCTL_MX 0x40 /* MX column address order */
|
||||||
|
#define MADCTL_MV 0x20 /* MV row / column exchange */
|
||||||
|
#define MADCTL_ML 0x10 /* ML vertical refresh order */
|
||||||
|
#define MADCTL_MH 0x04 /* MH horizontal refresh order */
|
||||||
|
#define MADCTL_RGB 0x00 /* RGB Order [default] */
|
||||||
|
#define MADCTL_BGR 0x08 /* BGR Order */
|
||||||
|
#define ILI9341_VSCRSADD 0x37 /* [8.2.30] Vertical Scrolling Start Address */
|
||||||
|
#define ILI9341_IDMOFF 0x38 /* [8.2.31] Idle Mode OFF */
|
||||||
|
#define ILI9341_IDMON 0x39 /* [8.2.32] Idle Mode ON */
|
||||||
|
#define ILI9341_PIXSET 0x3A /* [8.2.33] Pixel Format Set */
|
||||||
|
#define ILI9341_WRMEMCONT 0x3C /* [8.2.34] Write Memory Continue */
|
||||||
|
#define ILI9341_RDMEMCONT 0x3E /* [8.2.35] Read Memory Continue */
|
||||||
|
#define ILI9341_SETSCANTE 0x44 /* [8.2.36] Set Tear Scanline */
|
||||||
|
#define ILI9341_GETSCAN 0x45 /* [8.2.37] Get Scanline */
|
||||||
|
#define ILI9341_WRDISBV 0x51 /* [8.2.38] Write Display Brightness Value */
|
||||||
|
#define ILI9341_RDDISBV 0x52 /* [8.2.39] Read Display Brightness Value */
|
||||||
|
#define ILI9341_WRCTRLD 0x53 /* [8.2.40] Write Control Display */
|
||||||
|
#define ILI9341_RDCTRLD 0x54 /* [8.2.41] Read Control Display */
|
||||||
|
#define ILI9341_WRCABC 0x55 /* [8.2.42] Write Content Adaptive Brightness Control Value */
|
||||||
|
#define ILI9341_RDCABC 0x56 /* [8.2.43] Read Content Adaptive Brightness Control Value */
|
||||||
|
#define ILI9341_WRCABCMIN 0x5E /* [8.2.44] Write CABC Minimum Brightness */
|
||||||
|
#define ILI9341_RDCABCMIN 0x5F /* [8.2.45] Read CABC Minimum Brightness */
|
||||||
|
#define ILI9341_RDID1 0xDA /* [8.2.46] Read ID1 - Manufacturer ID (user) */
|
||||||
|
#define ILI9341_RDID2 0xDB /* [8.2.47] Read ID2 - Module/Driver version (supplier) */
|
||||||
|
#define ILI9341_RDID3 0xDC /* [8.2.48] Read ID3 - Module/Driver version (user) */
|
||||||
|
|
||||||
|
/* Level 2 Commands -------------- [section] Description */
|
||||||
|
|
||||||
|
#define ILI9341_IFMODE 0xB0 /* [8.3.1 ] Interface Mode Control */
|
||||||
|
#define ILI9341_FRMCTR1 0xB1 /* [8.3.2 ] Frame Rate Control (In Normal Mode/Full Colors) */
|
||||||
|
#define ILI9341_FRMCTR2 0xB2 /* [8.3.3 ] Frame Rate Control (In Idle Mode/8 colors) */
|
||||||
|
#define ILI9341_FRMCTR3 0xB3 /* [8.3.4 ] Frame Rate control (In Partial Mode/Full Colors) */
|
||||||
|
#define ILI9341_INVTR 0xB4 /* [8.3.5 ] Display Inversion Control */
|
||||||
|
#define ILI9341_PRCTR 0xB5 /* [8.3.6 ] Blanking Porch Control */
|
||||||
|
#define ILI9341_DISCTRL 0xB6 /* [8.3.7 ] Display Function Control */
|
||||||
|
#define ILI9341_ETMOD 0xB7 /* [8.3.8 ] Entry Mode Set */
|
||||||
|
#define ILI9341_BLCTRL1 0xB8 /* [8.3.9 ] Backlight Control 1 - Grayscale Histogram UI mode */
|
||||||
|
#define ILI9341_BLCTRL2 0xB9 /* [8.3.10] Backlight Control 2 - Grayscale Histogram still picture mode */
|
||||||
|
#define ILI9341_BLCTRL3 0xBA /* [8.3.11] Backlight Control 3 - Grayscale Thresholds UI mode */
|
||||||
|
#define ILI9341_BLCTRL4 0xBB /* [8.3.12] Backlight Control 4 - Grayscale Thresholds still picture mode */
|
||||||
|
#define ILI9341_BLCTRL5 0xBC /* [8.3.13] Backlight Control 5 - Brightness Transition time */
|
||||||
|
#define ILI9341_BLCTRL7 0xBE /* [8.3.14] Backlight Control 7 - PWM Frequency */
|
||||||
|
#define ILI9341_BLCTRL8 0xBF /* [8.3.15] Backlight Control 8 - ON/OFF + PWM Polarity*/
|
||||||
|
#define ILI9341_PWCTRL1 0xC0 /* [8.3.16] Power Control 1 - GVDD */
|
||||||
|
#define ILI9341_PWCTRL2 0xC1 /* [8.3.17] Power Control 2 - step-up factor for operating voltage */
|
||||||
|
#define ILI9341_VMCTRL1 0xC5 /* [8.3.18] VCOM Control 1 - Set VCOMH and VCOML */
|
||||||
|
#define ILI9341_VMCTRL2 0xC7 /* [8.3.19] VCOM Control 2 - VCOM offset voltage */
|
||||||
|
#define ILI9341_NVMWR 0xD0 /* [8.3.20] NV Memory Write */
|
||||||
|
#define ILI9341_NVMPKEY 0xD1 /* [8.3.21] NV Memory Protection Key */
|
||||||
|
#define ILI9341_RDNVM 0xD2 /* [8.3.22] NV Memory Status Read */
|
||||||
|
#define ILI9341_RDID4 0xD3 /* [8.3.23] Read ID4 - IC Device Code */
|
||||||
|
#define ILI9341_PGAMCTRL 0xE0 /* [8.3.24] Positive Gamma Control */
|
||||||
|
#define ILI9341_NGAMCTRL 0xE1 /* [8.3.25] Negative Gamma Correction */
|
||||||
|
#define ILI9341_DGAMCTRL1 0xE2 /* [8.3.26] Digital Gamma Control 1 */
|
||||||
|
#define ILI9341_DGAMCTRL2 0xE3 /* [8.3.27] Digital Gamma Control 2 */
|
||||||
|
#define ILI9341_IFCTL 0xF6 /* [8.3.28] 16bits Data Format Selection */
|
||||||
|
|
||||||
|
/* Extended Commands --------------- [section] Description*/
|
||||||
|
|
||||||
|
#define ILI9341_PWCTRLA 0xCB /* [8.4.1] Power control A */
|
||||||
|
#define ILI9341_PWCTRLB 0xCF /* [8.4.2] Power control B */
|
||||||
|
#define ILI9341_TIMECTRLA_INT 0xE8 /* [8.4.3] Internal Clock Driver timing control A */
|
||||||
|
#define ILI9341_TIMECTRLA_EXT 0xE9 /* [8.4.4] External Clock Driver timing control A */
|
||||||
|
#define ILI9341_TIMECTRLB 0xEA /* [8.4.5] Driver timing control B (gate driver timing control) */
|
||||||
|
#define ILI9341_PWSEQCTRL 0xED /* [8.4.6] Power on sequence control */
|
||||||
|
#define ILI9341_GAM3CTRL 0xF2 /* [8.4.7] Enable 3 gamma control */
|
||||||
|
#define ILI9341_PUMPRATIO 0xF7 /* [8.4.8] Pump ratio control */
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static inline void ili9341_write(int mode, uint8_t data);
|
||||||
|
static inline void ili9341_write_array(int mode, uint8_t *data, uint16_t len);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the ILI9341 display controller
|
||||||
|
*/
|
||||||
|
void ili9341_init(void)
|
||||||
|
{
|
||||||
|
uint8_t data[15];
|
||||||
|
|
||||||
|
/* hardware reset */
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
LV_DRV_DISP_CMD_DATA(ILI9341_DATA_MODE);
|
||||||
|
LV_DRV_DISP_RST(0);
|
||||||
|
LV_DRV_DELAY_US(50);
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(5);
|
||||||
|
|
||||||
|
/* software reset */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_SWRESET);
|
||||||
|
LV_DRV_DELAY_MS(5);
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISPOFF);
|
||||||
|
|
||||||
|
/* startup sequence */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRLB);
|
||||||
|
data[0] = 0x00;
|
||||||
|
data[1] = 0x83;
|
||||||
|
data[2] = 0x30;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 3);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWSEQCTRL);
|
||||||
|
data[0] = 0x64;
|
||||||
|
data[1] = 0x03;
|
||||||
|
data[2] = 0x12;
|
||||||
|
data[3] = 0x81;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_TIMECTRLA_INT);
|
||||||
|
data[0] = 0x85;
|
||||||
|
data[1] = 0x01;
|
||||||
|
data[2] = 0x79;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 3);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRLA);
|
||||||
|
data[0] = 0x39;
|
||||||
|
data[1] = 0x2c;
|
||||||
|
data[2] = 0x00;
|
||||||
|
data[3] = 0x34;
|
||||||
|
data[4] = 0x02;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 5);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PUMPRATIO);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0x20);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_TIMECTRLB);
|
||||||
|
data[0] = 0x00;
|
||||||
|
data[1] = 0x00;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
|
||||||
|
|
||||||
|
/* power control */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRL1);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0x26);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRL2);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0x11);
|
||||||
|
|
||||||
|
/* VCOM */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_VMCTRL1);
|
||||||
|
data[0] = 0x35;
|
||||||
|
data[1] = 0x3e;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_VMCTRL2);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0xbe);
|
||||||
|
|
||||||
|
/* set orientation */
|
||||||
|
ili9341_rotate(0, ILI9341_BGR);
|
||||||
|
|
||||||
|
/* 16 bit pixel */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PIXSET);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0x55);
|
||||||
|
|
||||||
|
/* frame rate */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_FRMCTR1);
|
||||||
|
data[0] = 0x00;
|
||||||
|
data[1] = 0x1b;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
|
||||||
|
|
||||||
|
#if ILI9341_GAMMA
|
||||||
|
/* gamma curve set */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_GAMSET);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0x01);
|
||||||
|
|
||||||
|
/* positive gamma correction */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PGAMCTRL);
|
||||||
|
data[0] = 0x1f;
|
||||||
|
data[1] = 0x1a;
|
||||||
|
data[2] = 0x18;
|
||||||
|
data[3] = 0x0a;
|
||||||
|
data[4] = 0x0f;
|
||||||
|
data[5] = 0x06;
|
||||||
|
data[6] = 0x45;
|
||||||
|
data[7] = 0x87;
|
||||||
|
data[8] = 0x32;
|
||||||
|
data[9] = 0x0a;
|
||||||
|
data[10] = 0x07;
|
||||||
|
data[11] = 0x02;
|
||||||
|
data[12] = 0x07;
|
||||||
|
data[13] = 0x05;
|
||||||
|
data[14] = 0x00;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 15);
|
||||||
|
|
||||||
|
/* negative gamma correction */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_NGAMCTRL);
|
||||||
|
data[0] = 0x00;
|
||||||
|
data[1] = 0x25;
|
||||||
|
data[2] = 0x27;
|
||||||
|
data[3] = 0x05;
|
||||||
|
data[4] = 0x10;
|
||||||
|
data[5] = 0x09;
|
||||||
|
data[6] = 0x3a;
|
||||||
|
data[7] = 0x78;
|
||||||
|
data[8] = 0x4d;
|
||||||
|
data[9] = 0x05;
|
||||||
|
data[10] = 0x18;
|
||||||
|
data[11] = 0x0d;
|
||||||
|
data[12] = 0x38;
|
||||||
|
data[13] = 0x3a;
|
||||||
|
data[14] = 0x1f;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 15);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* window horizontal */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_CASET);
|
||||||
|
data[0] = 0;
|
||||||
|
data[1] = 0;
|
||||||
|
data[2] = (ILI9341_HOR_RES - 1) >> 8;
|
||||||
|
data[3] = (ILI9341_HOR_RES - 1);
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
|
||||||
|
|
||||||
|
/* window vertical */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PASET);
|
||||||
|
data[0] = 0;
|
||||||
|
data[1] = 0;
|
||||||
|
data[2] = (ILI9341_VER_RES - 1) >> 8;
|
||||||
|
data[3] = (ILI9341_VER_RES - 1);
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_RAMWR);
|
||||||
|
|
||||||
|
#if ILI9341_TEARING
|
||||||
|
/* tearing effect off */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_TEOFF);
|
||||||
|
|
||||||
|
/* tearing effect on */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_TEON);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* entry mode set */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_ETMOD);
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, 0x07);
|
||||||
|
|
||||||
|
/* display function control */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISCTRL);
|
||||||
|
data[0] = 0x0a;
|
||||||
|
data[1] = 0x82;
|
||||||
|
data[2] = 0x27;
|
||||||
|
data[3] = 0x00;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
|
||||||
|
|
||||||
|
/* exit sleep mode */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_SLPOUT);
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(100);
|
||||||
|
|
||||||
|
/* display on */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISPON);
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
if(area->x2 < 0 || area->y2 < 0 || area->x1 > (ILI9341_HOR_RES - 1) || area->y1 > (ILI9341_VER_RES - 1)) {
|
||||||
|
lv_disp_flush_ready(drv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Truncate the area to the screen */
|
||||||
|
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
|
||||||
|
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
|
||||||
|
int32_t act_x2 = area->x2 > ILI9341_HOR_RES - 1 ? ILI9341_HOR_RES - 1 : area->x2;
|
||||||
|
int32_t act_y2 = area->y2 > ILI9341_VER_RES - 1 ? ILI9341_VER_RES - 1 : area->y2;
|
||||||
|
|
||||||
|
int32_t y;
|
||||||
|
uint8_t data[4];
|
||||||
|
int32_t len = len = (act_x2 - act_x1 + 1) * 2;
|
||||||
|
lv_coord_t w = (area->x2 - area->x1) + 1;
|
||||||
|
|
||||||
|
/* window horizontal */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_CASET);
|
||||||
|
data[0] = act_x1 >> 8;
|
||||||
|
data[1] = act_x1;
|
||||||
|
data[2] = act_x2 >> 8;
|
||||||
|
data[3] = act_x2;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
|
||||||
|
|
||||||
|
/* window vertical */
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_PASET);
|
||||||
|
data[0] = act_y1 >> 8;
|
||||||
|
data[1] = act_y1;
|
||||||
|
data[2] = act_y2 >> 8;
|
||||||
|
data[3] = act_y2;
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_RAMWR);
|
||||||
|
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
ili9341_write_array(ILI9341_DATA_MODE, (uint8_t *)color_p, len);
|
||||||
|
color_p += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_disp_flush_ready(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ili9341_rotate(int degrees, bool bgr)
|
||||||
|
{
|
||||||
|
uint8_t color_order = MADCTL_RGB;
|
||||||
|
|
||||||
|
if(bgr)
|
||||||
|
color_order = MADCTL_BGR;
|
||||||
|
|
||||||
|
ili9341_write(ILI9341_CMD_MODE, ILI9341_MADCTL);
|
||||||
|
|
||||||
|
switch(degrees) {
|
||||||
|
case 270:
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, MADCTL_MV | color_order);
|
||||||
|
break;
|
||||||
|
case 180:
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, MADCTL_MY | color_order);
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, MADCTL_MX | MADCTL_MY | MADCTL_MV | color_order);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* fall-through */
|
||||||
|
default:
|
||||||
|
ili9341_write(ILI9341_DATA_MODE, MADCTL_MX | color_order);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write byte
|
||||||
|
* @param mode sets command or data mode for write
|
||||||
|
* @param byte the byte to write
|
||||||
|
*/
|
||||||
|
static inline void ili9341_write(int mode, uint8_t data)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(mode);
|
||||||
|
LV_DRV_DISP_SPI_WR_BYTE(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write byte array
|
||||||
|
* @param mode sets command or data mode for write
|
||||||
|
* @param data the byte array to write
|
||||||
|
* @param len the length of the byte array
|
||||||
|
*/
|
||||||
|
static inline void ili9341_write_array(int mode, uint8_t *data, uint16_t len)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(mode);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* @file ILI9341.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ILI9341_H
|
||||||
|
#define ILI9341_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_ILI9341
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LV_COLOR_DEPTH != 16
|
||||||
|
#error "ILI9341 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LV_COLOR_16_SWAP != 1
|
||||||
|
#error "ILI9341 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define ILI9341_BGR true
|
||||||
|
#define ILI9341_RGB false
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void ili9341_init(void);
|
||||||
|
void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void ili9341_rotate(int degrees, bool bgr);
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_ILI9341 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ILI9341_H */
|
@ -0,0 +1,425 @@
|
|||||||
|
/**
|
||||||
|
* @file R61581.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "R61581.h"
|
||||||
|
#if USE_R61581 != 0
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "lvgl/lv_core/lv_vdb.h"
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define R61581_CMD_MODE 0
|
||||||
|
#define R61581_DATA_MODE 1
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void r61581_io_init(void);
|
||||||
|
static void r61581_reset(void);
|
||||||
|
static void r61581_set_tft_spec(void);
|
||||||
|
static inline void r61581_cmd_mode(void);
|
||||||
|
static inline void r61581_data_mode(void);
|
||||||
|
static inline void r61581_cmd(uint8_t cmd);
|
||||||
|
static inline void r61581_data(uint8_t data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static bool cmd_mode = true;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the R61581 display controller
|
||||||
|
* @return HW_RES_OK or any error from hw_res_t enum
|
||||||
|
*/
|
||||||
|
void r61581_init(void)
|
||||||
|
{
|
||||||
|
r61581_io_init();
|
||||||
|
|
||||||
|
/*Slow mode until the PLL is not started in the display controller*/
|
||||||
|
LV_DRV_DISP_PAR_SLOW;
|
||||||
|
|
||||||
|
r61581_reset();
|
||||||
|
|
||||||
|
r61581_set_tft_spec();
|
||||||
|
|
||||||
|
r61581_cmd(0x13); //SET display on
|
||||||
|
|
||||||
|
r61581_cmd(0x29); //SET display on
|
||||||
|
LV_DRV_DELAY_MS(30);
|
||||||
|
|
||||||
|
/*Parallel to max speed*/
|
||||||
|
LV_DRV_DISP_PAR_FAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(x2 < 0) return;
|
||||||
|
if(y2 < 0) return;
|
||||||
|
if(x1 > R61581_HOR_RES - 1) return;
|
||||||
|
if(y1 > R61581_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = x1 < 0 ? 0 : x1;
|
||||||
|
int32_t act_y1 = y1 < 0 ? 0 : y1;
|
||||||
|
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
|
||||||
|
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
|
||||||
|
|
||||||
|
|
||||||
|
//Set the rectangular area
|
||||||
|
r61581_cmd(0x002A);
|
||||||
|
r61581_data(act_x1 >> 8);
|
||||||
|
r61581_data(0x00FF & act_x1);
|
||||||
|
r61581_data(act_x2 >> 8);
|
||||||
|
r61581_data(0x00FF & act_x2);
|
||||||
|
|
||||||
|
r61581_cmd(0x002B);
|
||||||
|
r61581_data(act_y1 >> 8);
|
||||||
|
r61581_data(0x00FF & act_y1);
|
||||||
|
r61581_data(act_y2 >> 8);
|
||||||
|
r61581_data(0x00FF & act_y2);
|
||||||
|
|
||||||
|
r61581_cmd(0x2c);
|
||||||
|
|
||||||
|
int16_t i;
|
||||||
|
uint16_t full_w = x2 - x1 + 1;
|
||||||
|
|
||||||
|
r61581_data_mode();
|
||||||
|
|
||||||
|
#if LV_COLOR_DEPTH == 16
|
||||||
|
uint16_t act_w = act_x2 - act_x1 + 1;
|
||||||
|
for(i = act_y1; i <= act_y2; i++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
|
||||||
|
color_p += full_w;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int16_t j;
|
||||||
|
for(i = act_y1; i <= act_y2; i++) {
|
||||||
|
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j]));
|
||||||
|
color_p += full_w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lv_flush_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)
|
||||||
|
{
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(x2 < 0) return;
|
||||||
|
if(y2 < 0) return;
|
||||||
|
if(x1 > R61581_HOR_RES - 1) return;
|
||||||
|
if(y1 > R61581_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = x1 < 0 ? 0 : x1;
|
||||||
|
int32_t act_y1 = y1 < 0 ? 0 : y1;
|
||||||
|
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
|
||||||
|
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
|
||||||
|
|
||||||
|
//Set the rectangular area
|
||||||
|
r61581_cmd(0x002A);
|
||||||
|
r61581_data(act_x1 >> 8);
|
||||||
|
r61581_data(0x00FF & act_x1);
|
||||||
|
r61581_data(act_x2 >> 8);
|
||||||
|
r61581_data(0x00FF & act_x2);
|
||||||
|
|
||||||
|
r61581_cmd(0x002B);
|
||||||
|
r61581_data(act_y1 >> 8);
|
||||||
|
r61581_data(0x00FF & act_y1);
|
||||||
|
r61581_data(act_y2 >> 8);
|
||||||
|
r61581_data(0x00FF & act_y2);
|
||||||
|
|
||||||
|
r61581_cmd(0x2c);
|
||||||
|
|
||||||
|
r61581_data_mode();
|
||||||
|
|
||||||
|
uint16_t color16 = lv_color_to16(color);
|
||||||
|
uint32_t size = (act_x2 - act_x1 + 1) * (act_y2 - act_y1 + 1);
|
||||||
|
uint32_t i;
|
||||||
|
for(i = 0; i < size; i++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(color16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(x2 < 0) return;
|
||||||
|
if(y2 < 0) return;
|
||||||
|
if(x1 > R61581_HOR_RES - 1) return;
|
||||||
|
if(y1 > R61581_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = x1 < 0 ? 0 : x1;
|
||||||
|
int32_t act_y1 = y1 < 0 ? 0 : y1;
|
||||||
|
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
|
||||||
|
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
|
||||||
|
|
||||||
|
|
||||||
|
//Set the rectangular area
|
||||||
|
r61581_cmd(0x002A);
|
||||||
|
r61581_data(act_x1 >> 8);
|
||||||
|
r61581_data(0x00FF & act_x1);
|
||||||
|
r61581_data(act_x2 >> 8);
|
||||||
|
r61581_data(0x00FF & act_x2);
|
||||||
|
|
||||||
|
r61581_cmd(0x002B);
|
||||||
|
r61581_data(act_y1 >> 8);
|
||||||
|
r61581_data(0x00FF & act_y1);
|
||||||
|
r61581_data(act_y2 >> 8);
|
||||||
|
r61581_data(0x00FF & act_y2);
|
||||||
|
|
||||||
|
r61581_cmd(0x2c);
|
||||||
|
|
||||||
|
int16_t i;
|
||||||
|
uint16_t full_w = x2 - x1 + 1;
|
||||||
|
|
||||||
|
r61581_data_mode();
|
||||||
|
|
||||||
|
#if LV_COLOR_DEPTH == 16
|
||||||
|
uint16_t act_w = act_x2 - act_x1 + 1;
|
||||||
|
for(i = act_y1; i <= act_y2; i++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
|
||||||
|
color_p += full_w;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int16_t j;
|
||||||
|
for(i = act_y1; i <= act_y2; i++) {
|
||||||
|
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j]));
|
||||||
|
color_p += full_w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Io init
|
||||||
|
*/
|
||||||
|
static void r61581_io_init(void)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE)
|
||||||
|
cmd_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset
|
||||||
|
*/
|
||||||
|
static void r61581_reset(void)
|
||||||
|
{
|
||||||
|
/*Hardware reset*/
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
LV_DRV_DISP_RST(0);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
|
||||||
|
/*Chip enable*/
|
||||||
|
LV_DRV_DISP_PAR_CS(1);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
LV_DRV_DISP_PAR_CS(0);
|
||||||
|
LV_DRV_DELAY_MS(5);
|
||||||
|
|
||||||
|
/*Software reset*/
|
||||||
|
r61581_cmd(0x01);
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
|
||||||
|
r61581_cmd(0x01);
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
|
||||||
|
r61581_cmd(0x01);
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TFT specific initialization
|
||||||
|
*/
|
||||||
|
static void r61581_set_tft_spec(void)
|
||||||
|
{
|
||||||
|
r61581_cmd(0xB0);
|
||||||
|
r61581_data(0x00);
|
||||||
|
|
||||||
|
r61581_cmd(0xB3);
|
||||||
|
r61581_data(0x02);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x10);
|
||||||
|
|
||||||
|
r61581_cmd(0xB4);
|
||||||
|
r61581_data(0x00);//0X10
|
||||||
|
|
||||||
|
r61581_cmd(0xB9); //PWM
|
||||||
|
r61581_data(0x01);
|
||||||
|
r61581_data(0xFF); //FF brightness
|
||||||
|
r61581_data(0xFF);
|
||||||
|
r61581_data(0x18);
|
||||||
|
|
||||||
|
/*Panel Driving Setting*/
|
||||||
|
r61581_cmd(0xC0);
|
||||||
|
r61581_data(0x02);
|
||||||
|
r61581_data(0x3B);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x01);
|
||||||
|
r61581_data(0x00);//NW
|
||||||
|
r61581_data(0x43);
|
||||||
|
|
||||||
|
/*Display Timing Setting for Normal Mode */
|
||||||
|
r61581_cmd(0xC1);
|
||||||
|
r61581_data(0x08);
|
||||||
|
r61581_data(0x15); //CLOCK
|
||||||
|
r61581_data(R61581_VFP);
|
||||||
|
r61581_data(R61581_VBP);
|
||||||
|
|
||||||
|
/*Source/VCOM/Gate Driving Timing Setting*/
|
||||||
|
r61581_cmd(0xC4);
|
||||||
|
r61581_data(0x15);
|
||||||
|
r61581_data(0x03);
|
||||||
|
r61581_data(0x03);
|
||||||
|
r61581_data(0x01);
|
||||||
|
|
||||||
|
/*Interface Setting*/
|
||||||
|
r61581_cmd(0xC6);
|
||||||
|
r61581_data((R61581_DPL << 0) |
|
||||||
|
(R61581_EPL << 1) |
|
||||||
|
(R61581_HSPL << 4) |
|
||||||
|
(R61581_VSPL << 5));
|
||||||
|
|
||||||
|
/*Gamma Set*/
|
||||||
|
r61581_cmd(0xC8);
|
||||||
|
r61581_data(0x0c);
|
||||||
|
r61581_data(0x05);
|
||||||
|
r61581_data(0x0A);
|
||||||
|
r61581_data(0x6B);
|
||||||
|
r61581_data(0x04);
|
||||||
|
r61581_data(0x06);
|
||||||
|
r61581_data(0x15);
|
||||||
|
r61581_data(0x10);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x31);
|
||||||
|
|
||||||
|
|
||||||
|
r61581_cmd(0x36);
|
||||||
|
if(R61581_ORI == 0) r61581_data(0xE0);
|
||||||
|
else r61581_data(0x20);
|
||||||
|
|
||||||
|
r61581_cmd(0x0C);
|
||||||
|
r61581_data(0x55);
|
||||||
|
|
||||||
|
r61581_cmd(0x3A);
|
||||||
|
r61581_data(0x55);
|
||||||
|
|
||||||
|
r61581_cmd(0x38);
|
||||||
|
|
||||||
|
r61581_cmd(0xD0);
|
||||||
|
r61581_data(0x07);
|
||||||
|
r61581_data(0x07);
|
||||||
|
r61581_data(0x14);
|
||||||
|
r61581_data(0xA2);
|
||||||
|
|
||||||
|
r61581_cmd(0xD1);
|
||||||
|
r61581_data(0x03);
|
||||||
|
r61581_data(0x5A);
|
||||||
|
r61581_data(0x10);
|
||||||
|
|
||||||
|
r61581_cmd(0xD2);
|
||||||
|
r61581_data(0x03);
|
||||||
|
r61581_data(0x04);
|
||||||
|
r61581_data(0x04);
|
||||||
|
|
||||||
|
r61581_cmd(0x11);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
|
||||||
|
r61581_cmd(0x2A);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(((R61581_HOR_RES - 1) >> 8) & 0XFF);
|
||||||
|
r61581_data((R61581_HOR_RES - 1) & 0XFF);
|
||||||
|
|
||||||
|
r61581_cmd(0x2B);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(0x00);
|
||||||
|
r61581_data(((R61581_VER_RES - 1) >> 8) & 0XFF);
|
||||||
|
r61581_data((R61581_VER_RES - 1) & 0XFF);
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
|
||||||
|
r61581_cmd(0x29);
|
||||||
|
LV_DRV_DELAY_MS(5);
|
||||||
|
|
||||||
|
r61581_cmd(0x2C);
|
||||||
|
LV_DRV_DELAY_MS(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command mode
|
||||||
|
*/
|
||||||
|
static inline void r61581_cmd_mode(void)
|
||||||
|
{
|
||||||
|
if(cmd_mode == false) {
|
||||||
|
LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE)
|
||||||
|
cmd_mode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data mode
|
||||||
|
*/
|
||||||
|
static inline void r61581_data_mode(void)
|
||||||
|
{
|
||||||
|
if(cmd_mode != false) {
|
||||||
|
LV_DRV_DISP_CMD_DATA(R61581_DATA_MODE);
|
||||||
|
cmd_mode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write command
|
||||||
|
* @param cmd the command
|
||||||
|
*/
|
||||||
|
static inline void r61581_cmd(uint8_t cmd)
|
||||||
|
{
|
||||||
|
r61581_cmd_mode();
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data
|
||||||
|
* @param data the data
|
||||||
|
*/
|
||||||
|
static inline void r61581_data(uint8_t data)
|
||||||
|
{
|
||||||
|
r61581_data_mode();
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(data);
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* @file R61581.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef R61581_H
|
||||||
|
#define R61581_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_R61581
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void r61581_init(void);
|
||||||
|
void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
|
||||||
|
void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
|
||||||
|
void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_R61581 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* R61581_H */
|
@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* @file SHARP_MIP.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------------------------------
|
||||||
|
* SHARP memory in pixel monochrome display series
|
||||||
|
* LS012B7DD01 (184x38 pixels.)
|
||||||
|
* LS013B7DH03 (128x128 pixels.)
|
||||||
|
* LS013B7DH05 (144x168 pixels.)
|
||||||
|
* LS027B7DH01 (400x240 pixels.) (tested)
|
||||||
|
* LS032B7DD02 (336x536 pixels.)
|
||||||
|
* LS044Q7DH01 (320x240 pixels.)
|
||||||
|
*
|
||||||
|
* These displays need periodic com inversion, there are two ways :
|
||||||
|
* - software com inversion :
|
||||||
|
* define SHARP_MIP_SOFT_COM_INVERSION 1 and set EXTMODE display pin LOW,
|
||||||
|
* call sharp_mip_com_inversion() periodically
|
||||||
|
* - hardware com inversion with EXTCOMIN display pin :
|
||||||
|
* define SHARP_MIP_SOFT_COM_INVERSION 0,
|
||||||
|
* set EXTMODE display pin HIGH and handle
|
||||||
|
* EXTCOMIN waveform (for example with mcu pwm output),
|
||||||
|
* see datasheet pages 8-12 for details
|
||||||
|
*
|
||||||
|
* draw_buf size : (LV_VER_RES / X) * (2 + LV_HOR_RES / 8) + 2 bytes, structure :
|
||||||
|
* [FRAME_HEADER (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 1st line
|
||||||
|
* [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 2nd line
|
||||||
|
* ...........................................................................................
|
||||||
|
* [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] last line
|
||||||
|
* [DUMMY (2 bytes)]
|
||||||
|
*
|
||||||
|
* Since extra bytes (dummy, addresses, header) are stored in draw_buf, we need to use
|
||||||
|
* an "oversized" draw_buf. Buffer declaration in "lv_port_disp.c" becomes for example :
|
||||||
|
* static lv_disp_buf_t disp_buf;
|
||||||
|
* static uint8_t buf[(LV_VER_RES_MAX / X) * (2 + (LV_HOR_RES_MAX / 8)) + 2];
|
||||||
|
* lv_disp_buf_init(&disp_buf, buf, NULL, LV_VER_RES_MAX * LV_HOR_RES_MAX / X);
|
||||||
|
*-----------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#include "SHARP_MIP.h"
|
||||||
|
|
||||||
|
#if USE_SHARP_MIP
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#define SHARP_MIP_HEADER 0
|
||||||
|
#define SHARP_MIP_UPDATE_RAM_FLAG (1 << 7) /* (M0) Mode flag : H -> update memory, L -> maintain memory */
|
||||||
|
#define SHARP_MIP_COM_INVERSION_FLAG (1 << 6) /* (M1) Frame inversion flag : relevant when EXTMODE = L, */
|
||||||
|
/* H -> outputs VCOM = H, L -> outputs VCOM = L */
|
||||||
|
#define SHARP_MIP_CLEAR_SCREEN_FLAG (1 << 5) /* (M2) All clear flag : H -> clear all pixels */
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#if SHARP_MIP_SOFT_COM_INVERSION
|
||||||
|
static bool_t com_output_state = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the draw_buf byte index corresponding to the pixel
|
||||||
|
* relatives coordinates (x, y) in the area.
|
||||||
|
* The area is rounded to a whole screen line.
|
||||||
|
*/
|
||||||
|
#define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (SHARP_MIP_HOR_RES >> 3))) + 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the byte bitmask of a pixel bit corresponding
|
||||||
|
* to draw_buf arrangement (8 pixels per byte on lines).
|
||||||
|
*/
|
||||||
|
#define PIXIDX(x) SHARP_MIP_REV_BYTE(1 << ((x) & 7))
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void sharp_mip_init(void) {
|
||||||
|
/* These displays have nothing to initialize */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
|
||||||
|
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->y2 < 0) return;
|
||||||
|
if(area->y1 > SHARP_MIP_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
uint16_t act_y1 = area->y1 < 0 ? 0 : area->y1;
|
||||||
|
uint16_t act_y2 = area->y2 > SHARP_MIP_VER_RES - 1 ? SHARP_MIP_VER_RES - 1 : area->y2;
|
||||||
|
|
||||||
|
uint8_t * buf = (uint8_t *) color_p; /*Get the buffer address*/
|
||||||
|
uint16_t buf_h = (act_y2 - act_y1 + 1); /*Number of buffer lines*/
|
||||||
|
uint16_t buf_size = buf_h * (2 + SHARP_MIP_HOR_RES / 8) + 2; /*Buffer size in bytes */
|
||||||
|
|
||||||
|
/* Set lines to flush dummy byte & gate address in draw_buf*/
|
||||||
|
for(uint16_t act_y = 0 ; act_y < buf_h ; act_y++) {
|
||||||
|
buf[BUFIDX(0, act_y) - 1] = SHARP_MIP_REV_BYTE((act_y1 + act_y + 1));
|
||||||
|
buf[BUFIDX(0, act_y) - 2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set last dummy two bytes in draw_buf */
|
||||||
|
buf[BUFIDX(0, buf_h) - 1] = 0;
|
||||||
|
buf[BUFIDX(0, buf_h) - 2] = 0;
|
||||||
|
|
||||||
|
/* Set frame header in draw_buf */
|
||||||
|
buf[0] = SHARP_MIP_HEADER |
|
||||||
|
SHARP_MIP_UPDATE_RAM_FLAG;
|
||||||
|
|
||||||
|
/* Write the frame on display memory */
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size);
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
|
||||||
|
(void) disp_drv;
|
||||||
|
(void) buf_w;
|
||||||
|
(void) opa;
|
||||||
|
|
||||||
|
if (lv_color_to1(color) != 0) {
|
||||||
|
buf[BUFIDX(x, y)] |= PIXIDX(x); /*Set draw_buf pixel bit to 1 for other colors than BLACK*/
|
||||||
|
} else {
|
||||||
|
buf[BUFIDX(x, y)] &= ~PIXIDX(x); /*Set draw_buf pixel bit to 0 for BLACK color*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) {
|
||||||
|
(void) disp_drv;
|
||||||
|
|
||||||
|
/* Round area to a whole line */
|
||||||
|
area->x1 = 0;
|
||||||
|
area->x2 = SHARP_MIP_HOR_RES - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SHARP_MIP_SOFT_COM_INVERSION
|
||||||
|
void sharp_mip_com_inversion(void) {
|
||||||
|
uint8_t inversion_header[2] = {0};
|
||||||
|
|
||||||
|
/* Set inversion header */
|
||||||
|
if (com_output_state) {
|
||||||
|
com_output_state = false;
|
||||||
|
} else {
|
||||||
|
inversion_header[0] |= SHARP_MIP_COM_INVERSION_FLAG;
|
||||||
|
com_output_state = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write inversion header on display memory */
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(inversion_header, 2);
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* @file SHARP_MIP.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARP_MIP_H
|
||||||
|
#define SHARP_MIP_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SHARP_MIP
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void sharp_mip_init(void);
|
||||||
|
void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area);
|
||||||
|
void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
|
||||||
|
#if SHARP_MIP_SOFT_COM_INVERSION
|
||||||
|
void sharp_mip_com_inversion(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_SHARP_MIP */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SHARP_MIP_H */
|
@ -0,0 +1,292 @@
|
|||||||
|
/**
|
||||||
|
* @file SSD1963.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "SSD1963.h"
|
||||||
|
#if USE_SSD1963
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define SSD1963_CMD_MODE 0
|
||||||
|
#define SSD1963_DATA_MODE 1
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static inline void ssd1963_cmd_mode(void);
|
||||||
|
static inline void ssd1963_data_mode(void);
|
||||||
|
static inline void ssd1963_cmd(uint8_t cmd);
|
||||||
|
static inline void ssd1963_data(uint8_t data);
|
||||||
|
static void ssd1963_io_init(void);
|
||||||
|
static void ssd1963_reset(void);
|
||||||
|
static void ssd1963_set_clk(void);
|
||||||
|
static void ssd1963_set_tft_spec(void);
|
||||||
|
static void ssd1963_init_bl(void);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static bool cmd_mode = true;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void ssd1963_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
|
||||||
|
cmd_mode = true;
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(250);
|
||||||
|
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00E2); //PLL multiplier, set PLL clock to 120M
|
||||||
|
ssd1963_data(0x0023); //N=0x36 for 6.5M, 0x23 for 10M crystal
|
||||||
|
ssd1963_data(0x0002);
|
||||||
|
ssd1963_data(0x0004);
|
||||||
|
ssd1963_cmd(0x00E0); // PLL enable
|
||||||
|
ssd1963_data(0x0001);
|
||||||
|
LV_DRV_DELAY_MS(1);
|
||||||
|
ssd1963_cmd(0x00E0);
|
||||||
|
ssd1963_data(0x0003); // now, use PLL output as system clock
|
||||||
|
LV_DRV_DELAY_MS(1);
|
||||||
|
ssd1963_cmd(0x0001); // software reset
|
||||||
|
LV_DRV_DELAY_MS(1);
|
||||||
|
ssd1963_cmd(0x00E6); //PLL setting for PCLK, depends on resolution
|
||||||
|
|
||||||
|
ssd1963_data(0x0001); //HX8257C
|
||||||
|
ssd1963_data(0x0033); //HX8257C
|
||||||
|
ssd1963_data(0x0033); //HX8257C
|
||||||
|
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00B0); //LCD SPECIFICATION
|
||||||
|
ssd1963_data(0x0020);
|
||||||
|
ssd1963_data(0x0000);
|
||||||
|
ssd1963_data(((SSD1963_HOR_RES - 1) >> 8) & 0X00FF); //Set HDP
|
||||||
|
ssd1963_data((SSD1963_HOR_RES - 1) & 0X00FF);
|
||||||
|
ssd1963_data(((SSD1963_VER_RES - 1) >> 8) & 0X00FF); //Set VDP
|
||||||
|
ssd1963_data((SSD1963_VER_RES - 1) & 0X00FF);
|
||||||
|
ssd1963_data(0x0000);
|
||||||
|
LV_DRV_DELAY_MS(1);//Delay10us(5);
|
||||||
|
ssd1963_cmd(0x00B4); //HSYNC
|
||||||
|
ssd1963_data((SSD1963_HT >> 8) & 0X00FF); //Set HT
|
||||||
|
ssd1963_data(SSD1963_HT & 0X00FF);
|
||||||
|
ssd1963_data((SSD1963_HPS >> 8) & 0X00FF); //Set HPS
|
||||||
|
ssd1963_data(SSD1963_HPS & 0X00FF);
|
||||||
|
ssd1963_data(SSD1963_HPW); //Set HPW
|
||||||
|
ssd1963_data((SSD1963_LPS >> 8) & 0X00FF); //SetLPS
|
||||||
|
ssd1963_data(SSD1963_LPS & 0X00FF);
|
||||||
|
ssd1963_data(0x0000);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00B6); //VSYNC
|
||||||
|
ssd1963_data((SSD1963_VT >> 8) & 0X00FF); //Set VT
|
||||||
|
ssd1963_data(SSD1963_VT & 0X00FF);
|
||||||
|
ssd1963_data((SSD1963_VPS >> 8) & 0X00FF); //Set VPS
|
||||||
|
ssd1963_data(SSD1963_VPS & 0X00FF);
|
||||||
|
ssd1963_data(SSD1963_VPW); //Set VPW
|
||||||
|
ssd1963_data((SSD1963_FPS >> 8) & 0X00FF); //Set FPS
|
||||||
|
ssd1963_data(SSD1963_FPS & 0X00FF);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00B8);
|
||||||
|
ssd1963_data(0x000f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF
|
||||||
|
ssd1963_data(0x0001); //GPIO0 normal
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00BA);
|
||||||
|
ssd1963_data(0x0001); //GPIO[0] out 1 --- LCD display on/off control PIN
|
||||||
|
|
||||||
|
ssd1963_cmd(0x0036); //rotation
|
||||||
|
ssd1963_data(0x0008); //RGB=BGR
|
||||||
|
|
||||||
|
ssd1963_cmd(0x003A); //Set the current pixel format for RGB image data
|
||||||
|
ssd1963_data(0x0050); //16-bit/pixel
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00F0); //Pixel Data Interface Format
|
||||||
|
ssd1963_data(0x0003); //16-bit(565 format) data
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00BC);
|
||||||
|
ssd1963_data(0x0040); //contrast value
|
||||||
|
ssd1963_data(0x0080); //brightness value
|
||||||
|
ssd1963_data(0x0040); //saturation value
|
||||||
|
ssd1963_data(0x0001); //Post Processor Enable
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(1);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x0029); //display on
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00BE); //set PWM for B/L
|
||||||
|
ssd1963_data(0x0006);
|
||||||
|
ssd1963_data(0x0080);
|
||||||
|
ssd1963_data(0x0001);
|
||||||
|
ssd1963_data(0x00f0);
|
||||||
|
ssd1963_data(0x0000);
|
||||||
|
ssd1963_data(0x0000);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x00d0);
|
||||||
|
ssd1963_data(0x000d);
|
||||||
|
|
||||||
|
//DisplayBacklightOn();
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->x2 < 0) return;
|
||||||
|
if(area->y2 < 0) return;
|
||||||
|
if(area->x1 > SSD1963_HOR_RES - 1) return;
|
||||||
|
if(area->y1 > SSD1963_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
|
||||||
|
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
|
||||||
|
int32_t act_x2 = area->x2 > SSD1963_HOR_RES - 1 ? SSD1963_HOR_RES - 1 : area->x2;
|
||||||
|
int32_t act_y2 = area->y2 > SSD1963_VER_RES - 1 ? SSD1963_VER_RES - 1 : area->y2;
|
||||||
|
|
||||||
|
//Set the rectangular area
|
||||||
|
ssd1963_cmd(0x002A);
|
||||||
|
ssd1963_data(act_x1 >> 8);
|
||||||
|
ssd1963_data(0x00FF & act_x1);
|
||||||
|
ssd1963_data(act_x2 >> 8);
|
||||||
|
ssd1963_data(0x00FF & act_x2);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x002B);
|
||||||
|
ssd1963_data(act_y1 >> 8);
|
||||||
|
ssd1963_data(0x00FF & act_y1);
|
||||||
|
ssd1963_data(act_y2 >> 8);
|
||||||
|
ssd1963_data(0x00FF & act_y2);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x2c);
|
||||||
|
int16_t i;
|
||||||
|
uint16_t full_w = area->x2 - area->x1 + 1;
|
||||||
|
|
||||||
|
ssd1963_data_mode();
|
||||||
|
LV_DRV_DISP_PAR_CS(0);
|
||||||
|
#if LV_COLOR_DEPTH == 16
|
||||||
|
uint16_t act_w = act_x2 - act_x1 + 1;
|
||||||
|
for(i = act_y1; i <= act_y2; i++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
|
||||||
|
color_p += full_w;
|
||||||
|
}
|
||||||
|
LV_DRV_DISP_PAR_CS(1);
|
||||||
|
#else
|
||||||
|
int16_t j;
|
||||||
|
for(i = act_y1; i <= act_y2; i++) {
|
||||||
|
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(color_p[j]);
|
||||||
|
color_p += full_w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void ssd1963_io_init(void)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
|
||||||
|
cmd_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ssd1963_reset(void)
|
||||||
|
{
|
||||||
|
/*Hardware reset*/
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
LV_DRV_DISP_RST(0);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
|
||||||
|
/*Chip enable*/
|
||||||
|
LV_DRV_DISP_PAR_CS(0);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
LV_DRV_DISP_PAR_CS(1);
|
||||||
|
LV_DRV_DELAY_MS(5);
|
||||||
|
|
||||||
|
/*Software reset*/
|
||||||
|
ssd1963_cmd(0x01);
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x01);
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
|
||||||
|
ssd1963_cmd(0x01);
|
||||||
|
LV_DRV_DELAY_MS(20);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command mode
|
||||||
|
*/
|
||||||
|
static inline void ssd1963_cmd_mode(void)
|
||||||
|
{
|
||||||
|
if(cmd_mode == false) {
|
||||||
|
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
|
||||||
|
cmd_mode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data mode
|
||||||
|
*/
|
||||||
|
static inline void ssd1963_data_mode(void)
|
||||||
|
{
|
||||||
|
if(cmd_mode != false) {
|
||||||
|
LV_DRV_DISP_CMD_DATA(SSD1963_DATA_MODE);
|
||||||
|
cmd_mode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write command
|
||||||
|
* @param cmd the command
|
||||||
|
*/
|
||||||
|
static inline void ssd1963_cmd(uint8_t cmd)
|
||||||
|
{
|
||||||
|
|
||||||
|
LV_DRV_DISP_PAR_CS(0);
|
||||||
|
ssd1963_cmd_mode();
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(cmd);
|
||||||
|
LV_DRV_DISP_PAR_CS(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data
|
||||||
|
* @param data the data
|
||||||
|
*/
|
||||||
|
static inline void ssd1963_data(uint8_t data)
|
||||||
|
{
|
||||||
|
|
||||||
|
LV_DRV_DISP_PAR_CS(0);
|
||||||
|
ssd1963_data_mode();
|
||||||
|
LV_DRV_DISP_PAR_WR_WORD(data);
|
||||||
|
LV_DRV_DISP_PAR_CS(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* @file SSD1963.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SSD1963_H
|
||||||
|
#define SSD1963_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SSD1963
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
// SSD1963 command table
|
||||||
|
#define CMD_NOP 0x00 //No operation
|
||||||
|
#define CMD_SOFT_RESET 0x01 //Software reset
|
||||||
|
#define CMD_GET_PWR_MODE 0x0A //Get the current power mode
|
||||||
|
#define CMD_GET_ADDR_MODE 0x0B //Get the frame memory to the display panel read order
|
||||||
|
#define CMD_GET_PIXEL_FORMAT 0x0C //Get the current pixel format
|
||||||
|
#define CMD_GET_DISPLAY_MODE 0x0D //Returns the display mode
|
||||||
|
#define CMD_GET_SIGNAL_MODE 0x0E //
|
||||||
|
#define CMD_GET_DIAGNOSTIC 0x0F
|
||||||
|
#define CMD_ENT_SLEEP 0x10
|
||||||
|
#define CMD_EXIT_SLEEP 0x11
|
||||||
|
#define CMD_ENT_PARTIAL_MODE 0x12
|
||||||
|
#define CMD_ENT_NORMAL_MODE 0x13
|
||||||
|
#define CMD_EXIT_INVERT_MODE 0x20
|
||||||
|
#define CMD_ENT_INVERT_MODE 0x21
|
||||||
|
#define CMD_SET_GAMMA 0x26
|
||||||
|
#define CMD_BLANK_DISPLAY 0x28
|
||||||
|
#define CMD_ON_DISPLAY 0x29
|
||||||
|
#define CMD_SET_COLUMN 0x2A
|
||||||
|
#define CMD_SET_PAGE 0x2B
|
||||||
|
#define CMD_WR_MEMSTART 0x2C
|
||||||
|
#define CMD_RD_MEMSTART 0x2E
|
||||||
|
#define CMD_SET_PARTIAL_AREA 0x30
|
||||||
|
#define CMD_SET_SCROLL_AREA 0x33
|
||||||
|
#define CMD_SET_TEAR_OFF 0x34 //synchronization information is not sent from the display
|
||||||
|
#define CMD_SET_TEAR_ON 0x35 //sync. information is sent from the display
|
||||||
|
#define CMD_SET_ADDR_MODE 0x36 //set fram buffer read order to the display panel
|
||||||
|
#define CMD_SET_SCROLL_START 0x37
|
||||||
|
#define CMD_EXIT_IDLE_MODE 0x38
|
||||||
|
#define CMD_ENT_IDLE_MODE 0x39
|
||||||
|
#define CMD_SET_PIXEL_FORMAT 0x3A //defines how many bits per pixel is used
|
||||||
|
#define CMD_WR_MEM_AUTO 0x3C
|
||||||
|
#define CMD_RD_MEM_AUTO 0x3E
|
||||||
|
#define CMD_SET_TEAR_SCANLINE 0x44
|
||||||
|
#define CMD_GET_SCANLINE 0x45
|
||||||
|
#define CMD_RD_DDB_START 0xA1
|
||||||
|
#define CMD_RD_DDB_AUTO 0xA8
|
||||||
|
#define CMD_SET_PANEL_MODE 0xB0
|
||||||
|
#define CMD_GET_PANEL_MODE 0xB1
|
||||||
|
#define CMD_SET_HOR_PERIOD 0xB4
|
||||||
|
#define CMD_GET_HOR_PERIOD 0xB5
|
||||||
|
#define CMD_SET_VER_PERIOD 0xB6
|
||||||
|
#define CMD_GET_VER_PERIOD 0xB7
|
||||||
|
#define CMD_SET_GPIO_CONF 0xB8
|
||||||
|
#define CMD_GET_GPIO_CONF 0xB9
|
||||||
|
#define CMD_SET_GPIO_VAL 0xBA
|
||||||
|
#define CMD_GET_GPIO_STATUS 0xBB
|
||||||
|
#define CMD_SET_POST_PROC 0xBC
|
||||||
|
#define CMD_GET_POST_PROC 0xBD
|
||||||
|
#define CMD_SET_PWM_CONF 0xBE
|
||||||
|
#define CMD_GET_PWM_CONF 0xBF
|
||||||
|
#define CMD_SET_LCD_GEN0 0xC0
|
||||||
|
#define CMD_GET_LCD_GEN0 0xC1
|
||||||
|
#define CMD_SET_LCD_GEN1 0xC2
|
||||||
|
#define CMD_GET_LCD_GEN1 0xC3
|
||||||
|
#define CMD_SET_LCD_GEN2 0xC4
|
||||||
|
#define CMD_GET_LCD_GEN2 0xC5
|
||||||
|
#define CMD_SET_LCD_GEN3 0xC6
|
||||||
|
#define CMD_GET_LCD_GEN3 0xC7
|
||||||
|
#define CMD_SET_GPIO0_ROP 0xC8
|
||||||
|
#define CMD_GET_GPIO0_ROP 0xC9
|
||||||
|
#define CMD_SET_GPIO1_ROP 0xCA
|
||||||
|
#define CMD_GET_GPIO1_ROP 0xCB
|
||||||
|
#define CMD_SET_GPIO2_ROP 0xCC
|
||||||
|
#define CMD_GET_GPIO2_ROP 0xCD
|
||||||
|
#define CMD_SET_GPIO3_ROP 0xCE
|
||||||
|
#define CMD_GET_GPIO3_ROP 0xCF
|
||||||
|
#define CMD_SET_ABC_DBC_CONF 0xD0
|
||||||
|
#define CMD_GET_ABC_DBC_CONF 0xD1
|
||||||
|
#define CMD_SET_DBC_HISTO_PTR 0xD2
|
||||||
|
#define CMD_GET_DBC_HISTO_PTR 0xD3
|
||||||
|
#define CMD_SET_DBC_THRES 0xD4
|
||||||
|
#define CMD_GET_DBC_THRES 0xD5
|
||||||
|
#define CMD_SET_ABM_TMR 0xD6
|
||||||
|
#define CMD_GET_ABM_TMR 0xD7
|
||||||
|
#define CMD_SET_AMB_LVL0 0xD8
|
||||||
|
#define CMD_GET_AMB_LVL0 0xD9
|
||||||
|
#define CMD_SET_AMB_LVL1 0xDA
|
||||||
|
#define CMD_GET_AMB_LVL1 0xDB
|
||||||
|
#define CMD_SET_AMB_LVL2 0xDC
|
||||||
|
#define CMD_GET_AMB_LVL2 0xDD
|
||||||
|
#define CMD_SET_AMB_LVL3 0xDE
|
||||||
|
#define CMD_GET_AMB_LVL3 0xDF
|
||||||
|
#define CMD_PLL_START 0xE0 //start the PLL
|
||||||
|
#define CMD_PLL_STOP 0xE1 //disable the PLL
|
||||||
|
#define CMD_SET_PLL_MN 0xE2
|
||||||
|
#define CMD_GET_PLL_MN 0xE3
|
||||||
|
#define CMD_GET_PLL_STATUS 0xE4 //get the current PLL status
|
||||||
|
#define CMD_ENT_DEEP_SLEEP 0xE5
|
||||||
|
#define CMD_SET_PCLK 0xE6 //set pixel clock (LSHIFT signal) frequency
|
||||||
|
#define CMD_GET_PCLK 0xE7 //get pixel clock (LSHIFT signal) freq. settings
|
||||||
|
#define CMD_SET_DATA_INTERFACE 0xF0
|
||||||
|
#define CMD_GET_DATA_INTERFACE 0xF1
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void ssd1963_init(void);
|
||||||
|
void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_SSD1963 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SSD1963_H */
|
@ -0,0 +1,289 @@
|
|||||||
|
/**
|
||||||
|
* @file ST7565.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "ST7565.h"
|
||||||
|
#if USE_ST7565
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "lvgl/lv_core/lv_vdb.h"
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define ST7565_BAUD 2000000 /*< 2,5 MHz (400 ns)*/
|
||||||
|
|
||||||
|
#define ST7565_CMD_MODE 0
|
||||||
|
#define ST7565_DATA_MODE 1
|
||||||
|
|
||||||
|
#define ST7565_HOR_RES 128
|
||||||
|
#define ST7565_VER_RES 64
|
||||||
|
|
||||||
|
#define CMD_DISPLAY_OFF 0xAE
|
||||||
|
#define CMD_DISPLAY_ON 0xAF
|
||||||
|
|
||||||
|
#define CMD_SET_DISP_START_LINE 0x40
|
||||||
|
#define CMD_SET_PAGE 0xB0
|
||||||
|
|
||||||
|
#define CMD_SET_COLUMN_UPPER 0x10
|
||||||
|
#define CMD_SET_COLUMN_LOWER 0x00
|
||||||
|
|
||||||
|
#define CMD_SET_ADC_NORMAL 0xA0
|
||||||
|
#define CMD_SET_ADC_REVERSE 0xA1
|
||||||
|
|
||||||
|
#define CMD_SET_DISP_NORMAL 0xA6
|
||||||
|
#define CMD_SET_DISP_REVERSE 0xA7
|
||||||
|
|
||||||
|
#define CMD_SET_ALLPTS_NORMAL 0xA4
|
||||||
|
#define CMD_SET_ALLPTS_ON 0xA5
|
||||||
|
#define CMD_SET_BIAS_9 0xA2
|
||||||
|
#define CMD_SET_BIAS_7 0xA3
|
||||||
|
|
||||||
|
#define CMD_RMW 0xE0
|
||||||
|
#define CMD_RMW_CLEAR 0xEE
|
||||||
|
#define CMD_INTERNAL_RESET 0xE2
|
||||||
|
#define CMD_SET_COM_NORMAL 0xC0
|
||||||
|
#define CMD_SET_COM_REVERSE 0xC8
|
||||||
|
#define CMD_SET_POWER_CONTROL 0x28
|
||||||
|
#define CMD_SET_RESISTOR_RATIO 0x20
|
||||||
|
#define CMD_SET_VOLUME_FIRST 0x81
|
||||||
|
#define CMD_SET_VOLUME_SECOND 0x00
|
||||||
|
#define CMD_SET_STATIC_OFF 0xAC
|
||||||
|
#define CMD_SET_STATIC_ON 0xAD
|
||||||
|
#define CMD_SET_STATIC_REG 0x00
|
||||||
|
#define CMD_SET_BOOSTER_FIRST 0xF8
|
||||||
|
#define CMD_SET_BOOSTER_234 0x00
|
||||||
|
#define CMD_SET_BOOSTER_5 0x01
|
||||||
|
#define CMD_SET_BOOSTER_6 0x03
|
||||||
|
#define CMD_NOP 0xE3
|
||||||
|
#define CMD_TEST 0xF0
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2);
|
||||||
|
static void st7565_command(uint8_t cmd);
|
||||||
|
static void st7565_data(uint8_t data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static uint8_t lcd_fb[ST7565_HOR_RES * ST7565_VER_RES / 8] = {0xAA, 0xAA};
|
||||||
|
static uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the ST7565
|
||||||
|
*/
|
||||||
|
void st7565_init(void)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
LV_DRV_DISP_RST(0);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
LV_DRV_DISP_RST(1);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
|
||||||
|
st7565_command(CMD_SET_BIAS_7);
|
||||||
|
st7565_command(CMD_SET_ADC_NORMAL);
|
||||||
|
st7565_command(CMD_SET_COM_NORMAL);
|
||||||
|
st7565_command(CMD_SET_DISP_START_LINE);
|
||||||
|
st7565_command(CMD_SET_POWER_CONTROL | 0x4);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
|
||||||
|
st7565_command(CMD_SET_POWER_CONTROL | 0x6);
|
||||||
|
LV_DRV_DELAY_MS(50);
|
||||||
|
|
||||||
|
st7565_command(CMD_SET_POWER_CONTROL | 0x7);
|
||||||
|
LV_DRV_DELAY_MS(10);
|
||||||
|
|
||||||
|
st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); // Defaulted to 0x26 (but could also be between 0x20-0x27 based on display's specs)
|
||||||
|
|
||||||
|
st7565_command(CMD_DISPLAY_ON);
|
||||||
|
st7565_command(CMD_SET_ALLPTS_NORMAL);
|
||||||
|
|
||||||
|
/*Set brightness*/
|
||||||
|
st7565_command(CMD_SET_VOLUME_FIRST);
|
||||||
|
st7565_command(CMD_SET_VOLUME_SECOND | (0x18 & 0x3f));
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
|
||||||
|
memset(lcd_fb, 0x00, sizeof(lcd_fb));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(x2 < 0) return;
|
||||||
|
if(y2 < 0) return;
|
||||||
|
if(x1 > ST7565_HOR_RES - 1) return;
|
||||||
|
if(y1 > ST7565_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = x1 < 0 ? 0 : x1;
|
||||||
|
int32_t act_y1 = y1 < 0 ? 0 : y1;
|
||||||
|
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
|
||||||
|
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
|
||||||
|
|
||||||
|
int32_t x, y;
|
||||||
|
|
||||||
|
/*Set the first row in */
|
||||||
|
|
||||||
|
/*Refresh frame buffer*/
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
for(x = act_x1; x <= act_x2; x++) {
|
||||||
|
if(lv_color_to1(*color_p) != 0) {
|
||||||
|
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
|
||||||
|
} else {
|
||||||
|
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
|
||||||
|
}
|
||||||
|
color_p ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_p += x2 - act_x2; /*Next row*/
|
||||||
|
}
|
||||||
|
|
||||||
|
st7565_sync(act_x1, act_y1, act_x2, act_y2);
|
||||||
|
lv_flush_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)
|
||||||
|
{
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(x2 < 0) return;
|
||||||
|
if(y2 < 0) return;
|
||||||
|
if(x1 > ST7565_HOR_RES - 1) return;
|
||||||
|
if(y1 > ST7565_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = x1 < 0 ? 0 : x1;
|
||||||
|
int32_t act_y1 = y1 < 0 ? 0 : y1;
|
||||||
|
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
|
||||||
|
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
|
||||||
|
|
||||||
|
int32_t x, y;
|
||||||
|
uint8_t white = lv_color_to1(color);
|
||||||
|
|
||||||
|
/*Refresh frame buffer*/
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
for(x = act_x1; x <= act_x2; x++) {
|
||||||
|
if(white != 0) {
|
||||||
|
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
|
||||||
|
} else {
|
||||||
|
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st7565_sync(act_x1, act_y1, act_x2, act_y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(x2 < 0) return;
|
||||||
|
if(y2 < 0) return;
|
||||||
|
if(x1 > ST7565_HOR_RES - 1) return;
|
||||||
|
if(y1 > ST7565_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = x1 < 0 ? 0 : x1;
|
||||||
|
int32_t act_y1 = y1 < 0 ? 0 : y1;
|
||||||
|
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
|
||||||
|
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
|
||||||
|
|
||||||
|
int32_t x, y;
|
||||||
|
|
||||||
|
/*Set the first row in */
|
||||||
|
|
||||||
|
/*Refresh frame buffer*/
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
for(x = act_x1; x <= act_x2; x++) {
|
||||||
|
if(lv_color_to1(*color_p) != 0) {
|
||||||
|
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
|
||||||
|
} else {
|
||||||
|
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
|
||||||
|
}
|
||||||
|
color_p ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_p += x2 - act_x2; /*Next row*/
|
||||||
|
}
|
||||||
|
|
||||||
|
st7565_sync(act_x1, act_y1, act_x2, act_y2);
|
||||||
|
}
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
/**
|
||||||
|
* Flush a specific part of the buffer to the display
|
||||||
|
* @param x1 left coordinate of the area to flush
|
||||||
|
* @param y1 top coordinate of the area to flush
|
||||||
|
* @param x2 right coordinate of the area to flush
|
||||||
|
* @param y2 bottom coordinate of the area to flush
|
||||||
|
*/
|
||||||
|
static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
|
||||||
|
{
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
|
||||||
|
uint8_t c, p;
|
||||||
|
for(p = y1 / 8; p <= y2 / 8; p++) {
|
||||||
|
st7565_command(CMD_SET_PAGE | pagemap[p]);
|
||||||
|
st7565_command(CMD_SET_COLUMN_LOWER | (x1 & 0xf));
|
||||||
|
st7565_command(CMD_SET_COLUMN_UPPER | ((x1 >> 4) & 0xf));
|
||||||
|
st7565_command(CMD_RMW);
|
||||||
|
|
||||||
|
for(c = x1; c <= x2; c++) {
|
||||||
|
st7565_data(lcd_fb[(ST7565_HOR_RES * p) + c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a command to the ST7565
|
||||||
|
* @param cmd the command
|
||||||
|
*/
|
||||||
|
static void st7565_command(uint8_t cmd)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(ST7565_CMD_MODE);
|
||||||
|
LV_DRV_DISP_SPI_WR_BYTE(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data to the ST7565
|
||||||
|
* @param data the data
|
||||||
|
*/
|
||||||
|
static void st7565_data(uint8_t data)
|
||||||
|
{
|
||||||
|
LV_DRV_DISP_CMD_DATA(ST7565_DATA_MODE);
|
||||||
|
LV_DRV_DISP_SPI_WR_BYTE(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @file ST7565.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ST7565_H
|
||||||
|
#define ST7565_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_ST7565
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void st7565_init(void);
|
||||||
|
void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
|
||||||
|
void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
|
||||||
|
void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_ST7565 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ST7565_H */
|
@ -0,0 +1,206 @@
|
|||||||
|
/**
|
||||||
|
* @file UC1610.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "UC1610.h"
|
||||||
|
|
||||||
|
#if USE_UC1610
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include LV_DRV_DISP_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define UC1610_CMD_MODE 0
|
||||||
|
#define UC1610_DATA_MODE 1
|
||||||
|
#define UC1610_RESET_MODE 0
|
||||||
|
#define UC1610_SET_MODE 1
|
||||||
|
|
||||||
|
/* hardware control commands */
|
||||||
|
#define UC1610_SYSTEM_RESET 0xE2 /* software reset */
|
||||||
|
#define UC1610_NOP 0xE3
|
||||||
|
#define UC1610_SET_TEMP_COMP 0x24 /* set temperature compensation, default -0.05%/°C */
|
||||||
|
#define UC1610_SET_PANEL_LOADING 0x29 /* set panel loading, default 16~21 nF */
|
||||||
|
#define UC1610_SET_PUMP_CONTROL 0x2F /* default internal Vlcd (8x pump) */
|
||||||
|
#define UC1610_SET_LCD_BIAS_RATIO 0xEB /* default 11 */
|
||||||
|
#define UC1610_SET_VBIAS_POT 0x81 /* 1 byte (0~255) to follow setting the contrast, default 0x81 */
|
||||||
|
#define UC1610_SET_LINE_RATE 0xA0 /* default 12,1 Klps */
|
||||||
|
#define UC1610_SET_DISPLAY_ENABLE 0xAE /* + 1 / 0 : exit sleep mode / entering sleep mode */
|
||||||
|
#define UC1610_SET_LCD_GRAY_SHADE 0xD0 /* default 24% between the two gray shade levels */
|
||||||
|
#define UC1610_SET_COM_END 0xF1 /* set the number of used com electrodes (lines number -1) */
|
||||||
|
|
||||||
|
/* ram address control */
|
||||||
|
#define UC1610_SET_AC 0x88 /* set ram address control */
|
||||||
|
#define UC1610_AC_WA_FLAG 1 /* automatic column/page increment wrap around (1 : cycle increment) */
|
||||||
|
#define UC1610_AC_AIO_FLAG (1 << 1) /* auto increment order (0/1 : column/page increment first) */
|
||||||
|
#define UC1610_AC_PID_FLAG (1 << 2) /* page address auto increment order (0/1 : +1/-1) */
|
||||||
|
|
||||||
|
/* set cursor ram address */
|
||||||
|
#define UC1610_SET_CA_LSB 0x00 /* + 4 LSB bits */
|
||||||
|
#define UC1610_SET_CA_MSB 0x10 /* + 4 MSB bits // MSB + LSB values range : 0~159 */
|
||||||
|
#define UC1610_SET_PA 0x60 /* + 5 bits // values range : 0~26 */
|
||||||
|
|
||||||
|
/* display control commands */
|
||||||
|
#define UC1610_SET_FIXED_LINES 0x90 /* + 4 bits = 2xFL */
|
||||||
|
#define UC1610_SET_SCROLL_LINES_LSB 0x40 /* + 4 LSB bits scroll up display by N (7 bits) lines */
|
||||||
|
#define UC1610_SET_SCROLL_LINES_MSB 0x50 /* + 3 MSB bits */
|
||||||
|
#define UC1610_SET_ALL_PIXEL_ON 0xA4 /* + 1 / 0 : set all pixel on, reverse */
|
||||||
|
#define UC1610_SET_INVERSE_DISPLAY 0xA6 /* + 1 / 0 : inverse all data stored in ram, reverse */
|
||||||
|
#define UC1610_SET_MAPPING_CONTROL 0xC0 /* control mirroring */
|
||||||
|
#define UC1610_SET_MAPPING_CONTROL_LC_FLAG 1
|
||||||
|
#define UC1610_SET_MAPPING_CONTROL_MX_FLAG (1 << 1)
|
||||||
|
#define UC1610_SET_MAPPING_CONTROL_MY_FLAG (1 << 2)
|
||||||
|
|
||||||
|
/* window program mode */
|
||||||
|
#define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 /* + 1 / 0 : enable / disable window programming mode, */
|
||||||
|
/* reset before changing boundaries */
|
||||||
|
#define UC1610_SET_WP_STARTING_CA 0xF4 /* 1 byte to follow for column address */
|
||||||
|
#define UC1610_SET_WP_ENDING_CA 0xF6 /* 1 byte to follow for column address */
|
||||||
|
#define UC1610_SET_WP_STARTING_PA 0xF5 /* 1 byte to follow for page address */
|
||||||
|
#define UC1610_SET_WP_ENDING_PA 0xF7 /* 1 byte to follow for page address */
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static uint8_t cmd_buf[12];
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/* Return the byte bitmask of a pixel color corresponding to draw_buf arrangement */
|
||||||
|
#define PIXIDX(y, c) ((c) << (((y) & 3) << 1))
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void uc1610_init(void) {
|
||||||
|
LV_DRV_DELAY_MS(12);
|
||||||
|
|
||||||
|
/* initialization sequence */
|
||||||
|
#if UC1610_INIT_HARD_RST
|
||||||
|
LV_DRV_DISP_RST(UC1610_RESET_MODE); /* hardware reset */
|
||||||
|
LV_DRV_DELAY_MS(1);
|
||||||
|
LV_DRV_DISP_RST(UC1610_SET_MODE);
|
||||||
|
#else
|
||||||
|
cmd_buf[0] = UC1610_SYSTEM_RESET; /* software reset */
|
||||||
|
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 1);
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LV_DRV_DELAY_MS(2);
|
||||||
|
cmd_buf[0] = UC1610_SET_COM_END; /* set com end value */
|
||||||
|
cmd_buf[1] = UC1610_VER_RES - 1;
|
||||||
|
cmd_buf[2] = UC1610_SET_PANEL_LOADING;
|
||||||
|
cmd_buf[3] = UC1610_SET_LCD_BIAS_RATIO;
|
||||||
|
cmd_buf[4] = UC1610_SET_VBIAS_POT; /* set contrast */
|
||||||
|
cmd_buf[5] = (UC1610_INIT_CONTRAST * 255) / 100;
|
||||||
|
#if UC1610_TOP_VIEW
|
||||||
|
cmd_buf[6] = UC1610_SET_MAPPING_CONTROL | /* top view */
|
||||||
|
UC1610_SET_MAPPING_CONTROL_MY_FLAG |
|
||||||
|
UC1610_SET_MAPPING_CONTROL_MX_FLAG;
|
||||||
|
#else
|
||||||
|
cmd_buf[6] = UC1610_SET_MAPPING_CONTROL; /* bottom view */
|
||||||
|
#endif
|
||||||
|
cmd_buf[7] = UC1610_SET_SCROLL_LINES_LSB | 0; /* set scroll line on line 0 */
|
||||||
|
cmd_buf[8] = UC1610_SET_SCROLL_LINES_MSB | 0;
|
||||||
|
cmd_buf[9] = UC1610_SET_AC | UC1610_AC_WA_FLAG; /* set auto increment wrap around */
|
||||||
|
cmd_buf[10] = UC1610_SET_INVERSE_DISPLAY | 1; /* invert colors to complies lv color system */
|
||||||
|
cmd_buf[11] = UC1610_SET_DISPLAY_ENABLE | 1; /* turn display on */
|
||||||
|
|
||||||
|
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 12);
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->x2 < 0) return;
|
||||||
|
if(area->y2 < 0) return;
|
||||||
|
if(area->x1 > UC1610_HOR_RES - 1) return;
|
||||||
|
if(area->y1 > UC1610_VER_RES - 1) return;
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
uint8_t act_x1 = area->x1 < 0 ? 0 : area->x1;
|
||||||
|
uint8_t act_y1 = area->y1 < 0 ? 0 : area->y1;
|
||||||
|
uint8_t act_x2 = area->x2 > UC1610_HOR_RES - 1 ? UC1610_HOR_RES - 1 : area->x2;
|
||||||
|
uint8_t act_y2 = area->y2 > UC1610_VER_RES - 1 ? UC1610_VER_RES - 1 : area->y2;
|
||||||
|
|
||||||
|
uint8_t * buf = (uint8_t *) color_p;
|
||||||
|
uint16_t buf_size = (act_x2 - act_x1 + 1) * (((act_y2 - act_y1) >> 2) + 1);
|
||||||
|
|
||||||
|
/*Set display window to fill*/
|
||||||
|
cmd_buf[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; /* before changing boundaries */
|
||||||
|
cmd_buf[1] = UC1610_SET_WP_STARTING_CA;
|
||||||
|
cmd_buf[2] = act_x1;
|
||||||
|
cmd_buf[3] = UC1610_SET_WP_ENDING_CA;
|
||||||
|
cmd_buf[4] = act_x2;
|
||||||
|
cmd_buf[5] = UC1610_SET_WP_STARTING_PA;
|
||||||
|
cmd_buf[6] = act_y1 >> 2;
|
||||||
|
cmd_buf[7] = UC1610_SET_WP_ENDING_PA;
|
||||||
|
cmd_buf[8] = act_y2 >> 2;
|
||||||
|
cmd_buf[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; /* entering window programming */
|
||||||
|
|
||||||
|
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 10);
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
|
||||||
|
/*Flush draw_buf on display memory*/
|
||||||
|
LV_DRV_DISP_CMD_DATA(UC1610_DATA_MODE);
|
||||||
|
LV_DRV_DISP_SPI_CS(0);
|
||||||
|
LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size);
|
||||||
|
LV_DRV_DISP_SPI_CS(1);
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
|
||||||
|
(void) disp_drv;
|
||||||
|
(void) opa;
|
||||||
|
|
||||||
|
uint16_t idx = x + buf_w * (y >> 2);
|
||||||
|
|
||||||
|
/* Convert color to depth 2 */
|
||||||
|
#if LV_COLOR_DEPTH == 1
|
||||||
|
uint8_t color2 = color.full * 3;
|
||||||
|
#else
|
||||||
|
uint8_t color2 = color.full >> (LV_COLOR_DEPTH - 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
buf[idx] &= ~PIXIDX(y, 3); /* reset pixel color */
|
||||||
|
buf[idx] |= PIXIDX(y, color2); /* write new color */
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area) {
|
||||||
|
(void) disp_drv;
|
||||||
|
|
||||||
|
/* Round y window to display memory page size */
|
||||||
|
area->y1 = (area->y1 & (~3));
|
||||||
|
area->y2 = (area->y2 & (~3)) + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @file UC1610.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UC1610_H
|
||||||
|
#define UC1610_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_UC1610
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void uc1610_init(void);
|
||||||
|
void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area);
|
||||||
|
void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_UC1610 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* UC1610_H */
|
@ -0,0 +1,801 @@
|
|||||||
|
/**
|
||||||
|
* @file drm.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "drm.h"
|
||||||
|
#if USE_DRM
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
|
||||||
|
#define DBG_TAG "drm"
|
||||||
|
|
||||||
|
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||||
|
|
||||||
|
#define print(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__);
|
||||||
|
#define err(msg, ...) print("error: " msg "\n", ##__VA_ARGS__)
|
||||||
|
#define info(msg, ...) print(msg "\n", ##__VA_ARGS__)
|
||||||
|
#define dbg(msg, ...) {} //print(DBG_TAG ": " msg "\n", ##__VA_ARGS__)
|
||||||
|
|
||||||
|
struct drm_buffer {
|
||||||
|
uint32_t handle;
|
||||||
|
uint32_t pitch;
|
||||||
|
uint32_t offset;
|
||||||
|
unsigned long int size;
|
||||||
|
void * map;
|
||||||
|
uint32_t fb_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drm_dev {
|
||||||
|
int fd;
|
||||||
|
uint32_t conn_id, enc_id, crtc_id, plane_id, crtc_idx;
|
||||||
|
uint32_t width, height;
|
||||||
|
uint32_t mmWidth, mmHeight;
|
||||||
|
uint32_t fourcc;
|
||||||
|
drmModeModeInfo mode;
|
||||||
|
uint32_t blob_id;
|
||||||
|
drmModeCrtc *saved_crtc;
|
||||||
|
drmModeAtomicReq *req;
|
||||||
|
drmEventContext drm_event_ctx;
|
||||||
|
drmModePlane *plane;
|
||||||
|
drmModeCrtc *crtc;
|
||||||
|
drmModeConnector *conn;
|
||||||
|
uint32_t count_plane_props;
|
||||||
|
uint32_t count_crtc_props;
|
||||||
|
uint32_t count_conn_props;
|
||||||
|
drmModePropertyPtr plane_props[128];
|
||||||
|
drmModePropertyPtr crtc_props[128];
|
||||||
|
drmModePropertyPtr conn_props[128];
|
||||||
|
struct drm_buffer drm_bufs[2]; /* DUMB buffers */
|
||||||
|
struct drm_buffer *cur_bufs[2]; /* double buffering handling */
|
||||||
|
} drm_dev;
|
||||||
|
|
||||||
|
static uint32_t get_plane_property_id(const char *name)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
dbg("Find plane property: %s", name);
|
||||||
|
|
||||||
|
for (i = 0; i < drm_dev.count_plane_props; ++i)
|
||||||
|
if (!strcmp(drm_dev.plane_props[i]->name, name))
|
||||||
|
return drm_dev.plane_props[i]->prop_id;
|
||||||
|
|
||||||
|
dbg("Unknown plane property: %s", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t get_crtc_property_id(const char *name)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
dbg("Find crtc property: %s", name);
|
||||||
|
|
||||||
|
for (i = 0; i < drm_dev.count_crtc_props; ++i)
|
||||||
|
if (!strcmp(drm_dev.crtc_props[i]->name, name))
|
||||||
|
return drm_dev.crtc_props[i]->prop_id;
|
||||||
|
|
||||||
|
dbg("Unknown crtc property: %s", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t get_conn_property_id(const char *name)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
dbg("Find conn property: %s", name);
|
||||||
|
|
||||||
|
for (i = 0; i < drm_dev.count_conn_props; ++i)
|
||||||
|
if (!strcmp(drm_dev.conn_props[i]->name, name))
|
||||||
|
return drm_dev.conn_props[i]->prop_id;
|
||||||
|
|
||||||
|
dbg("Unknown conn property: %s", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
|
||||||
|
unsigned int tv_usec, void *user_data)
|
||||||
|
{
|
||||||
|
dbg("flip");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_get_plane_props(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.plane_id,
|
||||||
|
DRM_MODE_OBJECT_PLANE);
|
||||||
|
if (!props) {
|
||||||
|
err("drmModeObjectGetProperties failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dbg("Found %u plane props", props->count_props);
|
||||||
|
drm_dev.count_plane_props = props->count_props;
|
||||||
|
for (i = 0; i < props->count_props; i++) {
|
||||||
|
drm_dev.plane_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
|
||||||
|
dbg("Added plane prop %u:%s", drm_dev.plane_props[i]->prop_id, drm_dev.plane_props[i]->name);
|
||||||
|
}
|
||||||
|
drmModeFreeObjectProperties(props);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_get_crtc_props(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.crtc_id,
|
||||||
|
DRM_MODE_OBJECT_CRTC);
|
||||||
|
if (!props) {
|
||||||
|
err("drmModeObjectGetProperties failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dbg("Found %u crtc props", props->count_props);
|
||||||
|
drm_dev.count_crtc_props = props->count_props;
|
||||||
|
for (i = 0; i < props->count_props; i++) {
|
||||||
|
drm_dev.crtc_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
|
||||||
|
dbg("Added crtc prop %u:%s", drm_dev.crtc_props[i]->prop_id, drm_dev.crtc_props[i]->name);
|
||||||
|
}
|
||||||
|
drmModeFreeObjectProperties(props);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_get_conn_props(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.conn_id,
|
||||||
|
DRM_MODE_OBJECT_CONNECTOR);
|
||||||
|
if (!props) {
|
||||||
|
err("drmModeObjectGetProperties failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dbg("Found %u connector props", props->count_props);
|
||||||
|
drm_dev.count_conn_props = props->count_props;
|
||||||
|
for (i = 0; i < props->count_props; i++) {
|
||||||
|
drm_dev.conn_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
|
||||||
|
dbg("Added connector prop %u:%s", drm_dev.conn_props[i]->prop_id, drm_dev.conn_props[i]->name);
|
||||||
|
}
|
||||||
|
drmModeFreeObjectProperties(props);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_add_plane_property(const char *name, uint64_t value)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t prop_id = get_plane_property_id(name);
|
||||||
|
|
||||||
|
if (!prop_id) {
|
||||||
|
err("Couldn't find plane prop %s", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.plane_id, get_plane_property_id(name), value);
|
||||||
|
if (ret < 0) {
|
||||||
|
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_add_crtc_property(const char *name, uint64_t value)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t prop_id = get_crtc_property_id(name);
|
||||||
|
|
||||||
|
if (!prop_id) {
|
||||||
|
err("Couldn't find crtc prop %s", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.crtc_id, get_crtc_property_id(name), value);
|
||||||
|
if (ret < 0) {
|
||||||
|
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_add_conn_property(const char *name, uint64_t value)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t prop_id = get_conn_property_id(name);
|
||||||
|
|
||||||
|
if (!prop_id) {
|
||||||
|
err("Couldn't find conn prop %s", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.conn_id, get_conn_property_id(name), value);
|
||||||
|
if (ret < 0) {
|
||||||
|
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_dmabuf_set_plane(struct drm_buffer *buf)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
static int first = 1;
|
||||||
|
uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT;
|
||||||
|
|
||||||
|
drm_dev.req = drmModeAtomicAlloc();
|
||||||
|
|
||||||
|
/* On first Atomic commit, do a modeset */
|
||||||
|
if (first) {
|
||||||
|
drm_add_conn_property("CRTC_ID", drm_dev.crtc_id);
|
||||||
|
|
||||||
|
drm_add_crtc_property("MODE_ID", drm_dev.blob_id);
|
||||||
|
drm_add_crtc_property("ACTIVE", 1);
|
||||||
|
|
||||||
|
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||||
|
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_add_plane_property("FB_ID", buf->fb_handle);
|
||||||
|
drm_add_plane_property("CRTC_ID", drm_dev.crtc_id);
|
||||||
|
drm_add_plane_property("SRC_X", 0);
|
||||||
|
drm_add_plane_property("SRC_Y", 0);
|
||||||
|
drm_add_plane_property("SRC_W", drm_dev.width << 16);
|
||||||
|
drm_add_plane_property("SRC_H", drm_dev.height << 16);
|
||||||
|
drm_add_plane_property("CRTC_X", 0);
|
||||||
|
drm_add_plane_property("CRTC_Y", 0);
|
||||||
|
drm_add_plane_property("CRTC_W", drm_dev.width);
|
||||||
|
drm_add_plane_property("CRTC_H", drm_dev.height);
|
||||||
|
|
||||||
|
ret = drmModeAtomicCommit(drm_dev.fd, drm_dev.req, flags, NULL);
|
||||||
|
if (ret) {
|
||||||
|
err("drmModeAtomicCommit failed: %s", strerror(errno));
|
||||||
|
drmModeAtomicFree(drm_dev.req);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx)
|
||||||
|
{
|
||||||
|
drmModePlaneResPtr planes;
|
||||||
|
drmModePlanePtr plane;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int j;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int format = fourcc;
|
||||||
|
|
||||||
|
planes = drmModeGetPlaneResources(drm_dev.fd);
|
||||||
|
if (!planes) {
|
||||||
|
err("drmModeGetPlaneResources failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("drm: found planes %u", planes->count_planes);
|
||||||
|
|
||||||
|
for (i = 0; i < planes->count_planes; ++i) {
|
||||||
|
plane = drmModeGetPlane(drm_dev.fd, planes->planes[i]);
|
||||||
|
if (!plane) {
|
||||||
|
err("drmModeGetPlane failed: %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(plane->possible_crtcs & (1 << crtc_idx))) {
|
||||||
|
drmModeFreePlane(plane);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < plane->count_formats; ++j) {
|
||||||
|
if (plane->formats[j] == format)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == plane->count_formats) {
|
||||||
|
drmModeFreePlane(plane);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*plane_id = plane->plane_id;
|
||||||
|
drmModeFreePlane(plane);
|
||||||
|
|
||||||
|
dbg("found plane %d", *plane_id);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == planes->count_planes)
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
drmModeFreePlaneResources(planes);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_find_connector(void)
|
||||||
|
{
|
||||||
|
drmModeConnector *conn = NULL;
|
||||||
|
drmModeEncoder *enc = NULL;
|
||||||
|
drmModeRes *res;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((res = drmModeGetResources(drm_dev.fd)) == NULL) {
|
||||||
|
err("drmModeGetResources() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res->count_crtcs <= 0) {
|
||||||
|
err("no Crtcs");
|
||||||
|
goto free_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find all available connectors */
|
||||||
|
for (i = 0; i < res->count_connectors; i++) {
|
||||||
|
conn = drmModeGetConnector(drm_dev.fd, res->connectors[i]);
|
||||||
|
if (!conn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if DRM_CONNECTOR_ID >= 0
|
||||||
|
if (conn->connector_id != DRM_CONNECTOR_ID) {
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (conn->connection == DRM_MODE_CONNECTED) {
|
||||||
|
dbg("drm: connector %d: connected", conn->connector_id);
|
||||||
|
} else if (conn->connection == DRM_MODE_DISCONNECTED) {
|
||||||
|
dbg("drm: connector %d: disconnected", conn->connector_id);
|
||||||
|
} else if (conn->connection == DRM_MODE_UNKNOWNCONNECTION) {
|
||||||
|
dbg("drm: connector %d: unknownconnection", conn->connector_id);
|
||||||
|
} else {
|
||||||
|
dbg("drm: connector %d: unknown", conn->connector_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
conn = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!conn) {
|
||||||
|
err("suitable connector not found");
|
||||||
|
goto free_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.conn_id = conn->connector_id;
|
||||||
|
dbg("conn_id: %d", drm_dev.conn_id);
|
||||||
|
drm_dev.mmWidth = conn->mmWidth;
|
||||||
|
drm_dev.mmHeight = conn->mmHeight;
|
||||||
|
|
||||||
|
memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo));
|
||||||
|
|
||||||
|
if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode),
|
||||||
|
&drm_dev.blob_id)) {
|
||||||
|
err("error creating mode blob");
|
||||||
|
goto free_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.width = conn->modes[0].hdisplay;
|
||||||
|
drm_dev.height = conn->modes[0].vdisplay;
|
||||||
|
|
||||||
|
for (i = 0 ; i < res->count_encoders; i++) {
|
||||||
|
enc = drmModeGetEncoder(drm_dev.fd, res->encoders[i]);
|
||||||
|
if (!enc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dbg("enc%d enc_id %d conn enc_id %d", i, enc->encoder_id, conn->encoder_id);
|
||||||
|
|
||||||
|
if (enc->encoder_id == conn->encoder_id)
|
||||||
|
break;
|
||||||
|
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
enc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc) {
|
||||||
|
drm_dev.enc_id = enc->encoder_id;
|
||||||
|
dbg("enc_id: %d", drm_dev.enc_id);
|
||||||
|
drm_dev.crtc_id = enc->crtc_id;
|
||||||
|
dbg("crtc_id: %d", drm_dev.crtc_id);
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
} else {
|
||||||
|
/* Encoder hasn't been associated yet, look it up */
|
||||||
|
for (i = 0; i < conn->count_encoders; i++) {
|
||||||
|
int crtc, crtc_id = -1;
|
||||||
|
|
||||||
|
enc = drmModeGetEncoder(drm_dev.fd, conn->encoders[i]);
|
||||||
|
if (!enc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (crtc = 0 ; crtc < res->count_crtcs; crtc++) {
|
||||||
|
uint32_t crtc_mask = 1 << crtc;
|
||||||
|
|
||||||
|
crtc_id = res->crtcs[crtc];
|
||||||
|
|
||||||
|
dbg("enc_id %d crtc%d id %d mask %x possible %x", enc->encoder_id, crtc, crtc_id, crtc_mask, enc->possible_crtcs);
|
||||||
|
|
||||||
|
if (enc->possible_crtcs & crtc_mask)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crtc_id > 0) {
|
||||||
|
drm_dev.enc_id = enc->encoder_id;
|
||||||
|
dbg("enc_id: %d", drm_dev.enc_id);
|
||||||
|
drm_dev.crtc_id = crtc_id;
|
||||||
|
dbg("crtc_id: %d", drm_dev.crtc_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
enc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enc) {
|
||||||
|
err("suitable encoder not found");
|
||||||
|
goto free_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.crtc_idx = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_crtcs; ++i) {
|
||||||
|
if (drm_dev.crtc_id == res->crtcs[i]) {
|
||||||
|
drm_dev.crtc_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drm_dev.crtc_idx == -1) {
|
||||||
|
err("drm: CRTC not found");
|
||||||
|
goto free_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("crtc_idx: %d", drm_dev.crtc_idx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_res:
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_open(const char *path)
|
||||||
|
{
|
||||||
|
int fd, flags;
|
||||||
|
uint64_t has_dumb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fd = open(path, O_RDWR);
|
||||||
|
if (fd < 0) {
|
||||||
|
err("cannot open \"%s\"", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set FD_CLOEXEC flag */
|
||||||
|
if ((flags = fcntl(fd, F_GETFD)) < 0 ||
|
||||||
|
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
|
||||||
|
err("fcntl FD_CLOEXEC failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check capability */
|
||||||
|
ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
|
||||||
|
if (ret < 0 || has_dumb == 0) {
|
||||||
|
err("drmGetCap DRM_CAP_DUMB_BUFFER failed or \"%s\" doesn't have dumb "
|
||||||
|
"buffer", path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
err:
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_setup(unsigned int fourcc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const char *device_path = NULL;
|
||||||
|
|
||||||
|
device_path = getenv("DRM_CARD");
|
||||||
|
if (!device_path)
|
||||||
|
device_path = DRM_CARD;
|
||||||
|
|
||||||
|
drm_dev.fd = drm_open(device_path);
|
||||||
|
if (drm_dev.fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = drmSetClientCap(drm_dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
|
||||||
|
if (ret) {
|
||||||
|
err("No atomic modesetting support: %s", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_find_connector();
|
||||||
|
if (ret) {
|
||||||
|
err("available drm devices not found");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = find_plane(fourcc, &drm_dev.plane_id, drm_dev.crtc_id, drm_dev.crtc_idx);
|
||||||
|
if (ret) {
|
||||||
|
err("Cannot find plane");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.plane = drmModeGetPlane(drm_dev.fd, drm_dev.plane_id);
|
||||||
|
if (!drm_dev.plane) {
|
||||||
|
err("Cannot get plane");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.crtc = drmModeGetCrtc(drm_dev.fd, drm_dev.crtc_id);
|
||||||
|
if (!drm_dev.crtc) {
|
||||||
|
err("Cannot get crtc");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.conn = drmModeGetConnector(drm_dev.fd, drm_dev.conn_id);
|
||||||
|
if (!drm_dev.conn) {
|
||||||
|
err("Cannot get connector");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_get_plane_props();
|
||||||
|
if (ret) {
|
||||||
|
err("Cannot get plane props");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_get_crtc_props();
|
||||||
|
if (ret) {
|
||||||
|
err("Cannot get crtc props");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_get_conn_props();
|
||||||
|
if (ret) {
|
||||||
|
err("Cannot get connector props");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev.drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
|
||||||
|
drm_dev.drm_event_ctx.page_flip_handler = page_flip_handler;
|
||||||
|
drm_dev.fourcc = fourcc;
|
||||||
|
|
||||||
|
info("drm: Found plane_id: %u connector_id: %d crtc_id: %d",
|
||||||
|
drm_dev.plane_id, drm_dev.conn_id, drm_dev.crtc_id);
|
||||||
|
|
||||||
|
info("drm: %dx%d (%dmm X% dmm) pixel format %c%c%c%c",
|
||||||
|
drm_dev.width, drm_dev.height, drm_dev.mmWidth, drm_dev.mmHeight,
|
||||||
|
(fourcc>>0)&0xff, (fourcc>>8)&0xff, (fourcc>>16)&0xff, (fourcc>>24)&0xff);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
close(drm_dev.fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_allocate_dumb(struct drm_buffer *buf)
|
||||||
|
{
|
||||||
|
struct drm_mode_create_dumb creq;
|
||||||
|
struct drm_mode_map_dumb mreq;
|
||||||
|
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* create dumb buffer */
|
||||||
|
memset(&creq, 0, sizeof(creq));
|
||||||
|
creq.width = drm_dev.width;
|
||||||
|
creq.height = drm_dev.height;
|
||||||
|
creq.bpp = LV_COLOR_DEPTH;
|
||||||
|
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
|
||||||
|
if (ret < 0) {
|
||||||
|
err("DRM_IOCTL_MODE_CREATE_DUMB fail");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->handle = creq.handle;
|
||||||
|
buf->pitch = creq.pitch;
|
||||||
|
dbg("pitch %d", buf->pitch);
|
||||||
|
buf->size = creq.size;
|
||||||
|
dbg("size %d", buf->size);
|
||||||
|
|
||||||
|
/* prepare buffer for memory mapping */
|
||||||
|
memset(&mreq, 0, sizeof(mreq));
|
||||||
|
mreq.handle = creq.handle;
|
||||||
|
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
|
||||||
|
if (ret) {
|
||||||
|
err("DRM_IOCTL_MODE_MAP_DUMB fail");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->offset = mreq.offset;
|
||||||
|
|
||||||
|
/* perform actual memory mapping */
|
||||||
|
buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset);
|
||||||
|
if (buf->map == MAP_FAILED) {
|
||||||
|
err("mmap fail");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear the framebuffer to 0 (= full transparency in ARGB8888) */
|
||||||
|
memset(buf->map, 0, creq.size);
|
||||||
|
|
||||||
|
/* create framebuffer object for the dumb-buffer */
|
||||||
|
handles[0] = creq.handle;
|
||||||
|
pitches[0] = creq.pitch;
|
||||||
|
offsets[0] = 0;
|
||||||
|
ret = drmModeAddFB2(drm_dev.fd, drm_dev.width, drm_dev.height, drm_dev.fourcc,
|
||||||
|
handles, pitches, offsets, &buf->fb_handle, 0);
|
||||||
|
if (ret) {
|
||||||
|
err("drmModeAddFB fail");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_setup_buffers(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Allocate DUMB buffers */
|
||||||
|
ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = drm_allocate_dumb(&drm_dev.drm_bufs[1]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set buffering handling */
|
||||||
|
drm_dev.cur_bufs[0] = NULL;
|
||||||
|
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[0];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_wait_vsync(lv_disp_drv_t *disp_drv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(drm_dev.fd, &fds);
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = select(drm_dev.fd + 1, &fds, NULL, NULL, NULL);
|
||||||
|
} while (ret == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
err("select failed: %s", strerror(errno));
|
||||||
|
drmModeAtomicFree(drm_dev.req);
|
||||||
|
drm_dev.req = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(drm_dev.fd, &fds))
|
||||||
|
drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
|
||||||
|
|
||||||
|
drmModeAtomicFree(drm_dev.req);
|
||||||
|
drm_dev.req = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
||||||
|
{
|
||||||
|
struct drm_buffer *fbuf = drm_dev.cur_bufs[1];
|
||||||
|
lv_coord_t w = (area->x2 - area->x1 + 1);
|
||||||
|
lv_coord_t h = (area->y2 - area->y1 + 1);
|
||||||
|
int i, y;
|
||||||
|
|
||||||
|
dbg("x %d:%d y %d:%d w %d h %d", area->x1, area->x2, area->y1, area->y2, w, h);
|
||||||
|
|
||||||
|
/* Partial update */
|
||||||
|
if ((w != drm_dev.width || h != drm_dev.height) && drm_dev.cur_bufs[0])
|
||||||
|
memcpy(fbuf->map, drm_dev.cur_bufs[0]->map, fbuf->size);
|
||||||
|
|
||||||
|
for (y = 0, i = area->y1 ; i <= area->y2 ; ++i, ++y) {
|
||||||
|
memcpy((uint8_t *)fbuf->map + (area->x1 * (LV_COLOR_SIZE/8)) + (fbuf->pitch * i),
|
||||||
|
(uint8_t *)color_p + (w * (LV_COLOR_SIZE/8) * y),
|
||||||
|
w * (LV_COLOR_SIZE/8));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drm_dev.req)
|
||||||
|
drm_wait_vsync(disp_drv);
|
||||||
|
|
||||||
|
/* show fbuf plane */
|
||||||
|
if (drm_dmabuf_set_plane(fbuf)) {
|
||||||
|
err("Flush fail");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dbg("Flush done");
|
||||||
|
|
||||||
|
if (!drm_dev.cur_bufs[0])
|
||||||
|
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1];
|
||||||
|
else
|
||||||
|
drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
|
||||||
|
|
||||||
|
drm_dev.cur_bufs[0] = fbuf;
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LV_COLOR_DEPTH == 32
|
||||||
|
#define DRM_FOURCC DRM_FORMAT_ARGB8888
|
||||||
|
#elif LV_COLOR_DEPTH == 16
|
||||||
|
#define DRM_FOURCC DRM_FORMAT_RGB565
|
||||||
|
#else
|
||||||
|
#error LV_COLOR_DEPTH not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi)
|
||||||
|
{
|
||||||
|
if (width)
|
||||||
|
*width = drm_dev.width;
|
||||||
|
|
||||||
|
if (height)
|
||||||
|
*height = drm_dev.height;
|
||||||
|
|
||||||
|
if (dpi && drm_dev.mmWidth)
|
||||||
|
*dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = drm_setup(DRM_FOURCC);
|
||||||
|
if (ret) {
|
||||||
|
close(drm_dev.fd);
|
||||||
|
drm_dev.fd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_setup_buffers();
|
||||||
|
if (ret) {
|
||||||
|
err("DRM buffer allocation failed");
|
||||||
|
close(drm_dev.fd);
|
||||||
|
drm_dev.fd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info("DRM subsystem and buffer mapped successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_exit(void)
|
||||||
|
{
|
||||||
|
close(drm_dev.fd);
|
||||||
|
drm_dev.fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* @file drm.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DRM_H
|
||||||
|
#define DRM_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_DRM
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void drm_init(void);
|
||||||
|
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi);
|
||||||
|
void drm_exit(void);
|
||||||
|
void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void drm_wait_vsync(lv_disp_drv_t * drv);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*USE_DRM*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*DRM_H*/
|
@ -0,0 +1,275 @@
|
|||||||
|
/**
|
||||||
|
* @file fbdev.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "fbdev.h"
|
||||||
|
#if USE_FBDEV || USE_BSD_FBDEV
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#if USE_BSD_FBDEV
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/consio.h>
|
||||||
|
#include <sys/fbio.h>
|
||||||
|
#else /* USE_BSD_FBDEV */
|
||||||
|
#include <linux/fb.h>
|
||||||
|
#endif /* USE_BSD_FBDEV */
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#ifndef FBDEV_PATH
|
||||||
|
#define FBDEV_PATH "/dev/fb0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DIV_ROUND_UP
|
||||||
|
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STRUCTURES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
struct bsd_fb_var_info{
|
||||||
|
uint32_t xoffset;
|
||||||
|
uint32_t yoffset;
|
||||||
|
uint32_t xres;
|
||||||
|
uint32_t yres;
|
||||||
|
int bits_per_pixel;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bsd_fb_fix_info{
|
||||||
|
long int line_length;
|
||||||
|
long int smem_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
#if USE_BSD_FBDEV
|
||||||
|
static struct bsd_fb_var_info vinfo;
|
||||||
|
static struct bsd_fb_fix_info finfo;
|
||||||
|
#else
|
||||||
|
static struct fb_var_screeninfo vinfo;
|
||||||
|
static struct fb_fix_screeninfo finfo;
|
||||||
|
#endif /* USE_BSD_FBDEV */
|
||||||
|
static char *fbp = 0;
|
||||||
|
static long int screensize = 0;
|
||||||
|
static int fbfd = 0;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#if USE_BSD_FBDEV
|
||||||
|
#define FBIOBLANK FBIO_BLANK
|
||||||
|
#endif /* USE_BSD_FBDEV */
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void fbdev_init(void)
|
||||||
|
{
|
||||||
|
// Open the file for reading and writing
|
||||||
|
fbfd = open(FBDEV_PATH, O_RDWR);
|
||||||
|
if(fbfd == -1) {
|
||||||
|
perror("Error: cannot open framebuffer device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LV_LOG_INFO("The framebuffer device was opened successfully");
|
||||||
|
|
||||||
|
// Make sure that the display is on.
|
||||||
|
if (ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) {
|
||||||
|
perror("ioctl(FBIOBLANK)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_BSD_FBDEV
|
||||||
|
struct fbtype fb;
|
||||||
|
unsigned line_length;
|
||||||
|
|
||||||
|
//Get fb type
|
||||||
|
if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) {
|
||||||
|
perror("ioctl(FBIOGTYPE)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get screen width
|
||||||
|
if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) {
|
||||||
|
perror("ioctl(FBIO_GETLINEWIDTH)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vinfo.xres = (unsigned) fb.fb_width;
|
||||||
|
vinfo.yres = (unsigned) fb.fb_height;
|
||||||
|
vinfo.bits_per_pixel = fb.fb_depth;
|
||||||
|
vinfo.xoffset = 0;
|
||||||
|
vinfo.yoffset = 0;
|
||||||
|
finfo.line_length = line_length;
|
||||||
|
finfo.smem_len = finfo.line_length * vinfo.yres;
|
||||||
|
#else /* USE_BSD_FBDEV */
|
||||||
|
|
||||||
|
// Get fixed screen information
|
||||||
|
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
|
||||||
|
perror("Error reading fixed information");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get variable screen information
|
||||||
|
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
|
||||||
|
perror("Error reading variable information");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* USE_BSD_FBDEV */
|
||||||
|
|
||||||
|
LV_LOG_INFO("%dx%d, %dbpp", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
|
||||||
|
|
||||||
|
// Figure out the size of the screen in bytes
|
||||||
|
screensize = finfo.smem_len; //finfo.line_length * vinfo.yres;
|
||||||
|
|
||||||
|
// Map the device to memory
|
||||||
|
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
|
||||||
|
if((intptr_t)fbp == -1) {
|
||||||
|
perror("Error: failed to map framebuffer device to memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't initialise the memory to retain what's currently displayed / avoid clearing the screen.
|
||||||
|
// This is important for applications that only draw to a subsection of the full framebuffer.
|
||||||
|
|
||||||
|
LV_LOG_INFO("The framebuffer device was mapped to memory successfully");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fbdev_exit(void)
|
||||||
|
{
|
||||||
|
close(fbfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
if(fbp == NULL ||
|
||||||
|
area->x2 < 0 ||
|
||||||
|
area->y2 < 0 ||
|
||||||
|
area->x1 > (int32_t)vinfo.xres - 1 ||
|
||||||
|
area->y1 > (int32_t)vinfo.yres - 1) {
|
||||||
|
lv_disp_flush_ready(drv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Truncate the area to the screen*/
|
||||||
|
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
|
||||||
|
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
|
||||||
|
int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2;
|
||||||
|
int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2;
|
||||||
|
|
||||||
|
|
||||||
|
lv_coord_t w = (act_x2 - act_x1 + 1);
|
||||||
|
long int location = 0;
|
||||||
|
long int byte_location = 0;
|
||||||
|
unsigned char bit_location = 0;
|
||||||
|
|
||||||
|
/*32 or 24 bit per pixel*/
|
||||||
|
if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {
|
||||||
|
uint32_t * fbp32 = (uint32_t *)fbp;
|
||||||
|
int32_t y;
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 4;
|
||||||
|
memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4);
|
||||||
|
color_p += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*16 bit per pixel*/
|
||||||
|
else if(vinfo.bits_per_pixel == 16) {
|
||||||
|
uint16_t * fbp16 = (uint16_t *)fbp;
|
||||||
|
int32_t y;
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2;
|
||||||
|
memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2);
|
||||||
|
color_p += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*8 bit per pixel*/
|
||||||
|
else if(vinfo.bits_per_pixel == 8) {
|
||||||
|
uint8_t * fbp8 = (uint8_t *)fbp;
|
||||||
|
int32_t y;
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length;
|
||||||
|
memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1));
|
||||||
|
color_p += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*1 bit per pixel*/
|
||||||
|
else if(vinfo.bits_per_pixel == 1) {
|
||||||
|
uint8_t * fbp8 = (uint8_t *)fbp;
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
for(y = act_y1; y <= act_y2; y++) {
|
||||||
|
for(x = act_x1; x <= act_x2; x++) {
|
||||||
|
location = (x + vinfo.xoffset) + (y + vinfo.yoffset) * vinfo.xres;
|
||||||
|
byte_location = location / 8; /* find the byte we need to change */
|
||||||
|
bit_location = location % 8; /* inside the byte found, find the bit we need to change */
|
||||||
|
fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location);
|
||||||
|
fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location;
|
||||||
|
color_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_p += area->x2 - act_x2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*Not supported bit per pixel*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//May be some direct update command is required
|
||||||
|
//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));
|
||||||
|
|
||||||
|
lv_disp_flush_ready(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *dpi) {
|
||||||
|
if (width)
|
||||||
|
*width = vinfo.xres;
|
||||||
|
|
||||||
|
if (height)
|
||||||
|
*height = vinfo.yres;
|
||||||
|
|
||||||
|
if (dpi && vinfo.height)
|
||||||
|
*dpi = DIV_ROUND_UP(vinfo.xres * 254, vinfo.width * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fbdev_set_offset(uint32_t xoffset, uint32_t yoffset) {
|
||||||
|
vinfo.xoffset = xoffset;
|
||||||
|
vinfo.yoffset = yoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* @file fbdev.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FBDEV_H
|
||||||
|
#define FBDEV_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_FBDEV || USE_BSD_FBDEV
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void fbdev_init(void);
|
||||||
|
void fbdev_exit(void);
|
||||||
|
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *dpi);
|
||||||
|
/**
|
||||||
|
* Set the X and Y offset in the variable framebuffer info.
|
||||||
|
* @param xoffset horizontal offset
|
||||||
|
* @param yoffset vertical offset
|
||||||
|
*/
|
||||||
|
void fbdev_set_offset(uint32_t xoffset, uint32_t yoffset);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*USE_FBDEV*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*FBDEV_H*/
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* @file monitor.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MONITOR_H
|
||||||
|
#define MONITOR_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void monitor_init(void);
|
||||||
|
void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_MONITOR */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MONITOR_H */
|
@ -0,0 +1 @@
|
|||||||
|
--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent=
|
@ -0,0 +1 @@
|
|||||||
|
--convert-tabs --indent=spaces=4
|
@ -0,0 +1,97 @@
|
|||||||
|
# Add GTK under Linux in Eclipse
|
||||||
|
|
||||||
|
## Install GDK
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt-get install libgtk-3-dev
|
||||||
|
sudo apt-get install libglib2.0-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add GTK include paths and libraries
|
||||||
|
|
||||||
|
In "Project properties > C/C++ Build > Settings" set the followings:
|
||||||
|
|
||||||
|
- "Cross GCC Compiler > Command line pattern"
|
||||||
|
- Add ` ${gtk+-cflags}` to the end (add a space between the last command and this)
|
||||||
|
|
||||||
|
- "Cross GCC Compiler > Includes"
|
||||||
|
- /usr/include/glib-2.0
|
||||||
|
- /usr/include/gtk-3.0
|
||||||
|
- /usr/include/pango-1.0
|
||||||
|
- /usr/include/cairo
|
||||||
|
- /usr/include/gdk-pixbuf-2.0
|
||||||
|
- /usr/include/atk-1.0
|
||||||
|
|
||||||
|
- "Cross GCC Linker > Command line pattern"
|
||||||
|
- Add ` ${gtk+-libs}` to the end (add a space between the last command and this)
|
||||||
|
|
||||||
|
|
||||||
|
- "Cross GCC Linker > Libraries"
|
||||||
|
- Add `pthread`
|
||||||
|
|
||||||
|
|
||||||
|
- In "C/C++ Build > Build variables"
|
||||||
|
- Configuration: [All Configuration]
|
||||||
|
|
||||||
|
- Add
|
||||||
|
- Variable name: `gtk+-cflags`
|
||||||
|
- Type: `String`
|
||||||
|
- Value: `pkg-config --cflags gtk+-3.0`
|
||||||
|
- Variable name: `gtk+-libs`
|
||||||
|
- Type: `String`
|
||||||
|
- Value: `pkg-config --libs gtk+-3.0`
|
||||||
|
|
||||||
|
|
||||||
|
## Init GDK in LVGL
|
||||||
|
|
||||||
|
1. In `main.c` `#include "lv_drivers/gtkdrv/gtkdrv.h"`
|
||||||
|
2. Enable the GTK driver in `lv_drv_conf.h` with `USE_GTK 1`
|
||||||
|
3. After `lv_init()` call `gdkdrv_init()`;
|
||||||
|
4. Add a display:
|
||||||
|
```c
|
||||||
|
static lv_disp_buf_t disp_buf1;
|
||||||
|
static lv_color_t buf1_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];
|
||||||
|
lv_disp_buf_init(&disp_buf1, buf1_1, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX);
|
||||||
|
|
||||||
|
/*Create a display*/
|
||||||
|
lv_disp_drv_t disp_drv;
|
||||||
|
lv_disp_drv_init(&disp_drv);
|
||||||
|
disp_drv.buffer = &disp_buf1;
|
||||||
|
disp_drv.flush_cb = gtkdrv_flush_cb;
|
||||||
|
```
|
||||||
|
5. Add mouse:
|
||||||
|
```c
|
||||||
|
lv_indev_drv_t indev_drv_mouse;
|
||||||
|
lv_indev_drv_init(&indev_drv_mouse);
|
||||||
|
indev_drv_mouse.type = LV_INDEV_TYPE_POINTER;
|
||||||
|
```
|
||||||
|
6. Add keyboard:
|
||||||
|
```c
|
||||||
|
lv_indev_drv_t indev_drv_kb;
|
||||||
|
lv_indev_drv_init(&indev_drv_kb);
|
||||||
|
indev_drv_kb.type = LV_INDEV_TYPE_KEYPAD;
|
||||||
|
indev_drv_kb.read_cb = lv_keyboard_read_cb;
|
||||||
|
lv_indev_drv_register(&indev_drv_kb);
|
||||||
|
```
|
||||||
|
7. Configure tick in `lv_conf.h`
|
||||||
|
```c
|
||||||
|
#define LV_TICK_CUSTOM 1
|
||||||
|
#if LV_TICK_CUSTOM == 1
|
||||||
|
#define LV_TICK_CUSTOM_INCLUDE "lv_drivers/gtkdrv/gtkdrv.h" /*Header for the sys time function*/
|
||||||
|
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (gtkdrv_tick_get()) /*Expression evaluating to current systime in ms*/
|
||||||
|
#endif /*LV_TICK_CUSTOM*/
|
||||||
|
```
|
||||||
|
8. Be sure `LV_COLOR_DEPTH` is `32` in `lv_conf.h`
|
||||||
|
|
||||||
|
## Run in a window
|
||||||
|
Build and Run to "normally" run the UI in a window
|
||||||
|
|
||||||
|
## Run in browser
|
||||||
|
With the help of `Broadway` the UI can be easily shown via a browser.
|
||||||
|
|
||||||
|
1. Open Terminal and start *Broadway* with `broadwayd :5`. Leave the terminal running.
|
||||||
|
2. Navigate to where eclipse created the binary executable (my_project/Debug) and open a terminal in that folder.
|
||||||
|
In this terminal run `GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 ./my_executable` (replace *my_executable* wih name of your executable)
|
||||||
|
3. Open a web browser and go to `http://localhost:8085/`
|
||||||
|
|
||||||
|
![LVGL with GTK/GDK Broadway backend](https://github.com/lvgl/lv_drivers/blob/master/gtkdrv/broadway.png?raw=true)
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -0,0 +1,323 @@
|
|||||||
|
/**
|
||||||
|
* @file gtk.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "gtkdrv.h"
|
||||||
|
|
||||||
|
#if USE_GTK
|
||||||
|
#define _DEFAULT_SOURCE /* needed for usleep() */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <gtk/gtkx.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void gtkdrv_handler(void * p);
|
||||||
|
static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event,
|
||||||
|
gpointer user_data);
|
||||||
|
static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event,
|
||||||
|
gpointer user_data);
|
||||||
|
static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
|
||||||
|
gpointer user_data);
|
||||||
|
static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event,
|
||||||
|
gpointer user_data);
|
||||||
|
static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
static void quit_handler(void);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static GtkWidget *window;
|
||||||
|
static GtkWidget *event_box;
|
||||||
|
|
||||||
|
static GtkWidget *output_image;
|
||||||
|
static GdkPixbuf *pixbuf;
|
||||||
|
|
||||||
|
static unsigned char run_gtk;
|
||||||
|
|
||||||
|
static lv_coord_t mouse_x;
|
||||||
|
static lv_coord_t mouse_y;
|
||||||
|
static lv_indev_state_t mouse_btn = LV_INDEV_STATE_REL;
|
||||||
|
static lv_key_t last_key;
|
||||||
|
static lv_indev_state_t last_key_state;
|
||||||
|
|
||||||
|
static uint8_t fb[LV_HOR_RES_MAX * LV_VER_RES_MAX * 3];
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void gtkdrv_init(void)
|
||||||
|
{
|
||||||
|
// Init GTK
|
||||||
|
gtk_init(NULL, NULL);
|
||||||
|
|
||||||
|
/* Or just set up the widgets in code */
|
||||||
|
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||||
|
gtk_window_set_default_size(GTK_WINDOW(window), LV_HOR_RES_MAX, LV_VER_RES_MAX);
|
||||||
|
gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
|
||||||
|
output_image = gtk_image_new();
|
||||||
|
event_box = gtk_event_box_new (); // Use event_box around image, otherwise mouse position output in broadway is offset
|
||||||
|
gtk_container_add(GTK_CONTAINER (event_box), output_image);
|
||||||
|
gtk_container_add(GTK_CONTAINER (window), event_box);
|
||||||
|
|
||||||
|
gtk_widget_add_events(event_box, GDK_BUTTON_PRESS_MASK);
|
||||||
|
gtk_widget_add_events(event_box, GDK_SCROLL_MASK);
|
||||||
|
gtk_widget_add_events(event_box, GDK_POINTER_MOTION_MASK);
|
||||||
|
gtk_widget_add_events(window, GDK_KEY_PRESS_MASK);
|
||||||
|
|
||||||
|
g_signal_connect(window, "destroy", G_CALLBACK(quit_handler), NULL);
|
||||||
|
g_signal_connect(event_box, "button-press-event", G_CALLBACK(mouse_pressed), NULL);
|
||||||
|
g_signal_connect(event_box, "button-release-event", G_CALLBACK(mouse_released), NULL);
|
||||||
|
g_signal_connect(event_box, "motion-notify-event", G_CALLBACK(mouse_motion), NULL);
|
||||||
|
g_signal_connect(window, "key_press_event", G_CALLBACK(keyboard_press), NULL);
|
||||||
|
g_signal_connect(window, "key_release_event", G_CALLBACK(keyboard_release), NULL);
|
||||||
|
|
||||||
|
|
||||||
|
gtk_widget_show_all(window);
|
||||||
|
|
||||||
|
pixbuf = gdk_pixbuf_new_from_data((guchar*)fb, GDK_COLORSPACE_RGB, false, 8, LV_HOR_RES_MAX, LV_VER_RES_MAX, LV_HOR_RES_MAX * 3, NULL, NULL);
|
||||||
|
if (pixbuf == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Creating pixbuf failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, NULL, gtkdrv_handler, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
|
||||||
|
uint32_t gtkdrv_tick_get(void)
|
||||||
|
{
|
||||||
|
static uint64_t start_ms = 0;
|
||||||
|
if(start_ms == 0) {
|
||||||
|
struct timeval tv_start;
|
||||||
|
gettimeofday(&tv_start, NULL);
|
||||||
|
start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval tv_now;
|
||||||
|
gettimeofday(&tv_now, NULL);
|
||||||
|
uint64_t now_ms;
|
||||||
|
now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
|
||||||
|
|
||||||
|
uint32_t time_ms = now_ms - start_ms;
|
||||||
|
|
||||||
|
return time_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res;
|
||||||
|
lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res;
|
||||||
|
|
||||||
|
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t y;
|
||||||
|
int32_t x;
|
||||||
|
int32_t p;
|
||||||
|
for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
|
||||||
|
p = (y * disp_drv->hor_res + area->x1) * 3;
|
||||||
|
for(x = area->x1; x <= area->x2 && x < disp_drv->hor_res; x++) {
|
||||||
|
fb[p] = color_p->ch.red;
|
||||||
|
fb[p + 1] = color_p->ch.green;
|
||||||
|
fb[p + 2] = color_p->ch.blue;
|
||||||
|
|
||||||
|
p += 3;
|
||||||
|
color_p ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*IMPORTANT! It must be called to tell the system the flush is ready*/
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
data->point.x = mouse_x;
|
||||||
|
data->point.y = mouse_y;
|
||||||
|
data->state = mouse_btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
data->key = last_key;
|
||||||
|
data->state = last_key_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void gtkdrv_handler(void * p)
|
||||||
|
{
|
||||||
|
while(1) {
|
||||||
|
gtk_image_set_from_pixbuf(GTK_IMAGE(output_image), pixbuf); // Test code
|
||||||
|
|
||||||
|
/* Real code should: call gdk_pixbuf_new_from_data () with pointer to frame buffer
|
||||||
|
generated by LVGL. See
|
||||||
|
https://developer.gnome.org/gdk-pixbuf/2.36/gdk-pixbuf-Image-Data-in-Memory.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
gtk_main_iteration_do(FALSE);
|
||||||
|
/* Explicitly calling each iteration of the GTK main loop allows LVGL to sync frame
|
||||||
|
buffer updates with GTK. It is perhaps also possible to just call gtk_main(), but not
|
||||||
|
sure how sync will work then
|
||||||
|
*/
|
||||||
|
usleep(1*1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean mouse_pressed(GtkWidget *widget, GdkEventButton *event,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
mouse_btn = LV_INDEV_STATE_PR;
|
||||||
|
// Important, if this function returns TRUE the window cannot be moved around inside the browser
|
||||||
|
// when using broadway
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean mouse_released(GtkWidget *widget, GdkEventButton *event,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
mouse_btn = LV_INDEV_STATE_REL;
|
||||||
|
// Important, if this function returns TRUE the window cannot be moved around inside the browser
|
||||||
|
// when using broadway
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static gboolean mouse_motion(GtkWidget *widget, GdkEventMotion *event,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
mouse_x = event->x;
|
||||||
|
mouse_y = event->y;
|
||||||
|
// Important, if this function returns TRUE the window cannot be moved around inside the browser
|
||||||
|
// when using broadway
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean keyboard_press(GtkWidget *widget, GdkEventKey *event,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t ascii_key = event->keyval;
|
||||||
|
/*Remap some key to LV_KEY_... to manage groups*/
|
||||||
|
switch(event->keyval) {
|
||||||
|
case GDK_KEY_rightarrow:
|
||||||
|
case GDK_KEY_Right:
|
||||||
|
ascii_key = LV_KEY_RIGHT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_leftarrow:
|
||||||
|
case GDK_KEY_Left:
|
||||||
|
ascii_key = LV_KEY_LEFT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_uparrow:
|
||||||
|
case GDK_KEY_Up:
|
||||||
|
ascii_key = LV_KEY_UP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_downarrow:
|
||||||
|
case GDK_KEY_Down:
|
||||||
|
ascii_key = LV_KEY_DOWN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_Escape:
|
||||||
|
ascii_key = LV_KEY_ESC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_BackSpace:
|
||||||
|
ascii_key = LV_KEY_BACKSPACE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_Delete:
|
||||||
|
ascii_key = LV_KEY_DEL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_Tab:
|
||||||
|
ascii_key = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_KEY_KP_Enter:
|
||||||
|
case GDK_KEY_Return:
|
||||||
|
case '\r':
|
||||||
|
ascii_key = LV_KEY_ENTER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
last_key = ascii_key;
|
||||||
|
last_key_state = LV_INDEV_STATE_PR;
|
||||||
|
// For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean keyboard_release(GtkWidget *widget, GdkEventKey *event,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
last_key = 0;
|
||||||
|
last_key_state = LV_INDEV_STATE_REL;
|
||||||
|
// For other codes refer to https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventKey
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quit_handler(void)
|
||||||
|
{
|
||||||
|
exit(0);
|
||||||
|
run_gtk = FALSE;
|
||||||
|
}
|
||||||
|
#endif /*USE_GTK*/
|
||||||
|
|
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* @file gtkdrv
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GTKDRV_H
|
||||||
|
#define GTKDRV_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_GTK
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void gtkdrv_init(void);
|
||||||
|
uint32_t gtkdrv_tick_get(void);
|
||||||
|
void gtkdrv_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
void gtkdrv_mouse_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data);
|
||||||
|
void gtkdrv_keyboard_read_cb(lv_indev_drv_t * drv, lv_indev_data_t * data);
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*USE_GTK*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GTKDRV_H */
|
@ -0,0 +1,383 @@
|
|||||||
|
/**
|
||||||
|
* @file AD_touch.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AD_touch.h"
|
||||||
|
|
||||||
|
#if USE_AD_TOUCH
|
||||||
|
|
||||||
|
#include LV_DRV_INDEV_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
#define SAMPLE_POINTS 4
|
||||||
|
|
||||||
|
#define CALIBRATIONINSET 20 // range 0 <= CALIBRATIONINSET <= 40
|
||||||
|
|
||||||
|
#define RESISTIVETOUCH_AUTO_SAMPLE_MODE
|
||||||
|
#define TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD 350 // between 0-0x03ff the lesser this value
|
||||||
|
|
||||||
|
|
||||||
|
// Current ADC values for X and Y channels
|
||||||
|
int16_t adcX = 0;
|
||||||
|
int16_t adcY = 0;
|
||||||
|
volatile unsigned int adcTC = 0;
|
||||||
|
|
||||||
|
// coefficient values
|
||||||
|
volatile long _trA;
|
||||||
|
volatile long _trB;
|
||||||
|
volatile long _trC;
|
||||||
|
volatile long _trD;
|
||||||
|
|
||||||
|
volatile int16_t xRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULX, TOUCHCAL_URX, TOUCHCAL_LRX, TOUCHCAL_LLX};
|
||||||
|
volatile int16_t yRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULY, TOUCHCAL_URY, TOUCHCAL_LRY, TOUCHCAL_LLY};
|
||||||
|
|
||||||
|
#define TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR 8
|
||||||
|
|
||||||
|
// use this scale factor to avoid working in floating point numbers
|
||||||
|
#define SCALE_FACTOR (1 << TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IDLE, //0
|
||||||
|
SET_X, //1
|
||||||
|
RUN_X, //2
|
||||||
|
GET_X, //3
|
||||||
|
RUN_CHECK_X, //4
|
||||||
|
CHECK_X, //5
|
||||||
|
SET_Y, //6
|
||||||
|
RUN_Y, //7
|
||||||
|
GET_Y, //8
|
||||||
|
CHECK_Y, //9
|
||||||
|
SET_VALUES, //10
|
||||||
|
GET_POT, //11
|
||||||
|
RUN_POT //12
|
||||||
|
} TOUCH_STATES;
|
||||||
|
|
||||||
|
volatile TOUCH_STATES state = IDLE;
|
||||||
|
|
||||||
|
#define CAL_X_INSET (((GetMaxX() + 1) * (CALIBRATIONINSET >> 1)) / 100)
|
||||||
|
#define CAL_Y_INSET (((GetMaxY() + 1) * (CALIBRATIONINSET >> 1)) / 100)
|
||||||
|
|
||||||
|
int stat;
|
||||||
|
int16_t temp_x, temp_y;
|
||||||
|
|
||||||
|
|
||||||
|
static int16_t TouchGetX(void);
|
||||||
|
static int16_t TouchGetRawX(void);
|
||||||
|
static int16_t TouchGetY(void);
|
||||||
|
static int16_t TouchGetRawY(void);
|
||||||
|
static int16_t TouchDetectPosition(void);
|
||||||
|
static void TouchCalculateCalPoints(void);
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
void ad_touch_init(void)
|
||||||
|
{
|
||||||
|
// Initialize ADC for auto sampling mode
|
||||||
|
AD1CON1 = 0; // reset
|
||||||
|
AD1CON2 = 0; // AVdd, AVss, int every conversion, MUXA only
|
||||||
|
AD1CON3 = 0x1FFF; // 31 Tad auto-sample, Tad = 256*Tcy
|
||||||
|
AD1CON1 = 0x80E0; // Turn on A/D module, use auto-convert
|
||||||
|
|
||||||
|
|
||||||
|
ADPCFG_XPOS = RESISTIVETOUCH_ANALOG;
|
||||||
|
ADPCFG_YPOS = RESISTIVETOUCH_ANALOG;
|
||||||
|
|
||||||
|
AD1CSSL = 0; // No scanned inputs
|
||||||
|
|
||||||
|
state = SET_X; // set the state of the state machine to start the sampling
|
||||||
|
|
||||||
|
/*Load calibration data*/
|
||||||
|
xRawTouch[0] = TOUCHCAL_ULX;
|
||||||
|
yRawTouch[0] = TOUCHCAL_ULY;
|
||||||
|
xRawTouch[1] = TOUCHCAL_URX;
|
||||||
|
yRawTouch[1] = TOUCHCAL_URY;
|
||||||
|
xRawTouch[3] = TOUCHCAL_LLX;
|
||||||
|
yRawTouch[3] = TOUCHCAL_LLY;
|
||||||
|
xRawTouch[2] = TOUCHCAL_LRX;
|
||||||
|
yRawTouch[2] = TOUCHCAL_LRY;
|
||||||
|
|
||||||
|
TouchCalculateCalPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Use this in lv_indev_drv*/
|
||||||
|
bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
static int16_t last_x = 0;
|
||||||
|
static int16_t last_y = 0;
|
||||||
|
|
||||||
|
int16_t x, y;
|
||||||
|
|
||||||
|
x = TouchGetX();
|
||||||
|
y = TouchGetY();
|
||||||
|
|
||||||
|
if((x > 0) && (y > 0)) {
|
||||||
|
data->point.x = x;
|
||||||
|
data->point.y = y;
|
||||||
|
last_x = data->point.x;
|
||||||
|
last_y = data->point.y;
|
||||||
|
data->state = LV_INDEV_STATE_PR;
|
||||||
|
} else {
|
||||||
|
data->point.x = last_x;
|
||||||
|
data->point.y = last_y;
|
||||||
|
data->state = LV_INDEV_STATE_REL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call periodically (e.g. in every 1 ms) to handle reading with ADC*/
|
||||||
|
int16_t ad_touch_handler(void)
|
||||||
|
{
|
||||||
|
static int16_t tempX, tempY;
|
||||||
|
int16_t temp;
|
||||||
|
|
||||||
|
switch(state) {
|
||||||
|
case IDLE:
|
||||||
|
adcX = 0;
|
||||||
|
adcY = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SET_VALUES:
|
||||||
|
if(!TOUCH_ADC_DONE)
|
||||||
|
break;
|
||||||
|
if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) {
|
||||||
|
adcX = 0;
|
||||||
|
adcY = 0;
|
||||||
|
} else {
|
||||||
|
adcX = tempX;
|
||||||
|
adcY = tempY;
|
||||||
|
}
|
||||||
|
state = SET_X;
|
||||||
|
return 1; // touch screen acquisition is done
|
||||||
|
|
||||||
|
case SET_X:
|
||||||
|
TOUCH_ADC_INPUT_SEL = ADC_XPOS;
|
||||||
|
|
||||||
|
ResistiveTouchScreen_XPlus_Config_As_Input();
|
||||||
|
ResistiveTouchScreen_YPlus_Config_As_Input();
|
||||||
|
ResistiveTouchScreen_XMinus_Config_As_Input();
|
||||||
|
ResistiveTouchScreen_YMinus_Drive_Low();
|
||||||
|
ResistiveTouchScreen_YMinus_Config_As_Output();
|
||||||
|
|
||||||
|
ADPCFG_YPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin
|
||||||
|
ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; // set to analog pin
|
||||||
|
|
||||||
|
TOUCH_ADC_START = 1; // run conversion
|
||||||
|
state = CHECK_X;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHECK_X:
|
||||||
|
case CHECK_Y:
|
||||||
|
|
||||||
|
if(TOUCH_ADC_DONE == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD > (WORD)ADC1BUF0) {
|
||||||
|
if(state == CHECK_X) {
|
||||||
|
ResistiveTouchScreen_YPlus_Drive_High();
|
||||||
|
ResistiveTouchScreen_YPlus_Config_As_Output();
|
||||||
|
tempX = 0;
|
||||||
|
state = RUN_X;
|
||||||
|
} else {
|
||||||
|
ResistiveTouchScreen_XPlus_Drive_High();
|
||||||
|
ResistiveTouchScreen_XPlus_Config_As_Output();
|
||||||
|
tempY = 0;
|
||||||
|
state = RUN_Y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
adcX = 0;
|
||||||
|
adcY = 0;
|
||||||
|
state = SET_X;
|
||||||
|
return 1; // touch screen acquisition is done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RUN_X:
|
||||||
|
case RUN_Y:
|
||||||
|
TOUCH_ADC_START = 1;
|
||||||
|
state = (state == RUN_X) ? GET_X : GET_Y;
|
||||||
|
// no break needed here since the next state is either GET_X or GET_Y
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_X:
|
||||||
|
case GET_Y:
|
||||||
|
if(!TOUCH_ADC_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
temp = ADC1BUF0;
|
||||||
|
if(state == GET_X) {
|
||||||
|
if(temp != tempX) {
|
||||||
|
tempX = temp;
|
||||||
|
state = RUN_X;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(temp != tempY) {
|
||||||
|
tempY = temp;
|
||||||
|
state = RUN_Y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state == GET_X)
|
||||||
|
ResistiveTouchScreen_YPlus_Config_As_Input();
|
||||||
|
else
|
||||||
|
ResistiveTouchScreen_XPlus_Config_As_Input();
|
||||||
|
TOUCH_ADC_START = 1;
|
||||||
|
state = (state == GET_X) ? SET_Y : SET_VALUES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SET_Y:
|
||||||
|
if(!TOUCH_ADC_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) {
|
||||||
|
adcX = 0;
|
||||||
|
adcY = 0;
|
||||||
|
state = SET_X;
|
||||||
|
return 1; // touch screen acquisition is done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TOUCH_ADC_INPUT_SEL = ADC_YPOS;
|
||||||
|
|
||||||
|
ResistiveTouchScreen_XPlus_Config_As_Input();
|
||||||
|
ResistiveTouchScreen_YPlus_Config_As_Input();
|
||||||
|
ResistiveTouchScreen_XMinus_Drive_Low();
|
||||||
|
ResistiveTouchScreen_XMinus_Config_As_Output();
|
||||||
|
ResistiveTouchScreen_YMinus_Config_As_Input();
|
||||||
|
|
||||||
|
ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; // set to analog pin
|
||||||
|
ADPCFG_XPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin
|
||||||
|
TOUCH_ADC_START = 1; // run conversion
|
||||||
|
state = CHECK_Y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
state = SET_X;
|
||||||
|
return 1; // touch screen acquisition is done
|
||||||
|
}
|
||||||
|
stat = state;
|
||||||
|
temp_x = adcX;
|
||||||
|
temp_y = adcY;
|
||||||
|
|
||||||
|
return 0; // touch screen acquisition is not done
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
static int16_t TouchGetX(void)
|
||||||
|
{
|
||||||
|
long result;
|
||||||
|
|
||||||
|
result = TouchGetRawX();
|
||||||
|
|
||||||
|
if(result > 0) {
|
||||||
|
result = (long)((((long)_trC * result) + _trD) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR);
|
||||||
|
|
||||||
|
}
|
||||||
|
return ((int16_t)result);
|
||||||
|
}
|
||||||
|
/********************************************************************/
|
||||||
|
static int16_t TouchGetRawX(void)
|
||||||
|
{
|
||||||
|
#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY
|
||||||
|
return adcY;
|
||||||
|
#else
|
||||||
|
return adcX;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
static int16_t TouchGetY(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
long result;
|
||||||
|
|
||||||
|
result = TouchGetRawY();
|
||||||
|
|
||||||
|
if(result > 0) {
|
||||||
|
result = (long)((((long)_trA * result) + (long)_trB) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR);
|
||||||
|
|
||||||
|
}
|
||||||
|
return ((int16_t)result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
static int16_t TouchGetRawY(void)
|
||||||
|
{
|
||||||
|
#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY
|
||||||
|
return adcX;
|
||||||
|
#else
|
||||||
|
return adcY;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void TouchCalculateCalPoints(void)
|
||||||
|
{
|
||||||
|
long trA, trB, trC, trD; // variables for the coefficients
|
||||||
|
long trAhold, trBhold, trChold, trDhold;
|
||||||
|
long test1, test2; // temp variables (must be signed type)
|
||||||
|
|
||||||
|
int16_t xPoint[SAMPLE_POINTS], yPoint[SAMPLE_POINTS];
|
||||||
|
|
||||||
|
yPoint[0] = yPoint[1] = CAL_Y_INSET;
|
||||||
|
yPoint[2] = yPoint[3] = (GetMaxY() - CAL_Y_INSET);
|
||||||
|
xPoint[0] = xPoint[3] = CAL_X_INSET;
|
||||||
|
xPoint[1] = xPoint[2] = (GetMaxX() - CAL_X_INSET);
|
||||||
|
|
||||||
|
// calculate points transfer functiona
|
||||||
|
// based on two simultaneous equations solve for the
|
||||||
|
// constants
|
||||||
|
|
||||||
|
// use sample points 1 and 4
|
||||||
|
// Dy1 = aTy1 + b; Dy4 = aTy4 + b
|
||||||
|
// Dx1 = cTx1 + d; Dy4 = aTy4 + b
|
||||||
|
|
||||||
|
test1 = (long)yPoint[0] - (long)yPoint[3];
|
||||||
|
test2 = (long)yRawTouch[0] - (long)yRawTouch[3];
|
||||||
|
|
||||||
|
trA = ((long)((long)test1 * SCALE_FACTOR) / test2);
|
||||||
|
trB = ((long)((long)yPoint[0] * SCALE_FACTOR) - (trA * (long)yRawTouch[0]));
|
||||||
|
|
||||||
|
test1 = (long)xPoint[0] - (long)xPoint[2];
|
||||||
|
test2 = (long)xRawTouch[0] - (long)xRawTouch[2];
|
||||||
|
|
||||||
|
trC = ((long)((long)test1 * SCALE_FACTOR) / test2);
|
||||||
|
trD = ((long)((long)xPoint[0] * SCALE_FACTOR) - (trC * (long)xRawTouch[0]));
|
||||||
|
|
||||||
|
trAhold = trA;
|
||||||
|
trBhold = trB;
|
||||||
|
trChold = trC;
|
||||||
|
trDhold = trD;
|
||||||
|
|
||||||
|
// use sample points 2 and 3
|
||||||
|
// Dy2 = aTy2 + b; Dy3 = aTy3 + b
|
||||||
|
// Dx2 = cTx2 + d; Dy3 = aTy3 + b
|
||||||
|
|
||||||
|
test1 = (long)yPoint[1] - (long)yPoint[2];
|
||||||
|
test2 = (long)yRawTouch[1] - (long)yRawTouch[2];
|
||||||
|
|
||||||
|
trA = ((long)(test1 * SCALE_FACTOR) / test2);
|
||||||
|
trB = ((long)((long)yPoint[1] * SCALE_FACTOR) - (trA * (long)yRawTouch[1]));
|
||||||
|
|
||||||
|
test1 = (long)xPoint[1] - (long)xPoint[3];
|
||||||
|
test2 = (long)xRawTouch[1] - (long)xRawTouch[3];
|
||||||
|
|
||||||
|
trC = ((long)((long)test1 * SCALE_FACTOR) / test2);
|
||||||
|
trD = ((long)((long)xPoint[1] * SCALE_FACTOR) - (trC * (long)xRawTouch[1]));
|
||||||
|
|
||||||
|
// get the average and use the average
|
||||||
|
_trA = (trA + trAhold) >> 1;
|
||||||
|
_trB = (trB + trBhold) >> 1;
|
||||||
|
_trC = (trC + trChold) >> 1;
|
||||||
|
_trD = (trD + trDhold) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* @file AD_touch.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AD_TOUCH_H
|
||||||
|
#define AD_TOUCH_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_AD_TOUCH
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _SUPPRESS_PLIB_WARNING
|
||||||
|
#include <plib.h>
|
||||||
|
|
||||||
|
#include "GenericTypeDefs.h"
|
||||||
|
|
||||||
|
#define DISP_ORIENTATION 0
|
||||||
|
#define DISP_HOR_RESOLUTION 320
|
||||||
|
#define DISP_VER_RESOLUTION 240
|
||||||
|
|
||||||
|
/*GetMaxX Macro*/
|
||||||
|
#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
|
||||||
|
#define GetMaxX() (DISP_VER_RESOLUTION - 1)
|
||||||
|
#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
|
||||||
|
#define GetMaxX() (DISP_HOR_RESOLUTION - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*GetMaxY Macro*/
|
||||||
|
#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
|
||||||
|
#define GetMaxY() (DISP_HOR_RESOLUTION - 1)
|
||||||
|
#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
|
||||||
|
#define GetMaxY() (DISP_VER_RESOLUTION - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* HARDWARE PROFILE FOR THE RESISTIVE TOUCHSCREEN
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#define TOUCH_ADC_INPUT_SEL AD1CHS
|
||||||
|
|
||||||
|
// ADC Sample Start
|
||||||
|
#define TOUCH_ADC_START AD1CON1bits.SAMP
|
||||||
|
|
||||||
|
// ADC Status
|
||||||
|
#define TOUCH_ADC_DONE AD1CON1bits.DONE
|
||||||
|
|
||||||
|
#define RESISTIVETOUCH_ANALOG 1
|
||||||
|
#define RESISTIVETOUCH_DIGITAL 0
|
||||||
|
|
||||||
|
// ADC channel constants
|
||||||
|
#define ADC_XPOS ADC_CH0_POS_SAMPLEA_AN12
|
||||||
|
#define ADC_YPOS ADC_CH0_POS_SAMPLEA_AN13
|
||||||
|
|
||||||
|
// ADC Port Control Bits
|
||||||
|
#define ADPCFG_XPOS AD1PCFGbits.PCFG12 //XR
|
||||||
|
#define ADPCFG_YPOS AD1PCFGbits.PCFG13 //YD
|
||||||
|
|
||||||
|
// X port definitions
|
||||||
|
#define ResistiveTouchScreen_XPlus_Drive_High() LATBbits.LATB12 = 1
|
||||||
|
#define ResistiveTouchScreen_XPlus_Drive_Low() LATBbits.LATB12 = 0 //LAT_XPOS
|
||||||
|
#define ResistiveTouchScreen_XPlus_Config_As_Input() TRISBbits.TRISB12 = 1 //TRIS_XPOS
|
||||||
|
#define ResistiveTouchScreen_XPlus_Config_As_Output() TRISBbits.TRISB12 = 0
|
||||||
|
|
||||||
|
#define ResistiveTouchScreen_XMinus_Drive_High() LATFbits.LATF0 = 1
|
||||||
|
#define ResistiveTouchScreen_XMinus_Drive_Low() LATFbits.LATF0 = 0 //LAT_XNEG
|
||||||
|
#define ResistiveTouchScreen_XMinus_Config_As_Input() TRISFbits.TRISF0 = 1 //TRIS_XNEG
|
||||||
|
#define ResistiveTouchScreen_XMinus_Config_As_Output() TRISFbits.TRISF0 = 0
|
||||||
|
|
||||||
|
// Y port definitions
|
||||||
|
#define ResistiveTouchScreen_YPlus_Drive_High() LATBbits.LATB13 = 1
|
||||||
|
#define ResistiveTouchScreen_YPlus_Drive_Low() LATBbits.LATB13 = 0 //LAT_YPOS
|
||||||
|
#define ResistiveTouchScreen_YPlus_Config_As_Input() TRISBbits.TRISB13 = 1 //TRIS_YPOS
|
||||||
|
#define ResistiveTouchScreen_YPlus_Config_As_Output() TRISBbits.TRISB13 = 0
|
||||||
|
|
||||||
|
#define ResistiveTouchScreen_YMinus_Drive_High() LATFbits.LATF1 = 1
|
||||||
|
#define ResistiveTouchScreen_YMinus_Drive_Low() LATFbits.LATF1 = 0 //LAT_YNEG
|
||||||
|
#define ResistiveTouchScreen_YMinus_Config_As_Input() TRISFbits.TRISF1 = 1 //TRIS_YNEG
|
||||||
|
#define ResistiveTouchScreen_YMinus_Config_As_Output() TRISFbits.TRISF1 = 0
|
||||||
|
|
||||||
|
// Default calibration points
|
||||||
|
#define TOUCHCAL_ULX 0x0348
|
||||||
|
#define TOUCHCAL_ULY 0x00CC
|
||||||
|
#define TOUCHCAL_URX 0x00D2
|
||||||
|
#define TOUCHCAL_URY 0x00CE
|
||||||
|
#define TOUCHCAL_LLX 0x034D
|
||||||
|
#define TOUCHCAL_LLY 0x0335
|
||||||
|
#define TOUCHCAL_LRX 0x00D6
|
||||||
|
#define TOUCHCAL_LRY 0x032D
|
||||||
|
|
||||||
|
void ad_touch_init(void);
|
||||||
|
bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
int16_t ad_touch_handler(void);
|
||||||
|
|
||||||
|
#endif /* USE_AD_TOUCH */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AD_TOUCH_H */
|
@ -0,0 +1,179 @@
|
|||||||
|
/**
|
||||||
|
* @file FT5406EE8.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "FT5406EE8.h"
|
||||||
|
#if USE_FT5406EE8
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include LV_DRV_INDEV_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#define I2C_WR_BIT 0x00
|
||||||
|
#define I2C_RD_BIT 0x01
|
||||||
|
|
||||||
|
/*DEVICE MODES*/
|
||||||
|
#define OPERAT_MD 0x00
|
||||||
|
#define TEST_MD 0x04
|
||||||
|
#define SYS_INF_MD 0x01
|
||||||
|
|
||||||
|
/*OPERATING MODE*/
|
||||||
|
#define DEVICE_MODE 0x00
|
||||||
|
#define GEST_ID 0x01
|
||||||
|
#define TD_STATUS 0x02
|
||||||
|
|
||||||
|
#define FT5406EE8_FINGER_MAX 10
|
||||||
|
|
||||||
|
/*Register addresses*/
|
||||||
|
#define FT5406EE8_REG_DEVICE_MODE 0x00
|
||||||
|
#define FT5406EE8_REG_GEST_ID 0x01
|
||||||
|
#define FT5406EE8_REG_TD_STATUS 0x02
|
||||||
|
#define FT5406EE8_REG_YH 0x03
|
||||||
|
#define FT5406EE8_REG_YL 0x04
|
||||||
|
#define FT5406EE8_REG_XH 0x05
|
||||||
|
#define FT5406EE8_REG_XL 0x06
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static bool ft5406ee8_get_touch_num(void);
|
||||||
|
static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ft5406ee8_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the touchpad
|
||||||
|
* @param data store the read data here
|
||||||
|
* @return false: because no ore data to be read
|
||||||
|
*/
|
||||||
|
bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
static int16_t x_last;
|
||||||
|
static int16_t y_last;
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
bool valid = true;
|
||||||
|
|
||||||
|
valid = ft5406ee8_get_touch_num();
|
||||||
|
if(valid == true) {
|
||||||
|
valid = ft5406ee8_read_finger1(&x, &y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(valid == true) {
|
||||||
|
x = (uint32_t)((uint32_t)x * 320) / 2048;
|
||||||
|
y = (uint32_t)((uint32_t)y * 240) / 2048;
|
||||||
|
|
||||||
|
|
||||||
|
x_last = x;
|
||||||
|
y_last = y;
|
||||||
|
} else {
|
||||||
|
x = x_last;
|
||||||
|
y = y_last;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->point.x = x;
|
||||||
|
data->point.y = y;
|
||||||
|
data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static bool ft5406ee8_get_touch_num(void)
|
||||||
|
{
|
||||||
|
bool ok = true;
|
||||||
|
uint8_t t_num = 0;
|
||||||
|
|
||||||
|
LV_DRV_INDEV_I2C_START;
|
||||||
|
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT);
|
||||||
|
LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_TD_STATUS)
|
||||||
|
LV_DRV_INDEV_I2C_RESTART;
|
||||||
|
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT);
|
||||||
|
t_num = LV_DRV_INDEV_I2C_READ(0);
|
||||||
|
|
||||||
|
/* Error if not touched or too much finger */
|
||||||
|
if(t_num > FT5406EE8_FINGER_MAX || t_num == 0) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the x and y coordinated
|
||||||
|
* @param x store the x coordinate here
|
||||||
|
* @param y store the y coordinate here
|
||||||
|
* @return false: not valid point; true: valid point
|
||||||
|
*/
|
||||||
|
static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y)
|
||||||
|
{
|
||||||
|
uint8_t temp_xH = 0;
|
||||||
|
uint8_t temp_xL = 0;
|
||||||
|
uint8_t temp_yH = 0;
|
||||||
|
uint8_t temp_yL = 0;
|
||||||
|
|
||||||
|
/*Read Y High and low byte*/
|
||||||
|
LV_DRV_INDEV_I2C_START;
|
||||||
|
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT);
|
||||||
|
LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_YH)
|
||||||
|
LV_DRV_INDEV_I2C_RESTART;
|
||||||
|
LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT);
|
||||||
|
temp_yH = LV_DRV_INDEV_I2C_READ(1);
|
||||||
|
temp_yL = LV_DRV_INDEV_I2C_READ(1);
|
||||||
|
|
||||||
|
/*The upper two bit must be 2 on valid press*/
|
||||||
|
if(((temp_yH >> 6) & 0xFF) != 2) {
|
||||||
|
(void) LV_DRV_INDEV_I2C_READ(0); /*Dummy read to close read sequence*/
|
||||||
|
*x = 0;
|
||||||
|
*y = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Read X High and low byte*/
|
||||||
|
temp_xH = LV_DRV_INDEV_I2C_READ(1);
|
||||||
|
temp_xL = LV_DRV_INDEV_I2C_READ(0);
|
||||||
|
|
||||||
|
/*Save the result*/
|
||||||
|
*x = (temp_xH & 0x0F) << 8;
|
||||||
|
*x += temp_xL;
|
||||||
|
*y = (temp_yH & 0x0F) << 8;
|
||||||
|
*y += temp_yL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* @file FT5406EE8.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FT5406EE8_H
|
||||||
|
#define FT5406EE8_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_FT5406EE8
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void ft5406ee8_init(void);
|
||||||
|
bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_FT5406EE8 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FT5406EE8_H */
|
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* @file XPT2046.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "XPT2046.h"
|
||||||
|
#if USE_XPT2046
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include LV_DRV_INDEV_INCLUDE
|
||||||
|
#include LV_DRV_DELAY_INCLUDE
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define CMD_X_READ 0b10010000
|
||||||
|
#define CMD_Y_READ 0b11010000
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void xpt2046_corr(int16_t * x, int16_t * y);
|
||||||
|
static void xpt2046_avg(int16_t * x, int16_t * y);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
int16_t avg_buf_x[XPT2046_AVG];
|
||||||
|
int16_t avg_buf_y[XPT2046_AVG];
|
||||||
|
uint8_t avg_last;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the XPT2046
|
||||||
|
*/
|
||||||
|
void xpt2046_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the touchpad
|
||||||
|
* @param data store the read data here
|
||||||
|
* @return false: because no ore data to be read
|
||||||
|
*/
|
||||||
|
bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
static int16_t last_x = 0;
|
||||||
|
static int16_t last_y = 0;
|
||||||
|
uint8_t buf;
|
||||||
|
|
||||||
|
int16_t x = 0;
|
||||||
|
int16_t y = 0;
|
||||||
|
|
||||||
|
uint8_t irq = LV_DRV_INDEV_IRQ_READ;
|
||||||
|
|
||||||
|
if(irq == 0) {
|
||||||
|
LV_DRV_INDEV_SPI_CS(0);
|
||||||
|
|
||||||
|
LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_X_READ); /*Start x read*/
|
||||||
|
|
||||||
|
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read x MSB*/
|
||||||
|
x = buf << 8;
|
||||||
|
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_Y_READ); /*Until x LSB converted y command can be sent*/
|
||||||
|
x += buf;
|
||||||
|
|
||||||
|
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y MSB*/
|
||||||
|
y = buf << 8;
|
||||||
|
|
||||||
|
buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y LSB*/
|
||||||
|
y += buf;
|
||||||
|
|
||||||
|
/*Normalize Data*/
|
||||||
|
x = x >> 3;
|
||||||
|
y = y >> 3;
|
||||||
|
xpt2046_corr(&x, &y);
|
||||||
|
xpt2046_avg(&x, &y);
|
||||||
|
|
||||||
|
last_x = x;
|
||||||
|
last_y = y;
|
||||||
|
data->state = LV_INDEV_STATE_PR;
|
||||||
|
|
||||||
|
LV_DRV_INDEV_SPI_CS(1);
|
||||||
|
} else {
|
||||||
|
x = last_x;
|
||||||
|
y = last_y;
|
||||||
|
avg_last = 0;
|
||||||
|
data->state = LV_INDEV_STATE_REL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->point.x = x;
|
||||||
|
data->point.y = y;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
static void xpt2046_corr(int16_t * x, int16_t * y)
|
||||||
|
{
|
||||||
|
#if XPT2046_XY_SWAP != 0
|
||||||
|
int16_t swap_tmp;
|
||||||
|
swap_tmp = *x;
|
||||||
|
*x = *y;
|
||||||
|
*y = swap_tmp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if((*x) > XPT2046_X_MIN)(*x) -= XPT2046_X_MIN;
|
||||||
|
else(*x) = 0;
|
||||||
|
|
||||||
|
if((*y) > XPT2046_Y_MIN)(*y) -= XPT2046_Y_MIN;
|
||||||
|
else(*y) = 0;
|
||||||
|
|
||||||
|
(*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) /
|
||||||
|
(XPT2046_X_MAX - XPT2046_X_MIN);
|
||||||
|
|
||||||
|
(*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) /
|
||||||
|
(XPT2046_Y_MAX - XPT2046_Y_MIN);
|
||||||
|
|
||||||
|
#if XPT2046_X_INV != 0
|
||||||
|
(*x) = XPT2046_HOR_RES - (*x);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if XPT2046_Y_INV != 0
|
||||||
|
(*y) = XPT2046_VER_RES - (*y);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void xpt2046_avg(int16_t * x, int16_t * y)
|
||||||
|
{
|
||||||
|
/*Shift out the oldest data*/
|
||||||
|
uint8_t i;
|
||||||
|
for(i = XPT2046_AVG - 1; i > 0 ; i--) {
|
||||||
|
avg_buf_x[i] = avg_buf_x[i - 1];
|
||||||
|
avg_buf_y[i] = avg_buf_y[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Insert the new point*/
|
||||||
|
avg_buf_x[0] = *x;
|
||||||
|
avg_buf_y[0] = *y;
|
||||||
|
if(avg_last < XPT2046_AVG) avg_last++;
|
||||||
|
|
||||||
|
/*Sum the x and y coordinates*/
|
||||||
|
int32_t x_sum = 0;
|
||||||
|
int32_t y_sum = 0;
|
||||||
|
for(i = 0; i < avg_last ; i++) {
|
||||||
|
x_sum += avg_buf_x[i];
|
||||||
|
y_sum += avg_buf_y[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Normalize the sums*/
|
||||||
|
(*x) = (int32_t)x_sum / avg_last;
|
||||||
|
(*y) = (int32_t)y_sum / avg_last;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* @file XPT2046.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XPT2046_H
|
||||||
|
#define XPT2046_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_XPT2046
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void xpt2046_init(void);
|
||||||
|
bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_XPT2046 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* XPT2046_H */
|
@ -0,0 +1,251 @@
|
|||||||
|
/**
|
||||||
|
* @file evdev.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "evdev.h"
|
||||||
|
#if USE_EVDEV != 0 || USE_BSD_EVDEV
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#if USE_BSD_EVDEV
|
||||||
|
#include <dev/evdev/input.h>
|
||||||
|
#else
|
||||||
|
#include <linux/input.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_XKB
|
||||||
|
#include "xkb.h"
|
||||||
|
#endif /* USE_XKB */
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
int map(int x, int in_min, int in_max, int out_min, int out_max);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
int evdev_fd = -1;
|
||||||
|
int evdev_root_x;
|
||||||
|
int evdev_root_y;
|
||||||
|
int evdev_button;
|
||||||
|
|
||||||
|
int evdev_key_val;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the evdev interface
|
||||||
|
*/
|
||||||
|
void evdev_init(void)
|
||||||
|
{
|
||||||
|
if (!evdev_set_file(EVDEV_NAME)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_XKB
|
||||||
|
xkb_init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* reconfigure the device file for evdev
|
||||||
|
* @param dev_name set the evdev device filename
|
||||||
|
* @return true: the device file set complete
|
||||||
|
* false: the device file doesn't exist current system
|
||||||
|
*/
|
||||||
|
bool evdev_set_file(char* dev_name)
|
||||||
|
{
|
||||||
|
if(evdev_fd != -1) {
|
||||||
|
close(evdev_fd);
|
||||||
|
}
|
||||||
|
#if USE_BSD_EVDEV
|
||||||
|
evdev_fd = open(dev_name, O_RDWR | O_NOCTTY);
|
||||||
|
#else
|
||||||
|
evdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(evdev_fd == -1) {
|
||||||
|
perror("unable to open evdev interface:");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_BSD_EVDEV
|
||||||
|
fcntl(evdev_fd, F_SETFL, O_NONBLOCK);
|
||||||
|
#else
|
||||||
|
fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
evdev_root_x = 0;
|
||||||
|
evdev_root_y = 0;
|
||||||
|
evdev_key_val = 0;
|
||||||
|
evdev_button = LV_INDEV_STATE_REL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the evdev
|
||||||
|
* @param data store the evdev data here
|
||||||
|
*/
|
||||||
|
void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
struct input_event in;
|
||||||
|
|
||||||
|
while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {
|
||||||
|
if(in.type == EV_REL) {
|
||||||
|
if(in.code == REL_X)
|
||||||
|
#if EVDEV_SWAP_AXES
|
||||||
|
evdev_root_y += in.value;
|
||||||
|
#else
|
||||||
|
evdev_root_x += in.value;
|
||||||
|
#endif
|
||||||
|
else if(in.code == REL_Y)
|
||||||
|
#if EVDEV_SWAP_AXES
|
||||||
|
evdev_root_x += in.value;
|
||||||
|
#else
|
||||||
|
evdev_root_y += in.value;
|
||||||
|
#endif
|
||||||
|
} else if(in.type == EV_ABS) {
|
||||||
|
if(in.code == ABS_X)
|
||||||
|
#if EVDEV_SWAP_AXES
|
||||||
|
evdev_root_y = in.value;
|
||||||
|
#else
|
||||||
|
evdev_root_x = in.value;
|
||||||
|
#endif
|
||||||
|
else if(in.code == ABS_Y)
|
||||||
|
#if EVDEV_SWAP_AXES
|
||||||
|
evdev_root_x = in.value;
|
||||||
|
#else
|
||||||
|
evdev_root_y = in.value;
|
||||||
|
#endif
|
||||||
|
else if(in.code == ABS_MT_POSITION_X)
|
||||||
|
#if EVDEV_SWAP_AXES
|
||||||
|
evdev_root_y = in.value;
|
||||||
|
#else
|
||||||
|
evdev_root_x = in.value;
|
||||||
|
#endif
|
||||||
|
else if(in.code == ABS_MT_POSITION_Y)
|
||||||
|
#if EVDEV_SWAP_AXES
|
||||||
|
evdev_root_x = in.value;
|
||||||
|
#else
|
||||||
|
evdev_root_y = in.value;
|
||||||
|
#endif
|
||||||
|
else if(in.code == ABS_MT_TRACKING_ID) {
|
||||||
|
if(in.value == -1)
|
||||||
|
evdev_button = LV_INDEV_STATE_REL;
|
||||||
|
else if(in.value == 0)
|
||||||
|
evdev_button = LV_INDEV_STATE_PR;
|
||||||
|
}
|
||||||
|
} else if(in.type == EV_KEY) {
|
||||||
|
if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) {
|
||||||
|
if(in.value == 0)
|
||||||
|
evdev_button = LV_INDEV_STATE_REL;
|
||||||
|
else if(in.value == 1)
|
||||||
|
evdev_button = LV_INDEV_STATE_PR;
|
||||||
|
} else if(drv->type == LV_INDEV_TYPE_KEYPAD) {
|
||||||
|
#if USE_XKB
|
||||||
|
data->key = xkb_process_key(in.code, in.value != 0);
|
||||||
|
#else
|
||||||
|
switch(in.code) {
|
||||||
|
case KEY_BACKSPACE:
|
||||||
|
data->key = LV_KEY_BACKSPACE;
|
||||||
|
break;
|
||||||
|
case KEY_ENTER:
|
||||||
|
data->key = LV_KEY_ENTER;
|
||||||
|
break;
|
||||||
|
case KEY_PREVIOUS:
|
||||||
|
data->key = LV_KEY_PREV;
|
||||||
|
break;
|
||||||
|
case KEY_NEXT:
|
||||||
|
data->key = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
data->key = LV_KEY_UP;
|
||||||
|
break;
|
||||||
|
case KEY_LEFT:
|
||||||
|
data->key = LV_KEY_LEFT;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT:
|
||||||
|
data->key = LV_KEY_RIGHT;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
data->key = LV_KEY_DOWN;
|
||||||
|
break;
|
||||||
|
case KEY_TAB:
|
||||||
|
data->key = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
data->key = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* USE_XKB */
|
||||||
|
if (data->key != 0) {
|
||||||
|
/* Only record button state when actual output is produced to prevent widgets from refreshing */
|
||||||
|
data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
|
||||||
|
}
|
||||||
|
evdev_key_val = data->key;
|
||||||
|
evdev_button = data->state;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(drv->type == LV_INDEV_TYPE_KEYPAD) {
|
||||||
|
/* No data retrieved */
|
||||||
|
data->key = evdev_key_val;
|
||||||
|
data->state = evdev_button;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(drv->type != LV_INDEV_TYPE_POINTER)
|
||||||
|
return ;
|
||||||
|
/*Store the collected data*/
|
||||||
|
|
||||||
|
#if EVDEV_CALIBRATE
|
||||||
|
data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, drv->disp->driver->hor_res);
|
||||||
|
data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, drv->disp->driver->ver_res);
|
||||||
|
#else
|
||||||
|
data->point.x = evdev_root_x;
|
||||||
|
data->point.y = evdev_root_y;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
data->state = evdev_button;
|
||||||
|
|
||||||
|
if(data->point.x < 0)
|
||||||
|
data->point.x = 0;
|
||||||
|
if(data->point.y < 0)
|
||||||
|
data->point.y = 0;
|
||||||
|
if(data->point.x >= drv->disp->driver->hor_res)
|
||||||
|
data->point.x = drv->disp->driver->hor_res - 1;
|
||||||
|
if(data->point.y >= drv->disp->driver->ver_res)
|
||||||
|
data->point.y = drv->disp->driver->ver_res - 1;
|
||||||
|
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
int map(int x, int in_min, int in_max, int out_min, int out_max)
|
||||||
|
{
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* @file evdev.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EVDEV_H
|
||||||
|
#define EVDEV_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_EVDEV || USE_BSD_EVDEV
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the evdev
|
||||||
|
*/
|
||||||
|
void evdev_init(void);
|
||||||
|
/**
|
||||||
|
* reconfigure the device file for evdev
|
||||||
|
* @param dev_name set the evdev device filename
|
||||||
|
* @return true: the device file set complete
|
||||||
|
* false: the device file doesn't exist current system
|
||||||
|
*/
|
||||||
|
bool evdev_set_file(char* dev_name);
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the evdev
|
||||||
|
* @param data store the evdev data here
|
||||||
|
*/
|
||||||
|
void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_EVDEV */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EVDEV_H */
|
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* @file keyboard.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEYBOARD_H
|
||||||
|
#define KEYBOARD_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_KEYBOARD
|
||||||
|
|
||||||
|
#warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SDL_GPU
|
||||||
|
#include "../sdl/sdl_gpu.h"
|
||||||
|
#else
|
||||||
|
#include "../sdl/sdl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the keyboard
|
||||||
|
*/
|
||||||
|
static inline void keyboard_init(void)
|
||||||
|
{
|
||||||
|
/*Nothing to do*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last pressed or released character from the PC's keyboard
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the read data here
|
||||||
|
*/
|
||||||
|
static inline void keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
sdl_keyboard_read(indev_drv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*USE_KEYBOARD*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*KEYBOARD_H*/
|
@ -0,0 +1,491 @@
|
|||||||
|
/**
|
||||||
|
* @file libinput.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "libinput_drv.h"
|
||||||
|
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <libinput.h>
|
||||||
|
|
||||||
|
#if USE_BSD_LIBINPUT
|
||||||
|
#include <dev/evdev/input.h>
|
||||||
|
#else
|
||||||
|
#include <linux/input.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
struct input_device {
|
||||||
|
libinput_capability capabilities;
|
||||||
|
char *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static bool rescan_devices(void);
|
||||||
|
static bool add_scanned_device(char *path, libinput_capability capabilities);
|
||||||
|
static void reset_scanned_devices(void);
|
||||||
|
|
||||||
|
static void read_pointer(libinput_drv_state_t *state, struct libinput_event *event);
|
||||||
|
static void read_keypad(libinput_drv_state_t *state, struct libinput_event *event);
|
||||||
|
|
||||||
|
static int open_restricted(const char *path, int flags, void *user_data);
|
||||||
|
static void close_restricted(int fd, void *user_data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static struct input_device *devices = NULL;
|
||||||
|
static size_t num_devices = 0;
|
||||||
|
|
||||||
|
static libinput_drv_state_t default_state = { .most_recent_touch_point = { .x = 0, .y = 0 } };
|
||||||
|
|
||||||
|
static const int timeout = 0; // do not block
|
||||||
|
static const nfds_t nfds = 1;
|
||||||
|
|
||||||
|
static const struct libinput_interface interface = {
|
||||||
|
.open_restricted = open_restricted,
|
||||||
|
.close_restricted = close_restricted,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find connected input device with specific capabilities
|
||||||
|
* @param capabilities required device capabilities
|
||||||
|
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
|
||||||
|
* @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found.
|
||||||
|
* The pointer is safe to use until the next forceful device search.
|
||||||
|
*/
|
||||||
|
char *libinput_find_dev(libinput_capability capabilities, bool force_rescan) {
|
||||||
|
char *path = NULL;
|
||||||
|
libinput_find_devs(capabilities, &path, 1, force_rescan);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find connected input devices with specific capabilities
|
||||||
|
* @param capabilities required device capabilities
|
||||||
|
* @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are
|
||||||
|
* safe to use until the next forceful device search.
|
||||||
|
* @param count maximum number of devices to find (the devices array should be at least this long)
|
||||||
|
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
|
||||||
|
* @return number of devices that were found
|
||||||
|
*/
|
||||||
|
size_t libinput_find_devs(libinput_capability capabilities, char **found, size_t count, bool force_rescan) {
|
||||||
|
if ((!devices || force_rescan) && !rescan_devices()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t num_found = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_devices && num_found < count; ++i) {
|
||||||
|
if (devices[i].capabilities & capabilities) {
|
||||||
|
found[num_found] = devices[i].path;
|
||||||
|
num_found++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconfigure the device file for libinput using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
* @param dev_name input device node path (e.g. /dev/input/event0)
|
||||||
|
* @return true: the device file set complete
|
||||||
|
* false: the device file doesn't exist current system
|
||||||
|
*/
|
||||||
|
bool libinput_set_file(char* dev_name)
|
||||||
|
{
|
||||||
|
return libinput_set_file_state(&default_state, dev_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconfigure the device file for libinput using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state the driver state to configure
|
||||||
|
* @param dev_name input device node path (e.g. /dev/input/event0)
|
||||||
|
* @return true: the device file set complete
|
||||||
|
* false: the device file doesn't exist current system
|
||||||
|
*/
|
||||||
|
bool libinput_set_file_state(libinput_drv_state_t *state, char* dev_name)
|
||||||
|
{
|
||||||
|
// This check *should* not be necessary, yet applications crashes even on NULL handles.
|
||||||
|
// citing libinput.h:libinput_path_remove_device:
|
||||||
|
// > If no matching device exists, this function does nothing.
|
||||||
|
if (state->libinput_device) {
|
||||||
|
state->libinput_device = libinput_device_unref(state->libinput_device);
|
||||||
|
libinput_path_remove_device(state->libinput_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->libinput_device = libinput_path_add_device(state->libinput_context, dev_name);
|
||||||
|
if(!state->libinput_device) {
|
||||||
|
perror("unable to add device to libinput context:");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state->libinput_device = libinput_device_ref(state->libinput_device);
|
||||||
|
if(!state->libinput_device) {
|
||||||
|
perror("unable to reference device within libinput context:");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->button = LV_INDEV_STATE_REL;
|
||||||
|
state->key_val = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare for reading input via libinput using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
*/
|
||||||
|
void libinput_init(void)
|
||||||
|
{
|
||||||
|
libinput_init_state(&default_state, LIBINPUT_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare for reading input via libinput using the a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state driver state to initialize
|
||||||
|
* @param path input device node path (e.g. /dev/input/event0)
|
||||||
|
*/
|
||||||
|
void libinput_init_state(libinput_drv_state_t *state, char* path)
|
||||||
|
{
|
||||||
|
state->libinput_device = NULL;
|
||||||
|
state->libinput_context = libinput_path_create_context(&interface, NULL);
|
||||||
|
|
||||||
|
if(path == NULL || !libinput_set_file_state(state, path)) {
|
||||||
|
fprintf(stderr, "unable to add device \"%s\" to libinput context: %s\n", path ? path : "NULL", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state->fd = libinput_get_fd(state->libinput_context);
|
||||||
|
|
||||||
|
/* prepare poll */
|
||||||
|
state->fds[0].fd = state->fd;
|
||||||
|
state->fds[0].events = POLLIN;
|
||||||
|
state->fds[0].revents = 0;
|
||||||
|
|
||||||
|
#if USE_XKB
|
||||||
|
xkb_init_state(&(state->xkb_state));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read available input events via libinput using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
* @param indev_drv driver object itself
|
||||||
|
* @param data store the libinput data here
|
||||||
|
*/
|
||||||
|
void libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
libinput_read_state(&default_state, indev_drv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read available input events via libinput using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state the driver state to use
|
||||||
|
* @param indev_drv driver object itself
|
||||||
|
* @param data store the libinput data here
|
||||||
|
*/
|
||||||
|
void libinput_read_state(libinput_drv_state_t * state, lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
struct libinput_event *event;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
rc = poll(state->fds, nfds, timeout);
|
||||||
|
switch (rc){
|
||||||
|
case -1:
|
||||||
|
perror(NULL);
|
||||||
|
case 0:
|
||||||
|
goto report_most_recent_state;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
libinput_dispatch(state->libinput_context);
|
||||||
|
while((event = libinput_get_event(state->libinput_context)) != NULL) {
|
||||||
|
switch (indev_drv->type) {
|
||||||
|
case LV_INDEV_TYPE_POINTER:
|
||||||
|
read_pointer(state, event);
|
||||||
|
break;
|
||||||
|
case LV_INDEV_TYPE_KEYPAD:
|
||||||
|
read_keypad(state, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
libinput_event_destroy(event);
|
||||||
|
}
|
||||||
|
report_most_recent_state:
|
||||||
|
data->point.x = state->most_recent_touch_point.x;
|
||||||
|
data->point.y = state->most_recent_touch_point.y;
|
||||||
|
data->state = state->button;
|
||||||
|
data->key = state->key_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rescan all attached evdev devices and store capable ones into the static devices array for quick later filtering
|
||||||
|
* @return true if the operation succeeded
|
||||||
|
*/
|
||||||
|
static bool rescan_devices(void) {
|
||||||
|
reset_scanned_devices();
|
||||||
|
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
if (!(dir = opendir("/dev/input"))) {
|
||||||
|
perror("unable to open directory /dev/input");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct libinput *context = libinput_path_create_context(&interface, NULL);
|
||||||
|
|
||||||
|
while ((ent = readdir(dir))) {
|
||||||
|
if (strncmp(ent->d_name, "event", 5) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 11 characters for /dev/input/ + length of name + 1 NUL terminator */
|
||||||
|
char *path = malloc((11 + strlen(ent->d_name) + 1) * sizeof(char));
|
||||||
|
if (!path) {
|
||||||
|
perror("could not allocate memory for device node path");
|
||||||
|
libinput_unref(context);
|
||||||
|
reset_scanned_devices();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
strcpy(path, "/dev/input/");
|
||||||
|
strcat(path, ent->d_name);
|
||||||
|
|
||||||
|
struct libinput_device *device = libinput_path_add_device(context, path);
|
||||||
|
if(!device) {
|
||||||
|
perror("unable to add device to libinput context");
|
||||||
|
free(path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The device pointer is guaranteed to be valid until the next libinput_dispatch. Since we're not dispatching events
|
||||||
|
* as part of this function, we don't have to increase its reference count to keep it alive.
|
||||||
|
* https://wayland.freedesktop.org/libinput/doc/latest/api/group__base.html#gaa797496f0150b482a4e01376bd33a47b */
|
||||||
|
|
||||||
|
libinput_capability capabilities = LIBINPUT_CAPABILITY_NONE;
|
||||||
|
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)
|
||||||
|
&& (libinput_device_keyboard_has_key(device, KEY_ENTER) || libinput_device_keyboard_has_key(device, KEY_KPENTER)))
|
||||||
|
{
|
||||||
|
capabilities |= LIBINPUT_CAPABILITY_KEYBOARD;
|
||||||
|
}
|
||||||
|
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
|
||||||
|
capabilities |= LIBINPUT_CAPABILITY_POINTER;
|
||||||
|
}
|
||||||
|
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) {
|
||||||
|
capabilities |= LIBINPUT_CAPABILITY_TOUCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
libinput_path_remove_device(device);
|
||||||
|
|
||||||
|
if (capabilities == LIBINPUT_CAPABILITY_NONE) {
|
||||||
|
free(path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!add_scanned_device(path, capabilities)) {
|
||||||
|
free(path);
|
||||||
|
libinput_unref(context);
|
||||||
|
reset_scanned_devices();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libinput_unref(context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a new scanned device to the static devices array, growing its size when necessary
|
||||||
|
* @param path device file path
|
||||||
|
* @param capabilities device input capabilities
|
||||||
|
* @return true if the operation succeeded
|
||||||
|
*/
|
||||||
|
static bool add_scanned_device(char *path, libinput_capability capabilities) {
|
||||||
|
/* Double array size every 2^n elements */
|
||||||
|
if ((num_devices & (num_devices + 1)) == 0) {
|
||||||
|
struct input_device *tmp = realloc(devices, (2 * num_devices + 1) * sizeof(struct input_device));
|
||||||
|
if (!tmp) {
|
||||||
|
perror("could not reallocate memory for devices array");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
devices = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
devices[num_devices].path = path;
|
||||||
|
devices[num_devices].capabilities = capabilities;
|
||||||
|
num_devices++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reset the array of scanned devices and free any dynamically allocated memory
|
||||||
|
*/
|
||||||
|
static void reset_scanned_devices(void) {
|
||||||
|
if (!devices) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_devices; ++i) {
|
||||||
|
free(devices[i].path);
|
||||||
|
}
|
||||||
|
free(devices);
|
||||||
|
|
||||||
|
devices = NULL;
|
||||||
|
num_devices = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle libinput touch / pointer events
|
||||||
|
* @param state driver state to use
|
||||||
|
* @param event libinput event
|
||||||
|
*/
|
||||||
|
static void read_pointer(libinput_drv_state_t *state, struct libinput_event *event) {
|
||||||
|
struct libinput_event_touch *touch_event = NULL;
|
||||||
|
struct libinput_event_pointer *pointer_event = NULL;
|
||||||
|
enum libinput_event_type type = libinput_event_get_type(event);
|
||||||
|
|
||||||
|
/* We need to read unrotated display dimensions directly from the driver because libinput won't account
|
||||||
|
* for any rotation inside of LVGL */
|
||||||
|
lv_disp_drv_t *drv = lv_disp_get_default()->driver;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case LIBINPUT_EVENT_TOUCH_MOTION:
|
||||||
|
case LIBINPUT_EVENT_TOUCH_DOWN:
|
||||||
|
touch_event = libinput_event_get_touch_event(event);
|
||||||
|
lv_coord_t x = libinput_event_touch_get_x_transformed(touch_event, drv->physical_hor_res > 0 ? drv->physical_hor_res : drv->hor_res) - drv->offset_x;
|
||||||
|
lv_coord_t y = libinput_event_touch_get_y_transformed(touch_event, drv->physical_ver_res > 0 ? drv->physical_ver_res : drv->ver_res) - drv->offset_y;
|
||||||
|
if (x < 0 || x > drv->hor_res || y < 0 || y > drv->ver_res) {
|
||||||
|
break; /* ignore touches that are out of bounds */
|
||||||
|
}
|
||||||
|
state->most_recent_touch_point.x = x;
|
||||||
|
state->most_recent_touch_point.y = y;
|
||||||
|
state->button = LV_INDEV_STATE_PR;
|
||||||
|
break;
|
||||||
|
case LIBINPUT_EVENT_TOUCH_UP:
|
||||||
|
state->button = LV_INDEV_STATE_REL;
|
||||||
|
break;
|
||||||
|
case LIBINPUT_EVENT_POINTER_MOTION:
|
||||||
|
pointer_event = libinput_event_get_pointer_event(event);
|
||||||
|
state->most_recent_touch_point.x += libinput_event_pointer_get_dx(pointer_event);
|
||||||
|
state->most_recent_touch_point.y += libinput_event_pointer_get_dy(pointer_event);
|
||||||
|
state->most_recent_touch_point.x = LV_CLAMP(0, state->most_recent_touch_point.x, drv->hor_res - 1);
|
||||||
|
state->most_recent_touch_point.y = LV_CLAMP(0, state->most_recent_touch_point.y, drv->ver_res - 1);
|
||||||
|
break;
|
||||||
|
case LIBINPUT_EVENT_POINTER_BUTTON:
|
||||||
|
pointer_event = libinput_event_get_pointer_event(event);
|
||||||
|
enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event);
|
||||||
|
state->button = button_state == LIBINPUT_BUTTON_STATE_RELEASED ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle libinput keyboard events
|
||||||
|
* @param state driver state to use
|
||||||
|
* @param event libinput event
|
||||||
|
*/
|
||||||
|
static void read_keypad(libinput_drv_state_t *state, struct libinput_event *event) {
|
||||||
|
struct libinput_event_keyboard *keyboard_event = NULL;
|
||||||
|
enum libinput_event_type type = libinput_event_get_type(event);
|
||||||
|
switch (type) {
|
||||||
|
case LIBINPUT_EVENT_KEYBOARD_KEY:
|
||||||
|
keyboard_event = libinput_event_get_keyboard_event(event);
|
||||||
|
enum libinput_key_state key_state = libinput_event_keyboard_get_key_state(keyboard_event);
|
||||||
|
uint32_t code = libinput_event_keyboard_get_key(keyboard_event);
|
||||||
|
#if USE_XKB
|
||||||
|
state->key_val = xkb_process_key_state(&(state->xkb_state), code, key_state == LIBINPUT_KEY_STATE_PRESSED);
|
||||||
|
#else
|
||||||
|
switch(code) {
|
||||||
|
case KEY_BACKSPACE:
|
||||||
|
state->key_val = LV_KEY_BACKSPACE;
|
||||||
|
break;
|
||||||
|
case KEY_ENTER:
|
||||||
|
state->key_val = LV_KEY_ENTER;
|
||||||
|
break;
|
||||||
|
case KEY_PREVIOUS:
|
||||||
|
state->key_val = LV_KEY_PREV;
|
||||||
|
break;
|
||||||
|
case KEY_NEXT:
|
||||||
|
state->key_val = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
state->key_val = LV_KEY_UP;
|
||||||
|
break;
|
||||||
|
case KEY_LEFT:
|
||||||
|
state->key_val = LV_KEY_LEFT;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT:
|
||||||
|
state->key_val = LV_KEY_RIGHT;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
state->key_val = LV_KEY_DOWN;
|
||||||
|
break;
|
||||||
|
case KEY_TAB:
|
||||||
|
state->key_val = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state->key_val = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* USE_XKB */
|
||||||
|
if (state->key_val != 0) {
|
||||||
|
/* Only record button state when actual output is produced to prevent widgets from refreshing */
|
||||||
|
state->button = (key_state == LIBINPUT_KEY_STATE_RELEASED) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_restricted(const char *path, int flags, void *user_data)
|
||||||
|
{
|
||||||
|
LV_UNUSED(user_data);
|
||||||
|
int fd = open(path, flags);
|
||||||
|
return fd < 0 ? -errno : fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_restricted(int fd, void *user_data)
|
||||||
|
{
|
||||||
|
LV_UNUSED(user_data);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
|
@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* @file libinput.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LVGL_LIBINPUT_H
|
||||||
|
#define LVGL_LIBINPUT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
#if USE_XKB
|
||||||
|
#include "xkb.h"
|
||||||
|
#endif /* USE_XKB */
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
typedef enum {
|
||||||
|
LIBINPUT_CAPABILITY_NONE = 0,
|
||||||
|
LIBINPUT_CAPABILITY_KEYBOARD = 1U << 0,
|
||||||
|
LIBINPUT_CAPABILITY_POINTER = 1U << 1,
|
||||||
|
LIBINPUT_CAPABILITY_TOUCH = 1U << 2
|
||||||
|
} libinput_capability;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fd;
|
||||||
|
struct pollfd fds[1];
|
||||||
|
|
||||||
|
int button;
|
||||||
|
int key_val;
|
||||||
|
lv_point_t most_recent_touch_point;
|
||||||
|
|
||||||
|
struct libinput *libinput_context;
|
||||||
|
struct libinput_device *libinput_device;
|
||||||
|
|
||||||
|
#if USE_XKB
|
||||||
|
xkb_drv_state_t xkb_state;
|
||||||
|
#endif /* USE_XKB */
|
||||||
|
} libinput_drv_state_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find connected input device with specific capabilities
|
||||||
|
* @param capabilities required device capabilities
|
||||||
|
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
|
||||||
|
* @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found.
|
||||||
|
* The pointer is safe to use until the next forceful device search.
|
||||||
|
*/
|
||||||
|
char *libinput_find_dev(libinput_capability capabilities, bool force_rescan);
|
||||||
|
/**
|
||||||
|
* find connected input devices with specific capabilities
|
||||||
|
* @param capabilities required device capabilities
|
||||||
|
* @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are
|
||||||
|
* safe to use until the next forceful device search.
|
||||||
|
* @param count maximum number of devices to find (the devices array should be at least this long)
|
||||||
|
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices
|
||||||
|
* @return number of devices that were found
|
||||||
|
*/
|
||||||
|
size_t libinput_find_devs(libinput_capability capabilities, char **found, size_t count, bool force_rescan);
|
||||||
|
/**
|
||||||
|
* Prepare for reading input via libinput using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
*/
|
||||||
|
void libinput_init(void);
|
||||||
|
/**
|
||||||
|
* Prepare for reading input via libinput using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state driver state to initialize
|
||||||
|
* @param path input device node path (e.g. /dev/input/event0)
|
||||||
|
*/
|
||||||
|
void libinput_init_state(libinput_drv_state_t *state, char* path);
|
||||||
|
/**
|
||||||
|
* Reconfigure the device file for libinput using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
* @param dev_name input device node path (e.g. /dev/input/event0)
|
||||||
|
* @return true: the device file set complete
|
||||||
|
* false: the device file doesn't exist current system
|
||||||
|
*/
|
||||||
|
bool libinput_set_file(char* dev_name);
|
||||||
|
/**
|
||||||
|
* Reconfigure the device file for libinput using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state the driver state to configure
|
||||||
|
* @param dev_name input device node path (e.g. /dev/input/event0)
|
||||||
|
* @return true: the device file set complete
|
||||||
|
* false: the device file doesn't exist current system
|
||||||
|
*/
|
||||||
|
bool libinput_set_file_state(libinput_drv_state_t *state, char* dev_name);
|
||||||
|
/**
|
||||||
|
* Read available input events via libinput using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
* @param indev_drv driver object itself
|
||||||
|
* @param data store the libinput data here
|
||||||
|
*/
|
||||||
|
void libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
/**
|
||||||
|
* Read available input events via libinput using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state the driver state to use
|
||||||
|
* @param indev_drv driver object itself
|
||||||
|
* @param data store the libinput data here
|
||||||
|
*/
|
||||||
|
void libinput_read_state(libinput_drv_state_t * state, lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LVGL_LIBINPUT_H */
|
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* @file mouse.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MOUSE_H
|
||||||
|
#define MOUSE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSE
|
||||||
|
|
||||||
|
#warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SDL_GPU
|
||||||
|
#include "../sdl/sdl_gpu.h"
|
||||||
|
#else
|
||||||
|
#include "../sdl/sdl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the mouse
|
||||||
|
*/
|
||||||
|
static inline void mouse_init(void)
|
||||||
|
{
|
||||||
|
/*Nothing to do*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the mouse
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the mouse data here
|
||||||
|
*/
|
||||||
|
void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
sdl_mouse_read(indev_drv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_MOUSE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MOUSE_H */
|
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* @file mousewheel.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MOUSEWHEEL_H
|
||||||
|
#define MOUSEWHEEL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSEWHEEL
|
||||||
|
|
||||||
|
#warning "Deprecated, use the SDL driver instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SDL_GPU
|
||||||
|
#include "../sdl/sdl_gpu.h"
|
||||||
|
#else
|
||||||
|
#include "../sdl/sdl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the encoder
|
||||||
|
*/
|
||||||
|
static inline void mousewheel_init(void)
|
||||||
|
{
|
||||||
|
/*Nothing to do*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the read data here
|
||||||
|
*/
|
||||||
|
static inline void mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
sdl_mousewheel_read(indev_drv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*USE_MOUSEWHEEL*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*MOUSEWHEEL_H*/
|
@ -0,0 +1,217 @@
|
|||||||
|
/**
|
||||||
|
* @file xkb.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "xkb.h"
|
||||||
|
#if USE_XKB
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static struct xkb_context *context = NULL;
|
||||||
|
static xkb_drv_state_t default_state = { .keymap = NULL, .state = NULL };
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the XKB system using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
* @return true if the initialisation was successful
|
||||||
|
*/
|
||||||
|
bool xkb_init(void) {
|
||||||
|
return xkb_init_state(&default_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the XKB system using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state XKB driver state to use
|
||||||
|
* @return true if the initialisation was successful
|
||||||
|
*/
|
||||||
|
bool xkb_init_state(xkb_drv_state_t *state) {
|
||||||
|
if (!context) {
|
||||||
|
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
if (!context) {
|
||||||
|
perror("could not create new XKB context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef XKB_KEY_MAP
|
||||||
|
struct xkb_rule_names names = XKB_KEY_MAP;
|
||||||
|
return xkb_set_keymap_state(state, names);
|
||||||
|
#else
|
||||||
|
return false; /* Keymap needs to be set manually using xkb_set_keymap_state to complete initialisation */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new keymap to be used for processing future key events using the default driver state. Use
|
||||||
|
* this function if you only want to connect a single device.
|
||||||
|
* @param names XKB rule names structure (use NULL components for default values)
|
||||||
|
* @return true if creating the keymap and associated state succeeded
|
||||||
|
*/
|
||||||
|
bool xkb_set_keymap(struct xkb_rule_names names) {
|
||||||
|
return xkb_set_keymap_state(&default_state, names);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new keymap to be used for processing future key events using a specific driver state. Use
|
||||||
|
* this function if you want to connect multiple devices.
|
||||||
|
* @param state XKB driver state to use
|
||||||
|
* @param names XKB rule names structure (use NULL components for default values)
|
||||||
|
* @return true if creating the keymap and associated state succeeded
|
||||||
|
*/
|
||||||
|
bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names) {
|
||||||
|
if (state->keymap) {
|
||||||
|
xkb_keymap_unref(state->keymap);
|
||||||
|
state->keymap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->keymap = xkb_keymap_new_from_names(context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
|
if (!state->keymap) {
|
||||||
|
perror("could not create XKB keymap");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->keymap = xkb_keymap_ref(state->keymap);
|
||||||
|
if (!state->keymap) {
|
||||||
|
perror("could not reference XKB keymap");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->state) {
|
||||||
|
xkb_state_unref(state->state);
|
||||||
|
state->state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->state = xkb_state_new(state->keymap);
|
||||||
|
if (!state->state) {
|
||||||
|
perror("could not create XKB state");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->state = xkb_state_ref(state->state);
|
||||||
|
if (!state->state) {
|
||||||
|
perror("could not reference XKB state");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an evdev scancode using the default driver state. Use this function if you only want to
|
||||||
|
* connect a single device.
|
||||||
|
* @param scancode evdev scancode to process
|
||||||
|
* @param down true if the key was pressed, false if it was releases
|
||||||
|
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
|
||||||
|
*/
|
||||||
|
uint32_t xkb_process_key(uint32_t scancode, bool down) {
|
||||||
|
return xkb_process_key_state(&default_state, scancode, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an evdev scancode using a specific driver state. Use this function if you want to connect
|
||||||
|
* multiple devices.
|
||||||
|
* @param state XKB driver state to use
|
||||||
|
* @param scancode evdev scancode to process
|
||||||
|
* @param down true if the key was pressed, false if it was releases
|
||||||
|
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
|
||||||
|
*/
|
||||||
|
uint32_t xkb_process_key_state(xkb_drv_state_t *state, uint32_t scancode, bool down) {
|
||||||
|
/* Offset the evdev scancode by 8, see https://xkbcommon.org/doc/current/xkbcommon_8h.html#ac29aee92124c08d1953910ab28ee1997 */
|
||||||
|
xkb_keycode_t keycode = scancode + 8;
|
||||||
|
|
||||||
|
uint32_t result = 0;
|
||||||
|
|
||||||
|
switch (xkb_state_key_get_one_sym(state->state, keycode)) {
|
||||||
|
case XKB_KEY_BackSpace:
|
||||||
|
result = LV_KEY_BACKSPACE;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Return:
|
||||||
|
case XKB_KEY_KP_Enter:
|
||||||
|
result = LV_KEY_ENTER;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Prior:
|
||||||
|
case XKB_KEY_KP_Prior:
|
||||||
|
result = LV_KEY_PREV;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Next:
|
||||||
|
case XKB_KEY_KP_Next:
|
||||||
|
result = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Up:
|
||||||
|
case XKB_KEY_KP_Up:
|
||||||
|
result = LV_KEY_UP;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Left:
|
||||||
|
case XKB_KEY_KP_Left:
|
||||||
|
result = LV_KEY_LEFT;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Right:
|
||||||
|
case XKB_KEY_KP_Right:
|
||||||
|
result = LV_KEY_RIGHT;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Down:
|
||||||
|
case XKB_KEY_KP_Down:
|
||||||
|
result = LV_KEY_DOWN;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_Tab:
|
||||||
|
case XKB_KEY_KP_Tab:
|
||||||
|
result = LV_KEY_NEXT;
|
||||||
|
break;
|
||||||
|
case XKB_KEY_ISO_Left_Tab: /* Sent on SHIFT + TAB */
|
||||||
|
result = LV_KEY_PREV;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
char buffer[4] = { 0, 0, 0, 0 };
|
||||||
|
int size = xkb_state_key_get_utf8(state->state, keycode, NULL, 0) + 1;
|
||||||
|
if (size > 1) {
|
||||||
|
xkb_state_key_get_utf8(state->state, keycode, buffer, size);
|
||||||
|
memcpy(&result, buffer, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xkb_state_update_key(state->state, keycode, down ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_XKB */
|
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* @file xkb.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XKB_H
|
||||||
|
#define XKB_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_XKB
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
struct xkb_rule_names;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct xkb_keymap *keymap;
|
||||||
|
struct xkb_state *state;
|
||||||
|
} xkb_drv_state_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the XKB system using the default driver state. Use this function if you only want
|
||||||
|
* to connect a single device.
|
||||||
|
* @return true if the initialisation was successful
|
||||||
|
*/
|
||||||
|
bool xkb_init(void);
|
||||||
|
/**
|
||||||
|
* Initialise the XKB system using a specific driver state. Use this function if you want to
|
||||||
|
* connect multiple devices.
|
||||||
|
* @param state XKB driver state to use
|
||||||
|
* @return true if the initialisation was successful
|
||||||
|
*/
|
||||||
|
bool xkb_init_state(xkb_drv_state_t *state);
|
||||||
|
/**
|
||||||
|
* Set a new keymap to be used for processing future key events using the default driver state. Use
|
||||||
|
* this function if you only want to connect a single device.
|
||||||
|
* @param names XKB rule names structure (use NULL components for default values)
|
||||||
|
* @return true if creating the keymap and associated state succeeded
|
||||||
|
*/
|
||||||
|
bool xkb_set_keymap(struct xkb_rule_names names);
|
||||||
|
/**
|
||||||
|
* Set a new keymap to be used for processing future key events using a specific driver state. Use
|
||||||
|
* this function if you want to connect multiple devices.
|
||||||
|
* @param state XKB driver state to use
|
||||||
|
* @param names XKB rule names structure (use NULL components for default values)
|
||||||
|
* @return true if creating the keymap and associated state succeeded
|
||||||
|
*/
|
||||||
|
bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names);
|
||||||
|
/**
|
||||||
|
* Process an evdev scancode using the default driver state. Use this function if you only want to
|
||||||
|
* connect a single device.
|
||||||
|
* @param scancode evdev scancode to process
|
||||||
|
* @param down true if the key was pressed, false if it was releases
|
||||||
|
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
|
||||||
|
*/
|
||||||
|
uint32_t xkb_process_key(uint32_t scancode, bool down);
|
||||||
|
/**
|
||||||
|
* Process an evdev scancode using a specific driver state. Use this function if you want to connect
|
||||||
|
* multiple devices.
|
||||||
|
* @param state XKB driver state to use
|
||||||
|
* @param scancode evdev scancode to process
|
||||||
|
* @param down true if the key was pressed, false if it was releases
|
||||||
|
* @return the (first) UTF-8 character produced by the event or 0 if no output was produced
|
||||||
|
*/
|
||||||
|
uint32_t xkb_process_key_state(xkb_drv_state_t *state, uint32_t scancode, bool down);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_XKB */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* XKB_H */
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "lv_drivers",
|
||||||
|
"version": "8.3.0",
|
||||||
|
"keywords": "littlevgl, lvgl, driver, display, touchpad",
|
||||||
|
"description": "Drivers for LittlevGL graphics library.",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/littlevgl/lv_drivers.git"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"includeDir": "."
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
LV_DRIVERS_DIR_NAME ?= lv_drivers
|
||||||
|
|
||||||
|
override CFLAGS := -I$(LVGL_DIR) $(CFLAGS)
|
||||||
|
|
||||||
|
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/*.c)
|
||||||
|
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/wayland/*.c)
|
||||||
|
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/indev/*.c)
|
||||||
|
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/gtkdrv/*.c)
|
||||||
|
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/display/*.c)
|
||||||
|
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/sdl/*.c)
|
@ -0,0 +1,494 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_drv_conf.h
|
||||||
|
* Configuration file for v8.3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COPY THIS FILE AS lv_drv_conf.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
#if 0 /*Set it to "1" to enable the content*/
|
||||||
|
|
||||||
|
#ifndef LV_DRV_CONF_H
|
||||||
|
#define LV_DRV_CONF_H
|
||||||
|
|
||||||
|
#include "lv_conf.h"
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DELAY INTERFACE
|
||||||
|
*********************/
|
||||||
|
#define LV_DRV_DELAY_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||||
|
#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/
|
||||||
|
#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DISPLAY INTERFACE
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*------------
|
||||||
|
* Common
|
||||||
|
*------------*/
|
||||||
|
#define LV_DRV_DISP_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||||
|
#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/
|
||||||
|
#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
|
||||||
|
|
||||||
|
/*---------
|
||||||
|
* SPI
|
||||||
|
*---------*/
|
||||||
|
#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
|
||||||
|
#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/
|
||||||
|
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/
|
||||||
|
|
||||||
|
/*------------------
|
||||||
|
* Parallel port
|
||||||
|
*-----------------*/
|
||||||
|
#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/
|
||||||
|
#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/
|
||||||
|
#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/
|
||||||
|
#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/
|
||||||
|
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/
|
||||||
|
|
||||||
|
/***************************
|
||||||
|
* INPUT DEVICE INTERFACE
|
||||||
|
***************************/
|
||||||
|
|
||||||
|
/*----------
|
||||||
|
* Common
|
||||||
|
*----------*/
|
||||||
|
#define LV_DRV_INDEV_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||||
|
#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
|
||||||
|
#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/
|
||||||
|
|
||||||
|
/*---------
|
||||||
|
* SPI
|
||||||
|
*---------*/
|
||||||
|
#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
|
||||||
|
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/
|
||||||
|
|
||||||
|
/*---------
|
||||||
|
* I2C
|
||||||
|
*---------*/
|
||||||
|
#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/
|
||||||
|
#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/
|
||||||
|
#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/
|
||||||
|
#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/
|
||||||
|
#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DISPLAY DRIVERS
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*-------------------
|
||||||
|
* SDL
|
||||||
|
*-------------------*/
|
||||||
|
|
||||||
|
/* SDL based drivers for display, mouse, mousewheel and keyboard*/
|
||||||
|
#ifndef USE_SDL
|
||||||
|
# define USE_SDL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Hardware accelerated SDL driver */
|
||||||
|
#ifndef USE_SDL_GPU
|
||||||
|
# define USE_SDL_GPU 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SDL || USE_SDL_GPU
|
||||||
|
# define SDL_HOR_RES 480
|
||||||
|
# define SDL_VER_RES 320
|
||||||
|
|
||||||
|
/* Scale window by this factor (useful when simulating small screens) */
|
||||||
|
# define SDL_ZOOM 1
|
||||||
|
|
||||||
|
/* Used to test true double buffering with only address changing.
|
||||||
|
* Use 2 draw buffers, bith with SDL_HOR_RES x SDL_VER_RES size*/
|
||||||
|
# define SDL_DOUBLE_BUFFERED 0
|
||||||
|
|
||||||
|
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
|
||||||
|
# define SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||||
|
|
||||||
|
/*Open two windows to test multi display support*/
|
||||||
|
# define SDL_DUAL_DISPLAY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------
|
||||||
|
* Monitor of PC
|
||||||
|
*-------------------*/
|
||||||
|
|
||||||
|
/*DEPRECATED: Use the SDL driver instead. */
|
||||||
|
#ifndef USE_MONITOR
|
||||||
|
# define USE_MONITOR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR
|
||||||
|
# define MONITOR_HOR_RES 480
|
||||||
|
# define MONITOR_VER_RES 320
|
||||||
|
|
||||||
|
/* Scale window by this factor (useful when simulating small screens) */
|
||||||
|
# define MONITOR_ZOOM 1
|
||||||
|
|
||||||
|
/* Used to test true double buffering with only address changing.
|
||||||
|
* Use 2 draw buffers, bith with MONITOR_HOR_RES x MONITOR_VER_RES size*/
|
||||||
|
# define MONITOR_DOUBLE_BUFFERED 0
|
||||||
|
|
||||||
|
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
|
||||||
|
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||||
|
|
||||||
|
/*Open two windows to test multi display support*/
|
||||||
|
# define MONITOR_DUAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-----------------------------------
|
||||||
|
* Native Windows (including mouse)
|
||||||
|
*----------------------------------*/
|
||||||
|
#ifndef USE_WINDOWS
|
||||||
|
# define USE_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_WINDOWS
|
||||||
|
# define WINDOW_HOR_RES 480
|
||||||
|
# define WINDOW_VER_RES 320
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------
|
||||||
|
* Native Windows (win32drv)
|
||||||
|
*---------------------------*/
|
||||||
|
#ifndef USE_WIN32DRV
|
||||||
|
# define USE_WIN32DRV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_WIN32DRV
|
||||||
|
/* Scale window by this factor (useful when simulating small screens) */
|
||||||
|
# define WIN32DRV_MONITOR_ZOOM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------
|
||||||
|
* GTK drivers (monitor, mouse, keyboard
|
||||||
|
*---------------------------------------*/
|
||||||
|
#ifndef USE_GTK
|
||||||
|
# define USE_GTK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------
|
||||||
|
* Wayland drivers (monitor, mouse, keyboard, touchscreen)
|
||||||
|
*---------------------------------------*/
|
||||||
|
#ifndef USE_WAYLAND
|
||||||
|
# define USE_WAYLAND 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_WAYLAND
|
||||||
|
/* Support for client-side decorations */
|
||||||
|
# ifndef LV_WAYLAND_CLIENT_SIDE_DECORATIONS
|
||||||
|
# define LV_WAYLAND_CLIENT_SIDE_DECORATIONS 1
|
||||||
|
# endif
|
||||||
|
/* Support for (deprecated) wl-shell protocol */
|
||||||
|
# ifndef LV_WAYLAND_WL_SHELL
|
||||||
|
# define LV_WAYLAND_WL_SHELL 1
|
||||||
|
# endif
|
||||||
|
/* Support for xdg-shell protocol */
|
||||||
|
# ifndef LV_WAYLAND_XDG_SHELL
|
||||||
|
# define LV_WAYLAND_XDG_SHELL 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------
|
||||||
|
* SSD1963
|
||||||
|
*--------------*/
|
||||||
|
#ifndef USE_SSD1963
|
||||||
|
# define USE_SSD1963 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SSD1963
|
||||||
|
# define SSD1963_HOR_RES LV_HOR_RES
|
||||||
|
# define SSD1963_VER_RES LV_VER_RES
|
||||||
|
# define SSD1963_HT 531
|
||||||
|
# define SSD1963_HPS 43
|
||||||
|
# define SSD1963_LPS 8
|
||||||
|
# define SSD1963_HPW 10
|
||||||
|
# define SSD1963_VT 288
|
||||||
|
# define SSD1963_VPS 12
|
||||||
|
# define SSD1963_FPS 4
|
||||||
|
# define SSD1963_VPW 10
|
||||||
|
# define SSD1963_HS_NEG 0 /*Negative hsync*/
|
||||||
|
# define SSD1963_VS_NEG 0 /*Negative vsync*/
|
||||||
|
# define SSD1963_ORI 0 /*0, 90, 180, 270*/
|
||||||
|
# define SSD1963_COLOR_DEPTH 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------
|
||||||
|
* R61581
|
||||||
|
*--------------*/
|
||||||
|
#ifndef USE_R61581
|
||||||
|
# define USE_R61581 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_R61581
|
||||||
|
# define R61581_HOR_RES LV_HOR_RES
|
||||||
|
# define R61581_VER_RES LV_VER_RES
|
||||||
|
# define R61581_HSPL 0 /*HSYNC signal polarity*/
|
||||||
|
# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/
|
||||||
|
# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/
|
||||||
|
# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */
|
||||||
|
# define R61581_VSPL 0 /*VSYNC signal polarity*/
|
||||||
|
# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/
|
||||||
|
# define R61581_VFP 8 /*Vertical Front poarch*/
|
||||||
|
# define R61581_VBP 8 /*Vertical Back poarch */
|
||||||
|
# define R61581_DPL 0 /*DCLK signal polarity*/
|
||||||
|
# define R61581_EPL 1 /*ENABLE signal polarity*/
|
||||||
|
# define R61581_ORI 0 /*0, 180*/
|
||||||
|
# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*------------------------------
|
||||||
|
* ST7565 (Monochrome, low res.)
|
||||||
|
*-----------------------------*/
|
||||||
|
#ifndef USE_ST7565
|
||||||
|
# define USE_ST7565 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_ST7565
|
||||||
|
/*No settings*/
|
||||||
|
#endif /*USE_ST7565*/
|
||||||
|
|
||||||
|
/*------------------------------
|
||||||
|
* GC9A01 (color, low res.)
|
||||||
|
*-----------------------------*/
|
||||||
|
#ifndef USE_GC9A01
|
||||||
|
# define USE_GC9A01 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_GC9A01
|
||||||
|
/*No settings*/
|
||||||
|
#endif /*USE_GC9A01*/
|
||||||
|
|
||||||
|
/*------------------------------------------
|
||||||
|
* UC1610 (4 gray 160*[104|128])
|
||||||
|
* (EA DOGXL160 160x104 tested)
|
||||||
|
*-----------------------------------------*/
|
||||||
|
#ifndef USE_UC1610
|
||||||
|
# define USE_UC1610 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_UC1610
|
||||||
|
# define UC1610_HOR_RES LV_HOR_RES
|
||||||
|
# define UC1610_VER_RES LV_VER_RES
|
||||||
|
# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */
|
||||||
|
# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */
|
||||||
|
# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */
|
||||||
|
#endif /*USE_UC1610*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
* SHARP memory in pixel monochrome display series
|
||||||
|
* LS012B7DD01 (184x38 pixels.)
|
||||||
|
* LS013B7DH03 (128x128 pixels.)
|
||||||
|
* LS013B7DH05 (144x168 pixels.)
|
||||||
|
* LS027B7DH01 (400x240 pixels.) (tested)
|
||||||
|
* LS032B7DD02 (336x536 pixels.)
|
||||||
|
* LS044Q7DH01 (320x240 pixels.)
|
||||||
|
*------------------------------------------------*/
|
||||||
|
#ifndef USE_SHARP_MIP
|
||||||
|
# define USE_SHARP_MIP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SHARP_MIP
|
||||||
|
# define SHARP_MIP_HOR_RES LV_HOR_RES
|
||||||
|
# define SHARP_MIP_VER_RES LV_VER_RES
|
||||||
|
# define SHARP_MIP_SOFT_COM_INVERSION 0
|
||||||
|
# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/
|
||||||
|
#endif /*USE_SHARP_MIP*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
* ILI9341 240X320 TFT LCD
|
||||||
|
*------------------------------------------------*/
|
||||||
|
#ifndef USE_ILI9341
|
||||||
|
# define USE_ILI9341 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_ILI9341
|
||||||
|
# define ILI9341_HOR_RES LV_HOR_RES
|
||||||
|
# define ILI9341_VER_RES LV_VER_RES
|
||||||
|
# define ILI9341_GAMMA 1
|
||||||
|
# define ILI9341_TEARING 0
|
||||||
|
#endif /*USE_ILI9341*/
|
||||||
|
|
||||||
|
/*-----------------------------------------
|
||||||
|
* Linux frame buffer device (/dev/fbx)
|
||||||
|
*-----------------------------------------*/
|
||||||
|
#ifndef USE_FBDEV
|
||||||
|
# define USE_FBDEV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_FBDEV
|
||||||
|
# define FBDEV_PATH "/dev/fb0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-----------------------------------------
|
||||||
|
* FreeBSD frame buffer device (/dev/fbx)
|
||||||
|
*.........................................*/
|
||||||
|
#ifndef USE_BSD_FBDEV
|
||||||
|
# define USE_BSD_FBDEV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_BSD_FBDEV
|
||||||
|
# define FBDEV_PATH "/dev/fb0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-----------------------------------------
|
||||||
|
* DRM/KMS device (/dev/dri/cardX)
|
||||||
|
*-----------------------------------------*/
|
||||||
|
#ifndef USE_DRM
|
||||||
|
# define USE_DRM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_DRM
|
||||||
|
# define DRM_CARD "/dev/dri/card0"
|
||||||
|
# define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INPUT DEVICES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*--------------
|
||||||
|
* XPT2046
|
||||||
|
*--------------*/
|
||||||
|
#ifndef USE_XPT2046
|
||||||
|
# define USE_XPT2046 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_XPT2046
|
||||||
|
# define XPT2046_HOR_RES 480
|
||||||
|
# define XPT2046_VER_RES 320
|
||||||
|
# define XPT2046_X_MIN 200
|
||||||
|
# define XPT2046_Y_MIN 200
|
||||||
|
# define XPT2046_X_MAX 3800
|
||||||
|
# define XPT2046_Y_MAX 3800
|
||||||
|
# define XPT2046_AVG 4
|
||||||
|
# define XPT2046_X_INV 0
|
||||||
|
# define XPT2046_Y_INV 0
|
||||||
|
# define XPT2046_XY_SWAP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-----------------
|
||||||
|
* FT5406EE8
|
||||||
|
*-----------------*/
|
||||||
|
#ifndef USE_FT5406EE8
|
||||||
|
# define USE_FT5406EE8 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_FT5406EE8
|
||||||
|
# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*---------------
|
||||||
|
* AD TOUCH
|
||||||
|
*--------------*/
|
||||||
|
#ifndef USE_AD_TOUCH
|
||||||
|
# define USE_AD_TOUCH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_AD_TOUCH
|
||||||
|
/*No settings*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------
|
||||||
|
* Mouse or touchpad on PC (using SDL)
|
||||||
|
*-------------------------------------*/
|
||||||
|
/*DEPRECATED: Use the SDL driver instead. */
|
||||||
|
#ifndef USE_MOUSE
|
||||||
|
# define USE_MOUSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSE
|
||||||
|
/*No settings*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------
|
||||||
|
* Mousewheel as encoder on PC (using SDL)
|
||||||
|
*------------------------------------------*/
|
||||||
|
/*DEPRECATED: Use the SDL driver instead. */
|
||||||
|
#ifndef USE_MOUSEWHEEL
|
||||||
|
# define USE_MOUSEWHEEL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSEWHEEL
|
||||||
|
/*No settings*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
* Touchscreen, mouse/touchpad or keyboard as libinput interface (for Linux based systems)
|
||||||
|
*------------------------------------------------*/
|
||||||
|
#ifndef USE_LIBINPUT
|
||||||
|
# define USE_LIBINPUT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_BSD_LIBINPUT
|
||||||
|
# define USE_BSD_LIBINPUT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
||||||
|
/*If only a single device of the same type is connected, you can also auto detect it, e.g.:
|
||||||
|
*#define LIBINPUT_NAME libinput_find_dev(LIBINPUT_CAPABILITY_TOUCH, false)*/
|
||||||
|
# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
||||||
|
|
||||||
|
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
* Mouse or touchpad as evdev interface (for Linux based systems)
|
||||||
|
*------------------------------------------------*/
|
||||||
|
#ifndef USE_EVDEV
|
||||||
|
# define USE_EVDEV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_BSD_EVDEV
|
||||||
|
# define USE_BSD_EVDEV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_EVDEV || USE_BSD_EVDEV
|
||||||
|
# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
||||||
|
# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/
|
||||||
|
|
||||||
|
# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
|
||||||
|
|
||||||
|
# if EVDEV_CALIBRATE
|
||||||
|
# define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
|
||||||
|
# define EVDEV_HOR_MAX 4096 /*"evtest" Linux tool can help to get the correct calibraion values>*/
|
||||||
|
# define EVDEV_VER_MIN 0
|
||||||
|
# define EVDEV_VER_MAX 4096
|
||||||
|
# endif /*EVDEV_CALIBRATE*/
|
||||||
|
#endif /*USE_EVDEV*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------
|
||||||
|
* Full keyboard support for evdev and libinput interface
|
||||||
|
*------------------------------------------------*/
|
||||||
|
# ifndef USE_XKB
|
||||||
|
# define USE_XKB 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#if USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV
|
||||||
|
# if USE_XKB
|
||||||
|
# define XKB_KEY_MAP { .rules = NULL, \
|
||||||
|
.model = "pc101", \
|
||||||
|
.layout = "us", \
|
||||||
|
.variant = NULL, \
|
||||||
|
.options = NULL } /*"setxkbmap -query" can help find the right values for your keyboard*/
|
||||||
|
# endif /*USE_XKB*/
|
||||||
|
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV*/
|
||||||
|
|
||||||
|
/*-------------------------------
|
||||||
|
* Keyboard of a PC (using SDL)
|
||||||
|
*------------------------------*/
|
||||||
|
/*DEPRECATED: Use the SDL driver instead. */
|
||||||
|
#ifndef USE_KEYBOARD
|
||||||
|
# define USE_KEYBOARD 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_KEYBOARD
|
||||||
|
/*No settings*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*LV_DRV_CONF_H*/
|
||||||
|
|
||||||
|
#endif /*End of "Content enable"*/
|
@ -0,0 +1,390 @@
|
|||||||
|
/**
|
||||||
|
* @file sdl.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "sdl.h"
|
||||||
|
#if USE_MONITOR || USE_SDL
|
||||||
|
|
||||||
|
#if LV_USE_GPU_SDL
|
||||||
|
# error "LV_USE_GPU_SDL must not be enabled"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR
|
||||||
|
# warning "MONITOR is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_KEYBOARD
|
||||||
|
# warning "KEYBOARD is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSE
|
||||||
|
# warning "MOUSE is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSEWHEEL
|
||||||
|
# warning "MOUSEWHEEL is deprecated, use SDL instead that. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR && USE_SDL
|
||||||
|
# error "Cannot enable both MONITOR and SDL at the same time. "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR
|
||||||
|
# define SDL_HOR_RES MONITOR_HOR_RES
|
||||||
|
# define SDL_VER_RES MONITOR_VER_RES
|
||||||
|
# define SDL_ZOOM MONITOR_ZOOM
|
||||||
|
# define SDL_DOUBLE_BUFFERED MONITOR_DOUBLE_BUFFERED
|
||||||
|
# define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
|
||||||
|
# define SDL_VIRTUAL_MACHINE MONITOR_VIRTUAL_MACHINE
|
||||||
|
# define SDL_DUAL_DISPLAY MONITOR_DUAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_FULLSCREEN
|
||||||
|
# define SDL_FULLSCREEN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include SDL_INCLUDE_PATH
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#ifndef KEYBOARD_BUFFER_SIZE
|
||||||
|
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
typedef struct {
|
||||||
|
SDL_Window * window;
|
||||||
|
SDL_Renderer * renderer;
|
||||||
|
SDL_Texture * texture;
|
||||||
|
volatile bool sdl_refr_qry;
|
||||||
|
#if SDL_DOUBLE_BUFFERED
|
||||||
|
uint32_t * tft_fb_act;
|
||||||
|
#else
|
||||||
|
uint32_t * tft_fb;
|
||||||
|
#endif
|
||||||
|
}monitor_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void window_create(monitor_t * m);
|
||||||
|
static void window_update(monitor_t * m);
|
||||||
|
static void monitor_sdl_clean_up(void);
|
||||||
|
static void sdl_event_handler(lv_timer_t * t);
|
||||||
|
static void monitor_sdl_refr(lv_timer_t * t);
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
monitor_t monitor;
|
||||||
|
|
||||||
|
#if SDL_DUAL_DISPLAY
|
||||||
|
monitor_t monitor2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static volatile bool sdl_inited = false;
|
||||||
|
|
||||||
|
static bool left_button_down = false;
|
||||||
|
static int16_t last_x = 0;
|
||||||
|
static int16_t last_y = 0;
|
||||||
|
|
||||||
|
static int16_t wheel_diff = 0;
|
||||||
|
static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED;
|
||||||
|
|
||||||
|
static char buf[KEYBOARD_BUFFER_SIZE];
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void sdl_init(void)
|
||||||
|
{
|
||||||
|
/*Initialize the SDL*/
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
SDL_SetEventFilter(quit_filter, NULL);
|
||||||
|
|
||||||
|
window_create(&monitor);
|
||||||
|
#if SDL_DUAL_DISPLAY
|
||||||
|
window_create(&monitor2);
|
||||||
|
int x, y;
|
||||||
|
SDL_GetWindowPosition(monitor2.window, &x, &y);
|
||||||
|
SDL_SetWindowPosition(monitor.window, x + (SDL_HOR_RES * SDL_ZOOM) / 2 + 10, y);
|
||||||
|
SDL_SetWindowPosition(monitor2.window, x - (SDL_HOR_RES * SDL_ZOOM) / 2 - 10, y);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_StartTextInput();
|
||||||
|
|
||||||
|
lv_timer_create(sdl_event_handler, 10, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
const lv_coord_t hres = disp_drv->physical_hor_res == -1 ? disp_drv->hor_res : disp_drv->physical_hor_res;
|
||||||
|
const lv_coord_t vres = disp_drv->physical_ver_res == -1 ? disp_drv->ver_res : disp_drv->physical_ver_res;
|
||||||
|
|
||||||
|
// printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2);
|
||||||
|
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SDL_DOUBLE_BUFFERED
|
||||||
|
monitor.tft_fb_act = (uint32_t *)color_p;
|
||||||
|
#else /*SDL_DOUBLE_BUFFERED*/
|
||||||
|
|
||||||
|
int32_t y;
|
||||||
|
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
|
||||||
|
int32_t x;
|
||||||
|
for(y = area->y1; y <= area->y2 && y < vres; y++) {
|
||||||
|
for(x = area->x1; x <= area->x2; x++) {
|
||||||
|
monitor.tft_fb[y * hres + x] = lv_color_to32(*color_p);
|
||||||
|
color_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uint32_t w = lv_area_get_width(area);
|
||||||
|
for(y = area->y1; y <= area->y2 && y < vres; y++) {
|
||||||
|
memcpy(&monitor.tft_fb[y * hres + area->x1], color_p, w * sizeof(lv_color_t));
|
||||||
|
color_p += w;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /*SDL_DOUBLE_BUFFERED*/
|
||||||
|
|
||||||
|
monitor.sdl_refr_qry = true;
|
||||||
|
|
||||||
|
/* TYPICALLY YOU DO NOT NEED THIS
|
||||||
|
* If it was the last part to refresh update the texture of the window.*/
|
||||||
|
if(lv_disp_flush_is_last(disp_drv)) {
|
||||||
|
monitor_sdl_refr(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*IMPORTANT! It must be called to tell the system the flush is ready*/
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if SDL_DUAL_DISPLAY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
const lv_coord_t hres = disp_drv->physical_hor_res == -1 ? disp_drv->hor_res : disp_drv->physical_hor_res;
|
||||||
|
const lv_coord_t vres = disp_drv->physical_ver_res == -1 ? disp_drv->ver_res : disp_drv->physical_ver_res;
|
||||||
|
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SDL_DOUBLE_BUFFERED
|
||||||
|
monitor2.tft_fb_act = (uint32_t *)color_p;
|
||||||
|
|
||||||
|
monitor2.sdl_refr_qry = true;
|
||||||
|
|
||||||
|
/*IMPORTANT! It must be called to tell the system the flush is ready*/
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
#else
|
||||||
|
|
||||||
|
int32_t y;
|
||||||
|
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
|
||||||
|
int32_t x;
|
||||||
|
for(y = area->y1; y <= area->y2 && y < vres; y++) {
|
||||||
|
for(x = area->x1; x <= area->x2; x++) {
|
||||||
|
monitor2.tft_fb[y * hres + x] = lv_color_to32(*color_p);
|
||||||
|
color_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uint32_t w = lv_area_get_width(area);
|
||||||
|
for(y = area->y1; y <= area->y2 && y < vres; y++) {
|
||||||
|
memcpy(&monitor2.tft_fb[y * hres + area->x1], color_p, w * sizeof(lv_color_t));
|
||||||
|
color_p += w;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
monitor2.sdl_refr_qry = true;
|
||||||
|
|
||||||
|
/* TYPICALLY YOU DO NOT NEED THIS
|
||||||
|
* If it was the last part to refresh update the texture of the window.*/
|
||||||
|
if(lv_disp_flush_is_last(disp_drv)) {
|
||||||
|
monitor_sdl_refr(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*IMPORTANT! It must be called to tell the system the flush is ready*/
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDL main thread. All SDL related task have to be handled here!
|
||||||
|
* It initializes SDL, handles drawing and the mouse.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void sdl_event_handler(lv_timer_t * t)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
|
||||||
|
/*Refresh handling*/
|
||||||
|
SDL_Event event;
|
||||||
|
while(SDL_PollEvent(&event)) {
|
||||||
|
mouse_handler(&event);
|
||||||
|
mousewheel_handler(&event);
|
||||||
|
keyboard_handler(&event);
|
||||||
|
|
||||||
|
if((&event)->type == SDL_WINDOWEVENT) {
|
||||||
|
switch((&event)->window.event) {
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 5)
|
||||||
|
case SDL_WINDOWEVENT_TAKE_FOCUS:
|
||||||
|
#endif
|
||||||
|
case SDL_WINDOWEVENT_EXPOSED:
|
||||||
|
window_update(&monitor);
|
||||||
|
#if SDL_DUAL_DISPLAY
|
||||||
|
window_update(&monitor2);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Run until quit event not arrives*/
|
||||||
|
if(sdl_quit_qry) {
|
||||||
|
monitor_sdl_clean_up();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDL main thread. All SDL related task have to be handled here!
|
||||||
|
* It initializes SDL, handles drawing and the mouse.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void monitor_sdl_refr(lv_timer_t * t)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
|
||||||
|
/*Refresh handling*/
|
||||||
|
if(monitor.sdl_refr_qry != false) {
|
||||||
|
monitor.sdl_refr_qry = false;
|
||||||
|
window_update(&monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SDL_DUAL_DISPLAY
|
||||||
|
if(monitor2.sdl_refr_qry != false) {
|
||||||
|
monitor2.sdl_refr_qry = false;
|
||||||
|
window_update(&monitor2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void monitor_sdl_clean_up(void)
|
||||||
|
{
|
||||||
|
SDL_DestroyTexture(monitor.texture);
|
||||||
|
SDL_DestroyRenderer(monitor.renderer);
|
||||||
|
SDL_DestroyWindow(monitor.window);
|
||||||
|
|
||||||
|
#if SDL_DUAL_DISPLAY
|
||||||
|
SDL_DestroyTexture(monitor2.texture);
|
||||||
|
SDL_DestroyRenderer(monitor2.renderer);
|
||||||
|
SDL_DestroyWindow(monitor2.window);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void window_create(monitor_t * m)
|
||||||
|
{
|
||||||
|
|
||||||
|
int flag = 0;
|
||||||
|
#if SDL_FULLSCREEN
|
||||||
|
flag |= SDL_WINDOW_FULLSCREEN;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m->window = SDL_CreateWindow("TFT Simulator",
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/
|
||||||
|
|
||||||
|
m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_SOFTWARE);
|
||||||
|
m->texture = SDL_CreateTexture(m->renderer,
|
||||||
|
SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, SDL_HOR_RES, SDL_VER_RES);
|
||||||
|
SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
/*Initialize the frame buffer to gray (77 is an empirical value) */
|
||||||
|
#if SDL_DOUBLE_BUFFERED
|
||||||
|
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, SDL_HOR_RES * sizeof(uint32_t));
|
||||||
|
#else
|
||||||
|
m->tft_fb = (uint32_t *)malloc(sizeof(uint32_t) * SDL_HOR_RES * SDL_VER_RES);
|
||||||
|
memset(m->tft_fb, 0x44, SDL_HOR_RES * SDL_VER_RES * sizeof(uint32_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m->sdl_refr_qry = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void window_update(monitor_t * m)
|
||||||
|
{
|
||||||
|
#if SDL_DOUBLE_BUFFERED == 0
|
||||||
|
SDL_UpdateTexture(m->texture, NULL, m->tft_fb, SDL_HOR_RES * sizeof(uint32_t));
|
||||||
|
#else
|
||||||
|
if(m->tft_fb_act == NULL) return;
|
||||||
|
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, SDL_HOR_RES * sizeof(uint32_t));
|
||||||
|
#endif
|
||||||
|
SDL_RenderClear(m->renderer);
|
||||||
|
lv_disp_t * d = _lv_refr_get_disp_refreshing();
|
||||||
|
if(d->driver->screen_transp) {
|
||||||
|
SDL_SetRenderDrawColor(m->renderer, 0xff, 0, 0, 0xff);
|
||||||
|
SDL_Rect r;
|
||||||
|
r.x = 0; r.y = 0; r.w = SDL_HOR_RES; r.h = SDL_VER_RES;
|
||||||
|
SDL_RenderDrawRect(m->renderer, &r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Update the renderer with the texture containing the rendered image*/
|
||||||
|
SDL_RenderCopy(m->renderer, m->texture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(m->renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*USE_MONITOR || USE_SDL*/
|
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* @file sdl.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_H
|
||||||
|
#define SDL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR || USE_SDL
|
||||||
|
|
||||||
|
#include "sdl_common.h"
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize SDL to be used as display, mouse and mouse wheel drivers.
|
||||||
|
*/
|
||||||
|
void sdl_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the mouse
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the mouse data here
|
||||||
|
*/
|
||||||
|
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the read data here
|
||||||
|
*/
|
||||||
|
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get input from the keyboard.
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the red data here
|
||||||
|
*/
|
||||||
|
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/*For backward compatibility. Will be removed.*/
|
||||||
|
#define monitor_init sdl_init
|
||||||
|
#define monitor_flush sdl_display_flush
|
||||||
|
#define monitor_flush2 sdl_display_flush2
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_MONITOR || USE_SDL */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SDL_H */
|
@ -0,0 +1,271 @@
|
|||||||
|
//
|
||||||
|
// Created by Mariotaku on 2021/10/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "sdl_common.h"
|
||||||
|
|
||||||
|
#if USE_SDL || USE_SDL_GPU
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#ifndef KEYBOARD_BUFFER_SIZE
|
||||||
|
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
volatile bool sdl_quit_qry = false;
|
||||||
|
|
||||||
|
static bool left_button_down = false;
|
||||||
|
static int16_t last_x = 0;
|
||||||
|
static int16_t last_y = 0;
|
||||||
|
|
||||||
|
static int16_t wheel_diff = 0;
|
||||||
|
static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED;
|
||||||
|
|
||||||
|
static char buf[KEYBOARD_BUFFER_SIZE];
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the mouse
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the mouse data here
|
||||||
|
*/
|
||||||
|
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
(void) indev_drv; /*Unused*/
|
||||||
|
|
||||||
|
/*Store the collected data*/
|
||||||
|
data->point.x = last_x;
|
||||||
|
data->point.y = last_y;
|
||||||
|
data->state = left_button_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the read data here
|
||||||
|
*/
|
||||||
|
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
(void) indev_drv; /*Unused*/
|
||||||
|
|
||||||
|
data->state = wheel_state;
|
||||||
|
data->enc_diff = wheel_diff;
|
||||||
|
wheel_diff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get input from the keyboard.
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the red data here
|
||||||
|
*/
|
||||||
|
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
(void) indev_drv; /*Unused*/
|
||||||
|
|
||||||
|
static bool dummy_read = false;
|
||||||
|
const size_t len = strlen(buf);
|
||||||
|
|
||||||
|
/*Send a release manually*/
|
||||||
|
if (dummy_read) {
|
||||||
|
dummy_read = false;
|
||||||
|
data->state = LV_INDEV_STATE_RELEASED;
|
||||||
|
data->continue_reading = len > 0;
|
||||||
|
}
|
||||||
|
/*Send the pressed character*/
|
||||||
|
else if (len > 0) {
|
||||||
|
dummy_read = true;
|
||||||
|
data->state = LV_INDEV_STATE_PRESSED;
|
||||||
|
data->key = buf[0];
|
||||||
|
memmove(buf, buf + 1, len);
|
||||||
|
data->continue_reading = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
int quit_filter(void * userdata, SDL_Event * event)
|
||||||
|
{
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
|
if(event->type == SDL_QUIT) {
|
||||||
|
sdl_quit_qry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouse_handler(SDL_Event * event)
|
||||||
|
{
|
||||||
|
switch(event->type) {
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
if(event->button.button == SDL_BUTTON_LEFT)
|
||||||
|
left_button_down = false;
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
if(event->button.button == SDL_BUTTON_LEFT) {
|
||||||
|
left_button_down = true;
|
||||||
|
last_x = event->motion.x / SDL_ZOOM;
|
||||||
|
last_y = event->motion.y / SDL_ZOOM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
last_x = event->motion.x / SDL_ZOOM;
|
||||||
|
last_y = event->motion.y / SDL_ZOOM;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_FINGERUP:
|
||||||
|
left_button_down = false;
|
||||||
|
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM;
|
||||||
|
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM;
|
||||||
|
break;
|
||||||
|
case SDL_FINGERDOWN:
|
||||||
|
left_button_down = true;
|
||||||
|
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM;
|
||||||
|
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM;
|
||||||
|
break;
|
||||||
|
case SDL_FINGERMOTION:
|
||||||
|
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM;
|
||||||
|
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It is called periodically from the SDL thread to check mouse wheel state
|
||||||
|
* @param event describes the event
|
||||||
|
*/
|
||||||
|
void mousewheel_handler(SDL_Event * event)
|
||||||
|
{
|
||||||
|
switch(event->type) {
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
// Scroll down (y = -1) means positive encoder turn,
|
||||||
|
// so invert it
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
/*Escripten scales it wrong*/
|
||||||
|
if(event->wheel.y < 0) wheel_diff++;
|
||||||
|
if(event->wheel.y > 0) wheel_diff--;
|
||||||
|
#else
|
||||||
|
wheel_diff = -event->wheel.y;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
if(event->button.button == SDL_BUTTON_MIDDLE) {
|
||||||
|
wheel_state = LV_INDEV_STATE_PRESSED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
if(event->button.button == SDL_BUTTON_MIDDLE) {
|
||||||
|
wheel_state = LV_INDEV_STATE_RELEASED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called periodically from the SDL thread, store text input or control characters in the buffer.
|
||||||
|
* @param event describes the event
|
||||||
|
*/
|
||||||
|
void keyboard_handler(SDL_Event * event)
|
||||||
|
{
|
||||||
|
/* We only care about SDL_KEYDOWN and SDL_TEXTINPUT events */
|
||||||
|
switch(event->type) {
|
||||||
|
case SDL_KEYDOWN: /*Button press*/
|
||||||
|
{
|
||||||
|
const uint32_t ctrl_key = keycode_to_ctrl_key(event->key.keysym.sym);
|
||||||
|
if (ctrl_key == '\0')
|
||||||
|
return;
|
||||||
|
const size_t len = strlen(buf);
|
||||||
|
if (len < KEYBOARD_BUFFER_SIZE - 1) {
|
||||||
|
buf[len] = ctrl_key;
|
||||||
|
buf[len + 1] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_TEXTINPUT: /*Text input*/
|
||||||
|
{
|
||||||
|
const size_t len = strlen(buf) + strlen(event->text.text);
|
||||||
|
if (len < KEYBOARD_BUFFER_SIZE - 1)
|
||||||
|
strcat(buf, event->text.text);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a SDL key code to it's LV_KEY_* counterpart or return '\0' if it's not a control character.
|
||||||
|
* @param sdl_key the key code
|
||||||
|
* @return LV_KEY_* control character or '\0'
|
||||||
|
*/
|
||||||
|
uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key)
|
||||||
|
{
|
||||||
|
/*Remap some key to LV_KEY_... to manage groups*/
|
||||||
|
|
||||||
|
SDL_Keymod mode = SDL_GetModState();
|
||||||
|
|
||||||
|
switch(sdl_key) {
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
case SDLK_KP_PLUS:
|
||||||
|
return LV_KEY_RIGHT;
|
||||||
|
|
||||||
|
case SDLK_LEFT:
|
||||||
|
case SDLK_KP_MINUS:
|
||||||
|
return LV_KEY_LEFT;
|
||||||
|
|
||||||
|
case SDLK_UP:
|
||||||
|
return LV_KEY_UP;
|
||||||
|
|
||||||
|
case SDLK_DOWN:
|
||||||
|
return LV_KEY_DOWN;
|
||||||
|
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
return LV_KEY_ESC;
|
||||||
|
|
||||||
|
case SDLK_BACKSPACE:
|
||||||
|
return LV_KEY_BACKSPACE;
|
||||||
|
|
||||||
|
case SDLK_DELETE:
|
||||||
|
return LV_KEY_DEL;
|
||||||
|
|
||||||
|
case SDLK_KP_ENTER:
|
||||||
|
case '\r':
|
||||||
|
return LV_KEY_ENTER;
|
||||||
|
|
||||||
|
case SDLK_TAB:
|
||||||
|
return (mode & KMOD_SHIFT)? LV_KEY_PREV: LV_KEY_NEXT;
|
||||||
|
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
|
return LV_KEY_NEXT;
|
||||||
|
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
return LV_KEY_PREV;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_SDL || USD_SDL_GPU */
|
@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* @file sdl_common.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_COMMON_H
|
||||||
|
#define SDL_COMMON_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SDL || USE_SDL_GPU
|
||||||
|
|
||||||
|
#ifndef SDL_INCLUDE_PATH
|
||||||
|
#define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
|
||||||
|
#endif
|
||||||
|
#include SDL_INCLUDE_PATH
|
||||||
|
|
||||||
|
#ifndef SDL_ZOOM
|
||||||
|
#define SDL_ZOOM MONITOR_ZOOM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
extern volatile bool sdl_quit_qry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize SDL to be used as display, mouse and mouse wheel drivers.
|
||||||
|
*/
|
||||||
|
void sdl_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixel to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the mouse
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the mouse data here
|
||||||
|
*/
|
||||||
|
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the read data here
|
||||||
|
*/
|
||||||
|
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get input from the keyboard.
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the red data here
|
||||||
|
*/
|
||||||
|
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
int quit_filter(void * userdata, SDL_Event * event);
|
||||||
|
|
||||||
|
void mouse_handler(SDL_Event * event);
|
||||||
|
void mousewheel_handler(SDL_Event * event);
|
||||||
|
uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key);
|
||||||
|
void keyboard_handler(SDL_Event * event);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
#endif /* USE_SDL || USE_SDL_GPU */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SDL_COMMON_H */
|
@ -0,0 +1,278 @@
|
|||||||
|
/**
|
||||||
|
* @file sdl_gpu.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "sdl_gpu.h"
|
||||||
|
#if USE_SDL_GPU
|
||||||
|
|
||||||
|
#if LV_USE_GPU_SDL == 0
|
||||||
|
# error "LV_USE_DRAW_SDL must be enabled"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_KEYBOARD
|
||||||
|
# warning "KEYBOARD is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSE
|
||||||
|
# warning "MOUSE is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MOUSEWHEEL
|
||||||
|
# warning "MOUSEWHEEL is deprecated, use SDL instead that. See lv_drivers/sdl/sdl.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MONITOR
|
||||||
|
# error "Cannot enable both MONITOR and SDL at the same time. "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <lvgl/src/draw/sdl/lv_draw_sdl.h>
|
||||||
|
#include SDL_INCLUDE_PATH
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#ifndef KEYBOARD_BUFFER_SIZE
|
||||||
|
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
typedef struct {
|
||||||
|
lv_draw_sdl_drv_param_t drv_param;
|
||||||
|
SDL_Window * window;
|
||||||
|
SDL_Texture * texture;
|
||||||
|
}monitor_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void window_create(monitor_t * m);
|
||||||
|
static void window_update(lv_disp_drv_t *disp_drv, void * buf);
|
||||||
|
static void monitor_sdl_clean_up(void);
|
||||||
|
static void sdl_event_handler(lv_timer_t * t);
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
static volatile bool sdl_inited = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void sdl_init(void)
|
||||||
|
{
|
||||||
|
/*Initialize the SDL*/
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
SDL_SetEventFilter(quit_filter, NULL);
|
||||||
|
|
||||||
|
sdl_inited = true;
|
||||||
|
|
||||||
|
SDL_StartTextInput();
|
||||||
|
|
||||||
|
lv_timer_create(sdl_event_handler, 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdl_disp_drv_init(lv_disp_drv_t * disp_drv, lv_coord_t hor_res, lv_coord_t ver_res)
|
||||||
|
{
|
||||||
|
monitor_t *m = lv_mem_alloc(sizeof(monitor_t));
|
||||||
|
window_create(m);
|
||||||
|
lv_disp_drv_init(disp_drv);
|
||||||
|
disp_drv->direct_mode = 1;
|
||||||
|
disp_drv->flush_cb = monitor_flush;
|
||||||
|
disp_drv->hor_res = hor_res;
|
||||||
|
disp_drv->ver_res = ver_res;
|
||||||
|
lv_disp_draw_buf_t *disp_buf = lv_mem_alloc(sizeof(lv_disp_draw_buf_t));
|
||||||
|
lv_disp_draw_buf_init(disp_buf, m->texture, NULL, hor_res * ver_res);
|
||||||
|
disp_drv->draw_buf = disp_buf;
|
||||||
|
disp_drv->antialiasing = 1;
|
||||||
|
disp_drv->user_data = &m->drv_param;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
lv_coord_t hres = disp_drv->hor_res;
|
||||||
|
lv_coord_t vres = disp_drv->ver_res;
|
||||||
|
|
||||||
|
// printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2);
|
||||||
|
|
||||||
|
/*Return if the area is out the screen*/
|
||||||
|
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TYPICALLY YOU DO NOT NEED THIS
|
||||||
|
* If it was the last part to refresh update the texture of the window.*/
|
||||||
|
if(lv_disp_flush_is_last(disp_drv)) {
|
||||||
|
window_update(disp_drv, color_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*IMPORTANT! It must be called to tell the system the flush is ready*/
|
||||||
|
lv_disp_flush_ready(disp_drv);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdl_display_resize(lv_disp_t *disp, int width, int height)
|
||||||
|
{
|
||||||
|
lv_disp_drv_t *driver = disp->driver;
|
||||||
|
SDL_Renderer *renderer = ((lv_draw_sdl_drv_param_t *) driver->user_data)->renderer;
|
||||||
|
if (driver->draw_buf->buf1) {
|
||||||
|
SDL_DestroyTexture(driver->draw_buf->buf1);
|
||||||
|
}
|
||||||
|
SDL_Texture *texture = lv_draw_sdl_create_screen_texture(renderer, width, height);
|
||||||
|
lv_disp_draw_buf_init(driver->draw_buf, texture, NULL, width * height);
|
||||||
|
driver->hor_res = (lv_coord_t) width;
|
||||||
|
driver->ver_res = (lv_coord_t) height;
|
||||||
|
SDL_RendererInfo renderer_info;
|
||||||
|
SDL_GetRendererInfo(renderer, &renderer_info);
|
||||||
|
SDL_assert(renderer_info.flags & SDL_RENDERER_TARGETTEXTURE);
|
||||||
|
SDL_SetRenderTarget(renderer, texture);
|
||||||
|
lv_disp_drv_update(disp, driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDL main thread. All SDL related task have to be handled here!
|
||||||
|
* It initializes SDL, handles drawing and the mouse.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void sdl_event_handler(lv_timer_t * t)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
|
||||||
|
/*Refresh handling*/
|
||||||
|
SDL_Event event;
|
||||||
|
while(SDL_PollEvent(&event)) {
|
||||||
|
mouse_handler(&event);
|
||||||
|
mousewheel_handler(&event);
|
||||||
|
keyboard_handler(&event);
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_WINDOWEVENT: {
|
||||||
|
SDL_Window * window = SDL_GetWindowFromID(event.window.windowID);
|
||||||
|
switch (event.window.event) {
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 5)
|
||||||
|
case SDL_WINDOWEVENT_TAKE_FOCUS:
|
||||||
|
#endif
|
||||||
|
case SDL_WINDOWEVENT_EXPOSED:
|
||||||
|
for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; cur = lv_disp_get_next(cur)) {
|
||||||
|
window_update(cur->driver, cur->driver->draw_buf->buf_act);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_WINDOWEVENT_SIZE_CHANGED: {
|
||||||
|
for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; cur = lv_disp_get_next(cur)) {
|
||||||
|
lv_draw_sdl_drv_param_t *param = cur->driver->user_data;
|
||||||
|
SDL_Renderer *renderer = SDL_GetRenderer(window);
|
||||||
|
if (param->renderer != renderer) continue;
|
||||||
|
int w, h;
|
||||||
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
|
sdl_display_resize(cur, w, h);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_WINDOWEVENT_CLOSE: {
|
||||||
|
for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; ) {
|
||||||
|
lv_disp_t * tmp = cur;
|
||||||
|
cur = lv_disp_get_next(tmp);
|
||||||
|
monitor_t * m = tmp->driver->user_data;
|
||||||
|
SDL_Renderer *renderer = SDL_GetRenderer(window);
|
||||||
|
if (m->drv_param.renderer != renderer) continue;
|
||||||
|
SDL_DestroyTexture(tmp->driver->draw_buf->buf1);
|
||||||
|
SDL_DestroyRenderer(m->drv_param.renderer);
|
||||||
|
lv_disp_remove(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Run until quit event not arrives*/
|
||||||
|
if(sdl_quit_qry) {
|
||||||
|
monitor_sdl_clean_up();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void monitor_sdl_clean_up(void)
|
||||||
|
{
|
||||||
|
for (lv_disp_t *cur = lv_disp_get_next(NULL); cur; ) {
|
||||||
|
lv_disp_t * tmp = cur;
|
||||||
|
monitor_t * m = tmp->driver->user_data;
|
||||||
|
SDL_DestroyTexture(tmp->driver->draw_buf->buf1);
|
||||||
|
SDL_DestroyRenderer(m->drv_param.renderer);
|
||||||
|
cur = lv_disp_get_next(cur);
|
||||||
|
lv_disp_remove(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void window_create(monitor_t * m)
|
||||||
|
{
|
||||||
|
// SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1");
|
||||||
|
m->window = SDL_CreateWindow("TFT Simulator",
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM, SDL_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
|
m->drv_param.renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
|
||||||
|
m->texture = lv_draw_sdl_create_screen_texture(m->drv_param.renderer, SDL_HOR_RES, SDL_VER_RES);
|
||||||
|
/* For first frame */
|
||||||
|
SDL_SetRenderTarget(m->drv_param.renderer, m->texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void window_update(lv_disp_drv_t *disp_drv, void * buf)
|
||||||
|
{
|
||||||
|
SDL_Renderer *renderer = ((lv_draw_sdl_drv_param_t *) disp_drv->user_data)->renderer;
|
||||||
|
SDL_Texture *texture = buf;
|
||||||
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
#if LV_COLOR_SCREEN_TRANSP
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff);
|
||||||
|
SDL_Rect r;
|
||||||
|
r.x = 0; r.y = 0; r.w = SDL_HOR_RES; r.h = SDL_VER_RES;
|
||||||
|
SDL_RenderDrawRect(renderer, &r);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*Update the renderer with the texture containing the rendered image*/
|
||||||
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_RenderSetClipRect(renderer, NULL);
|
||||||
|
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
SDL_SetRenderTarget(renderer, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*USE_SDL_GPU*/
|
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* @file sdl_gpu.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_GPU_H
|
||||||
|
#define SDL_GPU_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SDL_GPU
|
||||||
|
|
||||||
|
#include "sdl_common.h"
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize SDL to be used as display, mouse and mouse wheel drivers.
|
||||||
|
*/
|
||||||
|
void sdl_init(void);
|
||||||
|
|
||||||
|
void sdl_disp_drv_init(lv_disp_drv_t * disp_drv, lv_coord_t hor_res, lv_coord_t ver_res);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param disp_drv pointer to driver where this function belongs
|
||||||
|
* @param area an area where to copy `color_p`
|
||||||
|
* @param color_p an array of pixels to copy to the `area` part of the screen
|
||||||
|
*/
|
||||||
|
void sdl_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position and state of the mouse
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the mouse data here
|
||||||
|
*/
|
||||||
|
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the read data here
|
||||||
|
*/
|
||||||
|
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get input from the keyboard.
|
||||||
|
* @param indev_drv pointer to the related input device driver
|
||||||
|
* @param data store the red data here
|
||||||
|
*/
|
||||||
|
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
|
||||||
|
|
||||||
|
/*For backward compatibility. Will be removed.*/
|
||||||
|
#define monitor_init sdl_init
|
||||||
|
#define monitor_flush sdl_display_flush
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_SDL_GPU */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SDL_GPU_H */
|
@ -0,0 +1,5 @@
|
|||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
/protocols
|
@ -0,0 +1,39 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
project(lv_wayland)
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(wayland-client REQUIRED wayland-client)
|
||||||
|
pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
|
||||||
|
pkg_check_modules(xkbcommon REQUIRED xkbcommon)
|
||||||
|
|
||||||
|
# Wayland protocols
|
||||||
|
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||||
|
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.15)
|
||||||
|
pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir)
|
||||||
|
|
||||||
|
macro(wayland_generate protocol_xml_file output_dir target)
|
||||||
|
get_filename_component(output_file_base ${protocol_xml_file} NAME_WE)
|
||||||
|
set(output_file_noext "${output_dir}/wayland-${output_file_base}-client-protocol")
|
||||||
|
add_custom_command(OUTPUT "${output_file_noext}.h"
|
||||||
|
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_xml_file}" "${output_file_noext}.h"
|
||||||
|
DEPENDS "${protocol_xml_file}"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT "${output_file_noext}.c"
|
||||||
|
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_xml_file}" "${output_file_noext}.c"
|
||||||
|
DEPENDS "${protocol_xml_file}"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${protocol_xml_file})
|
||||||
|
message("Protocol XML file not found: " ${protocol_xml_file})
|
||||||
|
else()
|
||||||
|
set_property(TARGET ${target} APPEND PROPERTY SOURCES "${output_file_noext}.h" "${output_file_noext}.c")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
set(WAYLAND_PROTOCOLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
|
||||||
|
file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR})
|
||||||
|
|
||||||
|
add_custom_target(generate_protocols ALL)
|
||||||
|
|
||||||
|
wayland_generate("${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml" ${WAYLAND_PROTOCOLS_DIR} generate_protocols)
|
@ -0,0 +1,157 @@
|
|||||||
|
# Wayland display and input driver
|
||||||
|
|
||||||
|
Wayland display and input driver, with support for keyboard, pointer (i.e. mouse) and touchscreen.
|
||||||
|
Keyboard support is based on libxkbcommon.
|
||||||
|
|
||||||
|
Following shell are supported:
|
||||||
|
|
||||||
|
* wl_shell (deprecated)
|
||||||
|
* xdg_shell
|
||||||
|
|
||||||
|
> xdg_shell requires an extra build step; see section _Generate protocols_ below.
|
||||||
|
|
||||||
|
|
||||||
|
Basic client-side window decorations (simple title bar, minimize and close buttons)
|
||||||
|
are supported, while integration with desktop environments is not.
|
||||||
|
|
||||||
|
|
||||||
|
## Install headers and libraries
|
||||||
|
|
||||||
|
### Ubuntu
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt-get install libwayland-dev libxkbcommon-dev libwayland-bin wayland-protocols
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fedora
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo dnf install wayland-devel libxkbcommon-devel wayland-utils wayland-protocols-devel
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Generate protocols
|
||||||
|
|
||||||
|
Support for non-basic shells (i.e. other than _wl_shell_) requires additional
|
||||||
|
source files to be generated before the first build of the project. To do so,
|
||||||
|
navigate to the _wayland_ folder (the one which includes this file) and issue
|
||||||
|
the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake .
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Build configuration under Eclipse
|
||||||
|
|
||||||
|
In "Project properties > C/C++ Build > Settings" set the followings:
|
||||||
|
|
||||||
|
- "Cross GCC Compiler > Command line pattern"
|
||||||
|
- Add ` ${wayland-cflags}` and ` ${xkbcommon-cflags}` to the end (add a space between the last command and this)
|
||||||
|
|
||||||
|
|
||||||
|
- "Cross GCC Linker > Command line pattern"
|
||||||
|
- Add ` ${wayland-libs}` and ` ${xkbcommon-libs}` to the end (add a space between the last command and this)
|
||||||
|
|
||||||
|
|
||||||
|
- In "C/C++ Build > Build variables"
|
||||||
|
- Configuration: [All Configuration]
|
||||||
|
|
||||||
|
- Add
|
||||||
|
- Variable name: `wayland-cflags`
|
||||||
|
- Type: `String`
|
||||||
|
- Value: `pkg-config --cflags wayland-client`
|
||||||
|
- Variable name: `wayland-libs`
|
||||||
|
- Type: `String`
|
||||||
|
- Value: `pkg-config --libs wayland-client`
|
||||||
|
- Variable name: `xkbcommon-cflags`
|
||||||
|
- Type: `String`
|
||||||
|
- Value: `pkg-config --cflags xkbcommon`
|
||||||
|
- Variable name: `xkbcommon-libs`
|
||||||
|
- Type: `String`
|
||||||
|
- Value: `pkg-config --libs xkbcommon`
|
||||||
|
|
||||||
|
|
||||||
|
## Init Wayland in LVGL
|
||||||
|
|
||||||
|
1. In `main.c` `#incude "lv_drivers/wayland/wayland.h"`
|
||||||
|
2. Enable the Wayland driver in `lv_drv_conf.h` with `USE_WAYLAND 1` and
|
||||||
|
configure its features below, enabling at least support for one shell.
|
||||||
|
3. `LV_COLOR_DEPTH` should be set either to `32` or `16` in `lv_conf.h`;
|
||||||
|
support for `8` and `1` depends on target platform.
|
||||||
|
4. After `lv_init()` call `lv_wayland_init()`.
|
||||||
|
5. Add a display (or more than one) using `lv_wayland_create_window()`,
|
||||||
|
possibly with a close callback to track the status of each display:
|
||||||
|
```c
|
||||||
|
#define H_RES (800)
|
||||||
|
#define V_RES (480)
|
||||||
|
|
||||||
|
/* Create a display */
|
||||||
|
lv_disp_t * disp = lv_wayland_create_window(H_RES, V_RES, "Window Title", close_cb);
|
||||||
|
```
|
||||||
|
As part of the above call, the Wayland driver will register four input devices
|
||||||
|
for each display:
|
||||||
|
- a KEYPAD connected to Wayland keyboard events
|
||||||
|
- a POINTER connected to Wayland touch events
|
||||||
|
- a POINTER connected to Wayland pointer events
|
||||||
|
- a ENCODER connected to Wayland pointer axis events
|
||||||
|
Handles for input devices of each display can be get using respectively
|
||||||
|
`lv_wayland_get_indev_keyboard()`, `lv_wayland_get_indev_touchscreen()`,
|
||||||
|
`lv_wayland_get_indev_pointer()` and `lv_wayland_get_indev_pointeraxis()`, using
|
||||||
|
`disp` as argument.
|
||||||
|
5. After `lv_deinit()` (if used), or in any case during de-initialization, call
|
||||||
|
`lv_wayland_deinit()`.
|
||||||
|
|
||||||
|
### Fullscreen mode
|
||||||
|
|
||||||
|
In order to set one window as fullscreen or restore it as a normal one,
|
||||||
|
call the `lv_wayland_window_set_fullscreen()` function respectively with `true`
|
||||||
|
or `false` as `fullscreen` argument.
|
||||||
|
|
||||||
|
### Disable window client-side decoration at runtime
|
||||||
|
|
||||||
|
Even when client-side decorations are enabled at compile time, they can be
|
||||||
|
disabled at runtime setting the `LV_WAYLAND_DISABLE_WINDOWDECORATION`
|
||||||
|
environment variable to `1`.
|
||||||
|
|
||||||
|
### Event-driven timer handler
|
||||||
|
|
||||||
|
Set `LV_WAYLAND_TIMER_HANDLER` in `lv_drv_conf.h` and call `lv_wayland_timer_handler()`
|
||||||
|
in your timer loop (in place of `lv_timer_handler()`).
|
||||||
|
|
||||||
|
You can now sleep/wait until the next timer/event is ready, e.g.:
|
||||||
|
```
|
||||||
|
/* [After initialization and display creation] */
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
struct pollfd pfd;
|
||||||
|
uint32_t time_till_next;
|
||||||
|
int sleep;
|
||||||
|
|
||||||
|
pfd.fd = lv_wayland_get_fd();
|
||||||
|
pfd.events = POLLIN;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* Handle any Wayland/LVGL timers/events */
|
||||||
|
time_till_next = lv_wayland_timer_handler();
|
||||||
|
|
||||||
|
/* Run until the last window closes */
|
||||||
|
if (!lv_wayland_window_is_open(NULL)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for something interesting to happen */
|
||||||
|
if (time_till_next == LV_NO_TIMER_READY) {
|
||||||
|
sleep = -1;
|
||||||
|
} else if (time_till_next > INT_MAX) {
|
||||||
|
sleep = INT_MAX;
|
||||||
|
} else {
|
||||||
|
sleep = time_till_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((poll(&pfd, 1, sleep) < 0) && (errno == EINTR));
|
||||||
|
}
|
||||||
|
```
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* @file wayland
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WAYLAND_H
|
||||||
|
#define WAYLAND_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_WAYLAND
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LV_USE_USER_DATA == 0
|
||||||
|
#error "Support for user data is required by wayland driver. Set LV_USE_USER_DATA to 1 in lv_conf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
typedef bool (*lv_wayland_display_close_f_t)(lv_disp_t * disp);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void lv_wayland_init(void);
|
||||||
|
void lv_wayland_deinit(void);
|
||||||
|
int lv_wayland_get_fd(void);
|
||||||
|
lv_disp_t * lv_wayland_create_window(lv_coord_t hor_res, lv_coord_t ver_res, char *title,
|
||||||
|
lv_wayland_display_close_f_t close_cb);
|
||||||
|
void lv_wayland_close_window(lv_disp_t * disp);
|
||||||
|
bool lv_wayland_window_is_open(lv_disp_t * disp);
|
||||||
|
bool lv_wayland_window_is_flush_pending(lv_disp_t * disp);
|
||||||
|
void lv_wayland_window_set_fullscreen(lv_disp_t * disp, bool fullscreen);
|
||||||
|
lv_indev_t * lv_wayland_get_pointer(lv_disp_t * disp);
|
||||||
|
lv_indev_t * lv_wayland_get_pointeraxis(lv_disp_t * disp);
|
||||||
|
lv_indev_t * lv_wayland_get_keyboard(lv_disp_t * disp);
|
||||||
|
lv_indev_t * lv_wayland_get_touchscreen(lv_disp_t * disp);
|
||||||
|
#ifdef LV_WAYLAND_TIMER_HANDLER
|
||||||
|
uint32_t lv_wayland_timer_handler(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /* USE_WAYLAND */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WAYLAND_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,304 @@
|
|||||||
|
/**
|
||||||
|
* @file win_drv.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "win_drv.h"
|
||||||
|
#if USE_WINDOWS
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
|
||||||
|
#if LV_COLOR_DEPTH < 16
|
||||||
|
#error Windows driver only supports true RGB colors at this time
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* DEFINES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#define WINDOW_STYLE (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME))
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void do_register(void);
|
||||||
|
static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p);
|
||||||
|
static void win_drv_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
|
||||||
|
static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
|
||||||
|
static void win_drv_read(lv_indev_t *drv, lv_indev_data_t * data);
|
||||||
|
static void msg_handler(void *param);
|
||||||
|
|
||||||
|
static COLORREF lv_color_to_colorref(const lv_color_t color);
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
bool lv_win_exit_flag = false;
|
||||||
|
lv_disp_t *lv_windows_disp;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static HWND hwnd;
|
||||||
|
static uint32_t *fbp = NULL; /* Raw framebuffer memory */
|
||||||
|
static bool mouse_pressed;
|
||||||
|
static int mouse_x, mouse_y;
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
const char g_szClassName[] = "LVGL";
|
||||||
|
|
||||||
|
HWND windrv_init(void)
|
||||||
|
{
|
||||||
|
WNDCLASSEX wc;
|
||||||
|
RECT winrect;
|
||||||
|
HICON lvgl_icon;
|
||||||
|
|
||||||
|
//Step 1: Registering the Window Class
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wc.style = 0;
|
||||||
|
wc.lpfnWndProc = WndProc;
|
||||||
|
wc.cbClsExtra = 0;
|
||||||
|
wc.cbWndExtra = 0;
|
||||||
|
wc.hInstance = GetModuleHandle(NULL);
|
||||||
|
lvgl_icon = (HICON) LoadImage( NULL, "lvgl_icon.bmp", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
|
||||||
|
|
||||||
|
if(lvgl_icon == NULL)
|
||||||
|
lvgl_icon = LoadIcon(NULL, IDI_APPLICATION);
|
||||||
|
|
||||||
|
wc.hIcon = lvgl_icon;
|
||||||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||||||
|
wc.lpszMenuName = NULL;
|
||||||
|
wc.lpszClassName = g_szClassName;
|
||||||
|
wc.hIconSm = lvgl_icon;
|
||||||
|
|
||||||
|
if(!RegisterClassEx(&wc))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
winrect.left = 0;
|
||||||
|
winrect.right = WINDOW_HOR_RES - 1;
|
||||||
|
winrect.top = 0;
|
||||||
|
winrect.bottom = WINDOW_VER_RES - 1;
|
||||||
|
AdjustWindowRectEx(&winrect, WINDOW_STYLE, FALSE, WS_EX_CLIENTEDGE);
|
||||||
|
OffsetRect(&winrect, -winrect.left, -winrect.top);
|
||||||
|
// Step 2: Creating the Window
|
||||||
|
hwnd = CreateWindowEx(
|
||||||
|
WS_EX_CLIENTEDGE,
|
||||||
|
g_szClassName,
|
||||||
|
"LVGL Simulator",
|
||||||
|
WINDOW_STYLE,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, winrect.right, winrect.bottom,
|
||||||
|
NULL, NULL, GetModuleHandle(NULL), NULL);
|
||||||
|
|
||||||
|
if(hwnd == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowWindow(hwnd, SW_SHOWDEFAULT);
|
||||||
|
UpdateWindow(hwnd);
|
||||||
|
|
||||||
|
|
||||||
|
lv_task_create(msg_handler, 0, LV_TASK_PRIO_HIGHEST, NULL);
|
||||||
|
lv_win_exit_flag = false;
|
||||||
|
do_register();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void do_register(void)
|
||||||
|
{
|
||||||
|
static lv_disp_draw_buf_t disp_buf_1;
|
||||||
|
static lv_color_t buf1_1[WINDOW_HOR_RES * 100]; /*A buffer for 10 rows*/
|
||||||
|
lv_disp_draw_buf_init(&disp_draw_buf_1, buf1_1, NULL, WINDOW_HOR_RES * 100); /*Initialize the display buffer*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------
|
||||||
|
* Register the display in LVGLGL
|
||||||
|
*----------------------------------*/
|
||||||
|
|
||||||
|
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
|
||||||
|
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||||
|
|
||||||
|
/*Set up the functions to access to your display*/
|
||||||
|
|
||||||
|
/*Set the resolution of the display*/
|
||||||
|
disp_drv.hor_res = WINDOW_HOR_RES;
|
||||||
|
disp_drv.ver_res = WINDOW_VER_RES;
|
||||||
|
|
||||||
|
/*Used to copy the buffer's content to the display*/
|
||||||
|
disp_drv.flush_cb = win_drv_flush;
|
||||||
|
|
||||||
|
/*Set a display buffer*/
|
||||||
|
disp_drv.draw_buf = &disp_buf_1;
|
||||||
|
|
||||||
|
/*Finally register the driver*/
|
||||||
|
lv_windows_disp = lv_disp_drv_register(&disp_drv);
|
||||||
|
static lv_indev_drv_t indev_drv;
|
||||||
|
lv_indev_drv_init(&indev_drv);
|
||||||
|
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||||
|
indev_drv.read_cb = win_drv_read;
|
||||||
|
lv_indev_drv_register(&indev_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msg_handler(void *param)
|
||||||
|
{
|
||||||
|
(void)param;
|
||||||
|
|
||||||
|
MSG msg;
|
||||||
|
BOOL bRet;
|
||||||
|
if( (bRet = PeekMessage( &msg, NULL, 0, 0, TRUE )) != 0)
|
||||||
|
{
|
||||||
|
if (bRet == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
if(msg.message == WM_QUIT)
|
||||||
|
lv_win_exit_flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_drv_read(lv_indev_t *drv, lv_indev_data_t * data)
|
||||||
|
{
|
||||||
|
data->state = mouse_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
|
||||||
|
data->point.x = mouse_x;
|
||||||
|
data->point.y = mouse_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_paint(void)
|
||||||
|
{
|
||||||
|
HBITMAP bmp = CreateBitmap(WINDOW_HOR_RES, WINDOW_VER_RES, 1, 32, fbp);
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
|
||||||
|
HDC hdc = BeginPaint(hwnd, &ps);
|
||||||
|
|
||||||
|
HDC hdcMem = CreateCompatibleDC(hdc);
|
||||||
|
HBITMAP hbmOld = SelectObject(hdcMem, bmp);
|
||||||
|
|
||||||
|
BitBlt(hdc, 0, 0, WINDOW_HOR_RES, WINDOW_VER_RES, hdcMem, 0, 0, SRCCOPY);
|
||||||
|
|
||||||
|
SelectObject(hdcMem, hbmOld);
|
||||||
|
DeleteDC(hdcMem);
|
||||||
|
|
||||||
|
EndPaint(hwnd, &ps);
|
||||||
|
DeleteObject(bmp);
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Flush a buffer to the marked area
|
||||||
|
* @param x1 left coordinate
|
||||||
|
* @param y1 top coordinate
|
||||||
|
* @param x2 right coordinate
|
||||||
|
* @param y2 bottom coordinate
|
||||||
|
* @param color_p an array of colors
|
||||||
|
*/
|
||||||
|
static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
win_drv_map(area->x1, area->y1, area->x2, area->y2, color_p);
|
||||||
|
lv_disp_flush_ready(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put a color map to the marked area
|
||||||
|
* @param x1 left coordinate
|
||||||
|
* @param y1 top coordinate
|
||||||
|
* @param x2 right coordinate
|
||||||
|
* @param y2 bottom coordinate
|
||||||
|
* @param color_p an array of colors
|
||||||
|
*/
|
||||||
|
static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
|
||||||
|
{
|
||||||
|
for(int y = y1; y <= y2; y++)
|
||||||
|
{
|
||||||
|
for(int x = x1; x <= x2; x++)
|
||||||
|
{
|
||||||
|
fbp[y*WINDOW_HOR_RES+x] = lv_color_to32(*color_p);
|
||||||
|
color_p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||||||
|
UpdateWindow(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
HDC hdc;
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
switch(msg) {
|
||||||
|
case WM_CREATE:
|
||||||
|
fbp = malloc(4*WINDOW_HOR_RES*WINDOW_VER_RES);
|
||||||
|
if(fbp == NULL)
|
||||||
|
return 1;
|
||||||
|
SetTimer(hwnd, 0, 10, (TIMERPROC)lv_task_handler);
|
||||||
|
SetTimer(hwnd, 1, 25, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
mouse_x = GET_X_LPARAM(lParam);
|
||||||
|
mouse_y = GET_Y_LPARAM(lParam);
|
||||||
|
if(msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) {
|
||||||
|
mouse_pressed = (msg == WM_LBUTTONDOWN);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case WM_CLOSE:
|
||||||
|
free(fbp);
|
||||||
|
fbp = NULL;
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
return 0;
|
||||||
|
case WM_PAINT:
|
||||||
|
on_paint();
|
||||||
|
return 0;
|
||||||
|
case WM_TIMER:
|
||||||
|
lv_tick_inc(25);
|
||||||
|
return 0;
|
||||||
|
case WM_DESTROY:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
static COLORREF lv_color_to_colorref(const lv_color_t color)
|
||||||
|
{
|
||||||
|
uint32_t raw_color = lv_color_to32(color);
|
||||||
|
lv_color32_t tmp;
|
||||||
|
tmp.full = raw_color;
|
||||||
|
uint32_t colorref = RGB(tmp.ch.red, tmp.ch.green, tmp.ch.blue);
|
||||||
|
return colorref;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* @file fbdev.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WINDRV_H
|
||||||
|
#define WINDRV_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#ifndef LV_DRV_NO_CONF
|
||||||
|
#ifdef LV_CONF_INCLUDE_SIMPLE
|
||||||
|
#include "lv_drv_conf.h"
|
||||||
|
#else
|
||||||
|
#include "../lv_drv_conf.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_WINDOWS
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
extern bool lv_win_exit_flag;
|
||||||
|
extern lv_disp_t *lv_windows_disp;
|
||||||
|
|
||||||
|
HWND windrv_init(void);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#endif /*USE_WINDOWS*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*WIN_DRV_H*/
|
Reference in New Issue