在上面移植到Ubuntu虚拟机上进行测试过,然而测试程序上面只有显示器驱动,没有输入设备(键盘、键盘、触摸板)的移植,明天将LittlevGL移植到我的一块Linux板子起来,板子带有一块800*480的屏幕以及电容触摸面板。说不准哪些时侯可能可以用上linux site:infoq.cn,虽然安卓和QT对系统的性能和资源要求太高,使用LittlevGL这套图形库可能会在个别场景上使用到。
打算使用原先在虚拟机上测试的那套类库进行更改linux空间,由于framebuffer的操作都是一样的,直接更改Makefile,将其中的CC改成交叉编译器即可:
CC = /home/tangquan/workspace/docs/Linux-SDK/dragonboard/out/sun8iw5p1/dragonboard/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-gcc
之后直接make编译即可得到开发板上可执行的文件,运行即可,疗效和虚拟机上测试是一样的,而且难以触摸。下边进行输入设备的移植工作。
参考文章:。
执行命令“cat/proc/bus/input/devices”查看本机的输入设备,找到其中关于触摸屏的信息:
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="ft5x_ts"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=ddrfreq_dsm event3
B: PROP=0
B: EV=b
B: KEY=400 0 0 0 0 0 0 0 0 0 0
B: ABS=2650000 0
信息中的Handlers表示该输入设备的风波处理者,第一个是DDR显存(目的是在点击屏幕的时侯调整DDR频度,一段时间不操作则增加DDR频度以节能)。第二个是event3,这个设备在“/dev/input/”中可以见到,我们可以操作event3这个设备来获得触摸屏的输入信息。
在”lv_drivers/indev/”文件夹中创建两个文件touchscreen.c和touchscreen.h,参考并更改参考文章中的内容,得到一个驱动设备:
#include "touchscreen.h"
#include "stdio.h"
#if USE_TOUCHSCREEN
#include
#include LV_DRV_INDEV_INCLUDE
#include LV_DRV_DELAY_INCLUDE
#include
#include
#include
#include
#include
#include
#include "unistd.h"
#include "pthread.h"
#include
pthread_t TouchScreenEventHandler_t;
void* TouchScreenEventHandler(void *args);
static bool left_button_down = false;
static int flags = 0;
static int16_t last_x = 0,last_x_tmp = 0;
static int16_t last_y = 0,last_y_tmp = 0;
void ts_init(void)
{
printf("Initialize touch screenrn");
//int pthread_create(pthread_t * tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);
pthread_create(&TouchScreenEventHandler_t,NULL,TouchScreenEventHandler,(void*)0);
}
/**
* 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 ts_read(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
/*Store the collected data*/
data->point.x = last_x;
data->point.y = last_y;
data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
return false;
}
/**********************
* STATIC FUNCTIONS
**********************/
void* TouchScreenEventHandler(void *args)
{
int fd;
fd_set rds;
int ret;
struct input_event event;
struct timeval time;
struct input_absinfo absI;
fd = open( "/dev/input/event3", O_RDONLY );
if ( fd < 0 )
{
perror( "/dev/input/event3" );
return NULL;
}
//得到X轴的abs信息
ioctl(fd,EVIOCGABS(ABS_X),&absI);
printf("x abs lastest value=%dn",absI.value);
printf("x abs min=%dn",absI.minimum);
printf("x abs max=%dn",absI.maximum);
//得到y轴的abs信息
ioctl(fd,EVIOCGABS(ABS_Y),&absI);
printf("y abs lastest value=%dn",absI.value);
printf("y abs min=%dn",absI.minimum);
printf("y abs max=%dn",absI.maximum);
//得到按压轴的abs信息
ioctl(fd,EVIOCGABS(ABS_PRESSURE),&absI);
printf("pressure abs lastest value=%dn",absI.value);
printf("pressure abs min=%dn",absI.minimum);
printf("pressure abs max=%dn",absI.maximum);
while ( 1 )
{
FD_ZERO( &rds );
FD_SET( fd, &rds );
/*调用select检查是否能够从/dev/input/event0设备读取数据*/
ret = select( fd + 1, &rds, NULL, NULL, NULL );
if ( ret < 0 )
{
perror( "select" );
return NULL;
}
/*能够读取到数据*/
else if ( FD_ISSET( fd, &rds ) )
{
ret = read( fd, &event, sizeof(struct input_event) );
time = event.time;
// printf( "timeS=%d,timeUS=%d,type=%d,code=%.2x,value=%dn", time.tv_sec, time.tv_usec, event.type, event.code, event.value );
// printf("%d,%drn",event.type,event.code);
if(event.type == EV_SYN)
{
if(event.code == SYN_REPORT)
{
if((flags & 0x03) == 0x03)
{
flags = 0x00;
last_x = last_x_tmp;
last_y = last_y_tmp;
if(!left_button_down)
{
left_button_down = true;
// printf("key:%drn",left_button_down);
}
// printf("%d,%drn",last_x,last_y);
}
else
{
left_button_down = false;
// printf("key:%drn",left_button_down);
}
}
}
else if(event.type == EV_ABS)
{
if(event.code == ABS_MT_POSITION_X)
{
last_x_tmp = event.value;
flags |= 0x01;
// printf("%d,",last_x);
}
else if(event.code == ABS_MT_POSITION_Y)
{
last_y_tmp = event.value;
flags |= 0x02;
// printf("%drn",last_y);
}
}
}
else
printf("a");
//usleep(100000);
}
/*关闭设备文件句柄*/
close( fd );
}
#endif
程序中创建了一个线程TouchScreenEventHandler用于读取触摸屏的数据,这儿须要注意Linux系统的input子系统的输入数据的格式,比如这儿的触摸屏应用中,通常是先读取到X轴的数据帧,之后再读取到Y轴的数据帧,之后读取到一个Eventtypes为EV_SYN,Eventcode为SYN_REPORT的帧作为不同组数据间的分割linux移植,假如停止触摸,则在收到最后一组触摸数据以及数据间隔以后会再收到一个EV_SYN|SYN_REPORT帧,表示两次触摸风波间的间隔。程序中使用一个flags变量用于处理原告的那些风波,并通过触摸风波模拟出键盘按下的风波。通过全局变量的方法将TouchScreenEventHandler中的数据传出去,LittlevGL内核调用ts_read函数读取设备输入数据:
/**
* 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 ts_read(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
/*Store the collected data*/
data->point.x = last_x;
data->point.y = last_y;
data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
return false;
}
下边可以创建一个输入设备实体并注册到LittlevGL中去了:
//Add a touchscreen input device
ts_init();
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = ts_read; /*This function will be called periodically (by the library) to get the mouse position and state*/
lv_indev_drv_register(&indev_drv);
前面这段代码放到创建完显示设备以后即可linux移植,将LV_DEMO_SLIDE_SHOW设置为0以关掉手动滑动功能取消。运行以后疗效就下来了:
流畅性还可以,做一些简单的应用是没有问题的。
注:可以使用tslib作为提供的插口函数创建下来一个输入设备来给LittlevGL使用,tslib的API参考:。