后板第一次提交

This commit is contained in:
2024-03-28 21:29:24 +08:00
parent 96f9be14dc
commit cdd76cc211
1288 changed files with 400753 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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