Squashed 'lib/lv_drivers/' content from commit 71830257

git-subtree-dir: lib/lv_drivers
git-subtree-split: 71830257710f430b6d8d1c324f89f2eab52488f1
add-custom-font
alex 2 years ago
commit 8e64914235

@ -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.

17
.github/stale.yml vendored

@ -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

2
.gitignore vendored

@ -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,79 @@
/**
* @file win32drv.h
*
*/
#ifndef LV_WIN32DRV_H
#define LV_WIN32DRV_H
/*********************
* 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_WIN32DRV
#include <Windows.h>
#if _MSC_VER >= 1200
// Disable compilation warnings.
#pragma warning(push)
// nonstandard extension used : bit field types other than int
#pragma warning(disable:4214)
// 'conversion' conversion from 'type1' to 'type2', possible loss of data
#pragma warning(disable:4244)
#endif
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if _MSC_VER >= 1200
// Restore compilation warnings.
#pragma warning(pop)
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
EXTERN_C bool lv_win32_quit_signal;
EXTERN_C lv_indev_t* lv_win32_pointer_device_object;
EXTERN_C lv_indev_t* lv_win32_keypad_device_object;
EXTERN_C lv_indev_t* lv_win32_encoder_device_object;
EXTERN_C void lv_win32_add_all_input_devices_to_group(
lv_group_t* group);
EXTERN_C bool lv_win32_init(
HINSTANCE instance_handle,
int show_window_mode,
lv_coord_t hor_res,
lv_coord_t ver_res,
HICON icon_handle);
/**********************
* MACROS
**********************/
#endif /*USE_WIN32DRV*/
#endif /*LV_WIN32DRV_H*/

@ -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*/