【Linux应用编程笔记】tslib库使用

系列文章目录

【Linux应用编程笔记】GPIO

【Linux应用编程笔记】输入设备


本系列使用的开发板为正点原子阿尔法IMX6ULL开发板,及根据正点原子所的提供教程学习

文章目录


做什么?

学习tslib库的使用

一、tslib简介

一个专门为触摸屏设备开发的开源Linux应用层函数库,可作为Qt的触摸屏输入插件,为Qt提供触摸输入支持。

tslib为触摸屏驱动和应用层之间的适配层,它把应用程序中读取触摸屏struct input_event类型数据并进行解析的操作过程进行了封装,向使用者提供了等装好的API接口。

二、tslib移植

1、编译tslib源码

下载 tslib 源码包

将下载好的源码包拷贝至Ubuntu系统中解压,创建一个目录用来安装tslib。

进入解压后的源码包目录中准备编译tslib源码,编译前记得先对交叉编译工具的环境进行设置:

c 复制代码
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

然后对tslib源码工程进行设置:

c 复制代码
./configure --host=arm-poky-linux-gnueabi --prefix=xx //这里的"xx"是安装路径

--host 选项用于指定交叉编译得到的库文件是运行在哪个平台,通常将--host 设置为交叉编译器名称的前缀,譬如 arm-pokylinux-gnueabi-gcc 前缀就是 arm-poky-linux-gnueabi;--prefix 选项则用于指定库文件的安装路径

接着make,然后再make install就可以了

2、tslib安装目录文件夹及移植

这里使用的根文件系统是挂载的BusyBox(之前跟着教程做的),内核和设备树使用的是出厂系统

1、bin目录

一些小工具,用于测试触摸屏。这个文件目录下的所有可执行文件要拷贝到开发板上的/bin目录下。

2、etc目录

里面就一个配置文件ts.conf,需要拷贝到开发板的/etc目录下

3、include目录

只有一个头文件tslib.h,包含了一些结构体数据结构以及API接口的声明,所以使用tslib提供的API就要包含这个头文件

4、lib目录

这里包含了编译tslib源码所得到的库文件,默认为动态库文件,也可以通过配置使其生成静态库文件,ts目录下存放的是一些插件库。这个目录下的所有库文件都要拷贝到开发板的/lib目录下。

5、share目录

教程上说可忽略。

三、tslib库的使用

1、环境变量配置

使用tslib前需要配置一些环境变量,因为它工作时需要依赖于一些环境变量

c 复制代码
export TSLIB_CONSOLEDEVICE=none //配置控制台设备文件名,直接为none即可
export TSLIB_FBDEVICE=/dev/fb0  //配置显示设备的名称
export TSLIB_TSDEVICE=/dev/input/event1 //配置触摸屏对应的设备节点
export TSLIB_CONFFILE=/etc/ts.conf //配置ts.con文件的路径
export TSLIB_PLUGINDIR=/lib/ts //配置插件所在的路径

配置到这就可以使用tslib提供的测试工具了,比如:

c 复制代码
ts_print:单点触摸工具
ts_print_mt:多点触摸工具
ts_print:在终端打印触摸点信息
... ...

如果不想每次开机都把环境变量配置敲一遍就配置一下/etc/profile(没有这个文件就自己创建一个),也可以不配置

c 复制代码
# /etc/profile

# 这是一个示例profile脚本

# No core files by default
ulimit -S -c 0 > /dev/null 2>&1

USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h \W]\# '
PATH=$PATH

HOSTNAME=`/bin/hostname`

export USER LOGNAME PS1 PATH

export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event1
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts

2、tslib库函数介绍

tslib的基本使用步骤:

  1. 打开触摸屏设备
  2. 配置触摸屏设备
  3. 读取触摸屏设备
  4. 关闭触摸屏设备

1、打开触摸屏设备

c 复制代码
#include "tslib.h"
struct tsdev *ts_open(const char *dev_name, int nonblock);
dev_name:触摸屏的设备节点
nonblock:
	0:阻塞方式打开触摸屏设备
	非0:非阻塞方式打开触摸屏设备
返回值:
	成功:返回一个 struct tsdev *指针,指向触摸屏设备句柄
	失败:NULL

