写在前边
本文是B站up主韦东山的4_7-9.编写基于tslib的测试程序_哔哩哔哩_bilibili视频的笔记,其中有些部分博主也没有理解,希望各位辩证的看。
目录
基本知识
tslib 是一个触摸屏的开源库,可以使用它来访问触摸屏设备,可以给输入设 备 添 加 各 种 “ filter ” ( 过 滤 器 , 就 是 各 种 处 理 ) , 地 址 是 :http://www.tslib.org/。
编译 tslib 后,可以得到 libts 库,还可以得到各种工具:较准工具、测试工具。
官网地址:C library for filtering touchscreen events
tslib 框架分析
tslib 的主要代码位置
tslib 1主要代码
plugins目录下的每个文件都是一个 module,每个模块都会被编译成动态库,每个 module 都提供 2 个函数:read、read_mt,前者用于读取单点触摸屏的数据,后者用于读取多点触摸屏的数据。
tests目录下是测试程序:参考 ts_test.c 和ts_test_mt.c,前者用于一般触摸屏(比如电阻屏、单点电容屏),后者用于多点触摸屏。
tslib 2tslib框架图
交叉编译、测试 tslib
首先先安装依赖库
sudo apt-get install autoconf automake libtool
然后需要根据自己板子的交叉编译工具链安装:
其中arm-linux-gnueabihf就是你的交叉编译工具链,你需要根据自己的工具链将这里进行替换。
./configure --host=arm-linux-gnueabihf --prefix=/
make
make install DESTDIR=$PWD/tmp
这里完成后会在当前文件夹下产生tslib的各种文件,接下来需要将某些文件加入到工具链的目录中,以便程序在编译时可以找到这些库函数。
这里需要做的是先知道这些工具链的目录在哪里:
echo 'main(){}'| arm-linux-gnueabihf-gcc -E -v -
同样的,arm-linux-gnueabihf是交叉编译工具链,将这里替换成自己的工具链。
tslib 3工具链目录
// 下边的这些命令我直接复制的百问的命令,所以这里边的工具链和我标出的不太一样,这里需按照自己的板子上的工具链进行替换。
cd tslib-1.21/tmp/
cp include/* /home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/../arm-linux-gnueabihf/libc/usr/include
cp -d lib/*so* /home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/../arm-linux-gnueabihf/libc/usr/lib/
这些完成之后,需要将库文件放到板子上运行(这里我提前挂载了网络文件系统):
cp /mnt/tslib-1.21/tmp/lib/*so* -d /lib
cp /mnt/tslib-1.21/tmp/bin/* /bin
cp /mnt/tslib-1.21/tmp/etc/ts.conf -d /etc
完成之后就可以在板子上运行tslib库了。
示例程序
下边是我做的一个画板程序,主要功能为可以在上边画线,点击上边颜色部分可以切换画线颜色。
tslib 4画板实物
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <tslib.h>
#include <sys/mman.h>
#include <linux/fb.h>
// 可变参数结构体
static struct fb_var_screeninfo var; /* current var */
// 屏幕文件的句柄
static int fd_fb;
// 整个屏幕的像素个数
static int screen_size;
// 指向映射的区域指针
static unsigned char* fb_base;
// 一行有多少像素
static unsigned int line_width;
// 一个像素多少byte
static unsigned int pixel_width;
// 定义颜色
unsigned int color = 0;
// 描点函数(color格式:0x00RRGGBB)
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char* pen_8 = fb_base + y * line_width + x * pixel_width;
unsigned short* pen_16;
unsigned int* pen_32;
unsigned int red, green, blue;
pen_16 = (unsigned short*)pen_8;
pen_32 = (unsigned int*)pen_8;
switch (var.bits_per_pixel) { /* bpp 像素深度 */
case 8:
{
*pen_8 = color;
break;
}
case 16:
{
/* RGB565 */
red = (color >> 16) & 0xFF;
green = (color >> 8) & 0xFF;
blue = (color >> 0) & 0xFF;
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = color;
break;
}
case 32:
{
/* RGB888 */
*pen_32 = color;
break;
}
default:
{
printf("Can't support %d bpp\n", var.bits_per_pixel);
break;
}
}
}
// 画线函数(color格式:0x00RRGGBB)
// x1,y1,x2,y2: 线段的起点和终点坐标
// color: 线段的颜色
void lcd_draw_line(int x1, int y1, int x2, int y2, unsigned int color)
{
// abs函数用于求绝对值
int dx = abs(x2 - x1);
int dy = abs(y2 - y1);
int sx = (x1 < x2) ? 1 : -1;
int sy = (y1 < y2) ? 1 : -1;
int err = dx - dy;
int e2;
while (1) {
lcd_put_pixel(x1, y1, color);
if (x1 == x2 && y1 == y2)
break;
e2 = 2 * err;
if (e2 > -dy) {
err = err - dy;
x1 = x1 + sx;
}
if (e2 < dx) {
err = err + dx;
y1 = y1 + sy;
}
/*printf("x1: %d, y1: %d\n", x1, y1);*/
}
}
// 选择颜色函数
void select_color(int x)
{
if (x < 100)
{
color = 0xFF0000; // 红色
}
else if (x < 200)
{
color = 0x000000; // 黑色
}
else if (x < 300)
{
color = 0xCC5500; // 燃橙
}
else if (x < 400)
{
color = 0x996B1F; // 卡其色
}
else if (x < 500)
{
color = 0xFFFFF0; // 象牙色
}
else if (x < 600)
{
color = 0xFFFF00; // 黄色
}
else if (x < 700)
{
color = 0x99FF4D; // 嫩绿
}
else if (x < 800)
{
color = 0xB0E0E6; // 婴儿粉蓝
}
else if (x < 900)
{
color = 0x000080; // 藏青
}
else
{
color = 0xEE82EE; // 亮紫
}
}
// (实心)矩形函数(color格式:0x00RRGGBB)
// x1,y1,x2,y2: 矩形的左上角和右下角坐标
// color: 矩形的颜色
void lcd_draw_rect(int x1, int y1, int x2, int y2, unsigned int color)
{
for (int i = y1; i < y2; i++)
{
for (int j = x1; j < x2; j++)
{
lcd_put_pixel(j, i, color);
}
}
}
int distance(struct ts_sample_mt* point1, struct ts_sample_mt* point2)
{
int x = point1->x - point2->x;
int y = point1->y - point2->y;
return x * x + y * y;
}
int main(int argc, char** argv)
{
struct tsdev* ts;
int i;
int ret;
struct ts_sample_mt** samp_mt;
int x = 0, y = 0;
int max_slots;
int point_pressed[20];
struct input_absinfo slot;
int touch_cnt = 0;
static int first_click = 1; // 标志变量,初始为1表示第一次点击
ts = ts_setup(NULL, 0);
if (!ts)
{
printf("ts_setup err\n");
return -1;
}
if (ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot) < 0) {
perror("ioctl EVIOGABS");
ts_close(ts);
return errno;
}
max_slots = slot.maximum + 1 - slot.minimum;
samp_mt = malloc(sizeof(struct ts_sample_mt*));
if (!samp_mt) {
ts_close(ts);
return -ENOMEM;
}
samp_mt[0] = calloc(max_slots, sizeof(struct ts_sample_mt));
if (!samp_mt[0]) {
free(samp_mt);
ts_close(ts);
return -ENOMEM;
}
for (i = 0; i < max_slots; i++)
samp_mt[0][i].valid = 0;
// 打开文件,获得文件句柄
int fd_fb = open("/dev/fb0", O_RDWR);
// 获取设备参数
ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
// 内存映射
line_width = var.xres * var.bits_per_pixel / 8; // 一行多少byte
pixel_width = var.bits_per_pixel / 8; // 一个像素多少byte
screen_size = var.xres * var.yres * var.bits_per_pixel / 8; // 一屏多少byte
fb_base = (unsigned char*)mmap(NULL, var.xres * var.yres * var.bits_per_pixel / 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
/* 清屏: 全部设为白色 */
memset(fb_base, 0xFF, screen_size);
x = 0;
y = 0;
lcd_draw_rect(0, 0, 100, 100, 0xFF0000); // 画一个矩形红色
lcd_draw_rect(100, 0, 200, 100, 0x000000); // 画一个矩形黑色
lcd_draw_rect(200, 0, 300, 100, 0xCC5500); // 画一个矩形燃橙
lcd_draw_rect(300, 0, 400, 100, 0x996B1F); // 画一个矩形卡其色
lcd_draw_rect(400, 0, 500, 100, 0xFFFFF0); // 画一个矩形象牙色
lcd_draw_rect(500, 0, 600, 100, 0xFFFF00); // 画一个矩形黄色
lcd_draw_rect(600, 0, 700, 100, 0x99FF4D); // 画一个矩形嫩绿
lcd_draw_rect(700, 0, 800, 100, 0xB0E0E6); // 画一个矩形婴儿粉蓝
lcd_draw_rect(800, 0, 900, 100, 0x000080); // 画一个矩形藏青
lcd_draw_rect(900, 0, 1000, 100, 0xEE82EE); // 画一个矩形亮紫
while (1)
{
ret = ts_read_mt(ts, samp_mt, max_slots, 1);
if (ret < 0) {
printf("ts_read_mt err\n");
ts_close(ts);
return -1;
}
if (samp_mt[0][0].valid && samp_mt[0][0].tracking_id != -1)
{
// 如果是第一次点击,则记录坐标
if (first_click)
{
x = samp_mt[0][0].x;
y = samp_mt[0][0].y;
first_click = 0;// 设置标志变量为0,表示不再是第一次点击
}
else
{
// 画线区域
if (samp_mt[0][0].y > 100)
{
lcd_draw_line(x, y, samp_mt[0][0].x, samp_mt[0][0].y, color);
x = samp_mt[0][0].x;
y = samp_mt[0][0].y;
}
}
}
else
first_click = 1;
// 选择颜色区域
if (samp_mt[0][0].y < 100)
{
select_color(samp_mt[0][0].x);
}
}
return 0;
}