在上面移植到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以关掉手动滑动功能取消。运行以后疗效就下来了:

移植Linux系统_linux移植_linux移植论坛

流畅性还可以,做一些简单的应用是没有问题的。

注:可以使用tslib作为提供的插口函数创建下来一个输入设备来给LittlevGL使用,tslib的API参考:。

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复