struct tsdev *ts_setup(const char *dev_name, int nonblock)
dev_name:触摸屏的设备节点,
	当设置为NULL时函数内部会读取TSLIB_TSDEVICE 环境变量,
	获取该环境变量的内容以得知触摸屏的设备节点(就是之前设置的环境变量)
nonblock:
	0:阻塞方式打开触摸屏设备
	非0:非阻塞方式打开触摸屏设备
教程上说这个函数能对触摸屏设备进行配置,但是没有说怎么配置,也可能没找到,先空着

2、配置触摸屏设备

c 复制代码
#include "tslib.h"
int ts_config(struct tsdev *ts)
ts:指向触摸屏句柄,就是打开成功返回的那个
返回值:
	成功:0
	失败:-1

配置就是解析ts.conf文件中的配置信息,加载相应的插件。

3、读取触摸屏数据

c 复制代码
#include "tslib.h"

//读取单点触摸数据
int ts_read(struct tsdev *ts, struct ts_sample *samp, int nr)
samp:一个 struct ts_sample *类型的指针,指向一个struct ts_sample对象,获取到的数据会存这里面



//读取多点触摸数据
int ts_read_mt(struct tsdev *ts, struct ts_sample_mt **samp, int max_slots, int nr)
max_slots:触摸屏设备支持的最大触摸点数
samp :是一个 struct ts_sample_mt **类型的指针,多点触摸,每个触摸点的信息struct ts_sample_mt 数据结构来描述。
一个触摸点的数据就是struct ts_sample,这堆触摸点合起来就是struct ts_sample_mt 数组



ts:指向触摸屏设备句柄,就是打开成功返回的那个
nr:指定了 ts_read 函数要从设备中读取多少字节的数据。如果设备中没有足够的数据可供读取,则 ts_read 函数将等待,直到有足够的数据可供读取或者发生错误。,设置为1即可。

4、关闭触摸屏设备

c 复制代码
int ts_close(struct tsdev *);
//函数指针,只需要传递一个struct tsdev类型的指针就好了

5、结构体

c 复制代码
struct ts_sample {
	 int x; //X 坐标
	 int y; //Y 坐标
	 unsigned int pressure; //按压力大小
	 struct timeval tv; //时间
};

struct ts_sample_mt {
	 /* ABS_MT_* event codes. linux/include/uapi/linux/input-event-codes.h
	 * has the definitions.
	 */
	 int x; //X 坐标
	 int y; //Y 坐标
	 unsigned int pressure; //按压力大小
	 int slot; //触摸点 slot
	 int tracking_id; //ID
	 int tool_type;
	 int tool_x;
	 int tool_y;
	 unsigned int touch_major;
	 unsigned int width_major;
	 unsigned int touch_minor;
	 unsigned int width_minor;
	 int orientation;
	 int distance;
	 int blob_id;
	 struct timeval tv; //时间
	 /* BTN_TOUCH state */
	 short pen_down; //BTN_TOUCH 的状态
	 /* valid is set != 0 if this sample
	 * contains new data; see below for the
	 * bits that get set.
	 * valid is set to 0 otherwise
	 */
	 short valid; //此次样本是否有效标志 触摸点数据是否发生更新
};

四、应用编程

1、单点触摸

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <tslib.h> //包含 tslib.h 头文件
int main(int argc, char *argv[])
{
	 struct tsdev *ts = NULL;
	 struct ts_sample samp;
	 int pressure = 0;//用于保存上一次的按压力,初始为 0,表示松开
	 /* 打开并配置触摸屏设备 */
	 ts = ts_setup(NULL, 0);
	 if (NULL == ts) {
		 fprintf(stderr, "ts_setup error");
		 exit(EXIT_FAILURE);
	 }
	 /* 读数据 */
	 for ( ; ; ) {
		 if (0 > ts_read(ts, &samp, 1)) {
			 fprintf(stderr, "ts_read error");
			 ts_close(ts);
			 exit(EXIT_FAILURE);
	 	}
	 	if (samp.pressure) {//按压力>0
			 if (pressure) //若上一次的按压力>0
				 printf("移动(%d, %d)\n", samp.x, samp.y);
			 else
			 	printf("按下(%d, %d)\n", samp.x, samp.y);
	 	}
	 	else
		 	printf("松开\n");//打印坐标
		 pressure = samp.pressure;
	 }
	 ts_close(ts);
	 exit(EXIT_SUCCESS);
}

2、多点触摸

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <tslib.h>
int main(int argc, char *argv[])
{
	 struct tsdev *ts = NULL;
	 struct ts_sample_mt *mt_ptr = NULL;
	 struct input_absinfo slot;
	 int max_slots;
	 unsigned int pressure[12] = {0}; //用于保存每一个触摸点上一次的按压力,初始为 0,表示松开
	 int i;
	 /* 打开并配置触摸屏设备 */
	 ts = ts_setup(NULL, 0);
	 if (NULL == ts) {
		 fprintf(stderr, "ts_setup error");
		 exit(EXIT_FAILURE);
	 }
	 /* 获取触摸屏支持的最大触摸点数 */
	 if (0 > ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot)) {
		 perror("ioctl error");
		 ts_close(ts);
		 exit(EXIT_FAILURE);
	 }
	 max_slots = slot.maximum + 1 - slot.minimum;
	 printf("max_slots: %d\n", max_slots);
	 /* 内存分配 */
	 mt_ptr = calloc(max_slots, sizeof(struct ts_sample_mt));
	 /* 读数据 */
	 for ( ; ; ) {
		 if (0 > ts_read_mt(ts, &mt_ptr, max_slots, 1)) {
			 perror("ts_read_mt error");
			 ts_close(ts);
			 free(mt_ptr);
			 exit(EXIT_FAILURE);
	 	}
		 for (i = 0; i < max_slots; i++) {
			 if (mt_ptr[i].valid) {//有效表示有更新!
				 if (mt_ptr[i].pressure) { //如果按压力>0
					 if (pressure[mt_ptr[i].slot])//如果上一次的按压力>0
					 	printf("slot<%d>, 移动(%d, %d)\n", mt_ptr[i].slot, mt_ptr[i].x, mt_ptr[i].y);
					 else
					 	printf("slot<%d>, 按下(%d, %d)\n", mt_ptr[i].slot, mt_ptr[i].x, mt_ptr[i].y);
				 }
				 else
			    	 printf("slot<%d>, 松开\n", mt_ptr[i].slot);
				 pressure[mt_ptr[i].slot] = mt_ptr[i].pressure;
			 }
		 }
	 }
	 /* 关闭设备、释放内存、退出 */
	 ts_close(ts);
	 free(mt_ptr);
	 exit(EXIT_SUCCESS);
}

3、编译

c 复制代码
${CC} -I /home/xx/linux/tools/tslib/include -L /home/xx/linux/tools/tslib/lib -lts -o LCDAPP LCD.c

-I:可以让编译器在指定的目录中搜索头文件,以便正确地编译源代码文件。

/home/xx/linux/tools/tslib/include:tslib 库的头文件所在的目录。

-L:可以让编译器在指定的目录中搜索库文件,以便正确地链接库函数并生成可执行文件。

/home/xx/linux/tools/tslib/lib:tslib 库的库文件所在的目录。

-lts:指定了需要链接的库文件名,其中 -l 表示链接库文件,ts 表示库文件名为 libts.so。Linux 中,动态库文件的命名方式为 lib+名字+.so

-o:指定了编译生成的可执行文件的名称,其中LCDAPP是可执行文件的名称。

LCD.c:这个参数指定了需要编译的源代码文件的名称,其中 LCD.c 是 C 语言源代码文件的名称。

相关推荐
cominglately1 小时前
centos单机部署seata
linux·运维·centos
魏 无羡1 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos
CircleMouse1 小时前
Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
linux·运维·服务器·centos
木子Linux2 小时前
【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
linux·运维·服务器·centos·云计算
mit6.8242 小时前
Ubuntu 系统下性能剖析工具: perf
linux·运维·ubuntu
鹏大师运维2 小时前
聊聊开源的虚拟化平台--PVE
linux·开源·虚拟化·虚拟机·pve·存储·nfs
watermelonoops2 小时前
Windows安装Ubuntu,Deepin三系统启动问题(XXX has invalid signature 您需要先加载内核)
linux·运维·ubuntu·deepin
滴水之功3 小时前
VMware OpenWrt怎么桥接模式联网
linux·openwrt
枯无穷肉3 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
ldinvicible3 小时前
How to run Flutter on an Embedded Device
linux