Linux移植随笔:对tslib库的ts_test测试程序代码的⼀点分析
【转】
本⽂是作者对tslib库的ts_test.c⽂件进⾏分析的随笔,其实tslib的⼏个测试程序结构差不多,譬如ts_print.c和ts_print_raw.c等。
本⽂并没有涉及太多概念,也没有详细介绍这些概念,但并不代表作者对此不了解,也不代表作者对此很精通。如⽂中提到的input,虽只出现⼀个单词,但是相信许多⼈都知道它在⽂中指的是Linux操作系统下的input⼦系统,该⼦系统不简单,看三天三夜也未必能全⾯掌握。作者⽔平有限,真正接触tslib不超过⼀周,错误在所难免,欢迎指正(可在⽂后留⾔,亦可在本站搜索作者联系⽅式)。
本⽂不涉及tslib的移植,如果感兴趣,可以看看这篇⽂章(有图有真相):
Linux移植随笔:终于解决Tslib的问题了
运⾏ts_test,在触摸屏上⽅显⽰三个按钮,按钮正⽂显⽰两⾏信息(效果图可参考上⾯给出的链接⽂章),当⽤笔触摸屏幕时,屏幕上有相应的显⽰(取决于“Drag”和“Draw”按钮),终端上会显⽰⼀些信息。⼀般地,没有添加任何调试信息时显⽰如下:
1302776697.620288:    99    20      1
前⾯两个是timeval结构体的两个成员:tv_sec和tv_usec,中间两列分别是X和Y的坐标,最后为pressure,这⾥可以理解成“触摸事件”,为1表⽰触摸笔点击了(接触)屏幕,为0表⽰触摸笔离开了屏幕。
我们将ts_test.c⽂件中的main函数分成4个部分(添加调试信息后的完整的源代码⽂件附于⽂后):
1、设置信号处理,有3个:SIGSEGV、SIGINT和SIGTERM;
2、打开触摸屏设备、读取配置信息(ts.conf⽂件);
3、画框(按钮)并显⽰字符串;
4、事件处理,包括在终端上显⽰信息、在屏幕上显⽰⼗字架或⽤触摸笔画的线条。
下⾯分别讲⼀下:
1、信号处理
调⽤signal函数处理3种信号:
signal(SIGSEGV, sig);
signal(SIGINT, sig);
signal(SIGTERM, sig);
其中sig函数如下:
static void sig(int sig)
{
close_framebuffer();
fflush(stderr);
printf(“signal %d caughtn”, sig);
fflush(stdout);
exit(1);
}
第⼀个为SIGSEGV,即Segmentation violation。⽹上有资料显⽰,如果在ts.conf中module_raw input前
留有空格,会出现Segmentation fault。不过不敢确定出现段错误是系统处理的还是tslib处理的——因为终端没有显⽰sig函数中打印的字符串。
第⼆个是SIGINT,Interrupt,按Ctrl+c产⽣,如果在运⾏ts_test时按Ctrl+c,程序会退出,同时终端上显⽰:^Csignal 2 caught。^C是按Ctrl+C显⽰的,⽽signal 2 caught则是sig函数中打印的。详细的signal号可以在<bits/signum.h>中到。在我的系统中,
是/usr/include/bits/signum.h 。
最后⼀个是SIGTERM,Termination,由kill(1)命令发送的系统默认终⽌信号,kill(1)表⽰“kill”是kill命令,⽽⾮系统调⽤的kill函数。
linux字符串转数组
2、触摸屏设备及配置
打开触摸屏设备:
if( (tsdevice = getenv(“TSLIB_TSDEVICE”)) != NULL ) {
ts = ts_open(tsdevice,0);
} else {
if (!(ts = ts_open(“/dev/input/event0″, 0)))
ts = ts_open(“/dev/touchscreen/ucb1x00″, 0);
前⾯提到的⽂章中说tslib默认的设备⽂件系统为“/dev/input/event0”,从这⾥的代码就可以看出来了。
读取ts.conf⽂件:
if (ts_config(ts)) {
perror(“ts_config”);
exit(1);
}
这⾥可能会发⽣⼀个⾮常经典的出错提⽰信息,有兴趣的可以看看这篇⽂章:
3、画图及显⽰字符串
在屏幕上画图:
x = xres/2;
y = yres/2;
for (i = 0; i < NR_COLORS; i++)
setcolor (i, palette [i]);
/* Initialize buttons */
memset (&buttons, 0, sizeof (buttons));
buttons [0].w = buttons [1].w = buttons [2].w = xres / 4;
buttons [0].h = buttons [1].h = buttons [2].h = 20;
buttons [0].x = 0;
buttons [1].x = (3 * xres) / 8;
buttons [2].x = (3 * xres) / 4;
buttons [0].y = buttons [1].y = buttons [2].y = 10;
buttons [0].text = “Drag”;
buttons [1].text = “Draw”;
buttons [2].text = “Quit”;
refresh_screen ();
其中xres为240,yres为320,(0,0)为左上⾓坐标(了解计算机图形学的可能知道)。根据这些代码,可以知道3个按钮的坐标范围。“Drag”按钮x坐标为0~60,“Draw”按钮x坐标为90~150,⽽“Quit”按钮x坐标为180~240。⽽3个按钮y坐标都⼀样,范围是10~30。接着在屏幕上显⽰:
static void refresh_screen ()
{
int i;
fillrect (0, 0, xres – 1, yres – 1, 0);
put_string_center (xres/2, yres/4,  “TSLIB test program”, 1);
put_string_center (xres/2, yres/4+20,“Touch screen to move crosshair”, 2);
#ifdef TS_DEBUG
/* just a test */
int j;
int y = yres/4+30;
for (j = 0; j < 255; j++, y+=20)
put_string(0, y, “Hello from Late Lee”, j);
//printf(“y:%d, j:%dn”, y, j);
for (i = 0; i < NR_BUTTONS; i++)
button_draw (&buttons [i]);
}
/* end of the test */
#endif
}
先显⽰两⾏字符串,再调⽤button_draw函数画按钮:
static void button_draw (struct ts_button *button)
{
int s = (button->flags & BUTTON_ACTIVE) ? 3 : 0;
rect (button->x, button->y, button->x + button->w – 1,
button->y + button->h – 1, button_palette [s]);
fillrect (button->x + 1, button->y + 1,
button->x + button->w – 2,
button->y + button->h – 2, button_palette [s + 1]);
put_string_center (button->x + button->w / 2,
button->y + button->h / 2,
button->text, button_palette [s + 2]);
}
button_palette为调⾊板索引号,前⾯3个是不激活(接触)按钮的颜⾊,后3个是激活按钮时的颜⾊。依次为边框⾊、填充⾊和⽂字颜⾊。
/* [inactive] border fill text [active] border fill text */
static int button_palette [6] =
{
1, 4, 2,
1, 5, 0
};
这⾥的palette(调⾊板)是作者在原代码基本上额外添加⼏种颜⾊:
static int palette [] =
{
0x000000, 0xffe080, 0xffffff, 0xe0c0a0, 0x304050,
0x80b8c0, 0x6600cc, 0xff0000, 0x00ff00, 0x0000ff, 0xffff00
};
后⾯5种分别为紫⾊、红⾊、、绿⾊、蓝⾊、黄⾊(前⾯⼏种除0x000000(⿊⾊)和0xffffff(⽩⾊)外不好⽤⽂字描述)。
在前⾯的refresh_screen添加了如下函数:
put_string(0, y, “Hello from Late Lee”, j);
本意是打印0~255种颜⾊的字体,可事与愿违,屏幕上只显⽰10种颜⾊。从上⾯的palette数组中我们知道⼀共有11种颜⾊,⽽在main函数中⽤如下语句设置颜⾊:
for (i = 0; i < NR_COLORS; i++)
setcolor (i, palette [i]);
⼀种可能的解释是:第1种⿊⾊在屏幕上显⽰了,但看不出来(可以⽤触摸笔触摸按钮,看按钮的各种颜⾊变化)。
4、事件处理
这是⼀个while(1)循环,当⽤触摸笔点击“Quit”按钮或按“Ctrl+C”时退出。
⾸先在屏幕上显⽰⼗字架:
/* Show the cross */
if ((mode & 15) != 1) {
put_cross(x, y, 2 | XORMODE);
}
之后读取坐标:
ret = ts_read(ts, &samp, 1);
跟着判断屏幕上3个按钮的事件:
for (i = 0; i < NR_BUTTONS; i++)
if (button_handle (&buttons [i], &samp))
switch (i) {
case 0:
mode = 0;
refresh_screen ();
break;
case 1:
mode = 1;
refresh_screen ();
break;
case 2:
quit_pressed = 1;
}
当是“Drag”时,mode为0,⽽“Draw”时mode为1。
然后在终端(⾄于printf与终端、串⼝之间的关联,⾮本⽂范围,不讨论)上显⽰坐标:
printf(“%ld.%06ld: %6d %6d %6dn”, samp.tv.tv_sec, samp.tv.tv_usec,
samp.x, samp.y, samp.pressure);
后⾯根据每个按钮作出不同响应:
if (samp.pressure > 0) {
if (mode == 0x80000001)
line (x, y, samp.x, samp.y, 2);
x = samp.x;
y = samp.y;
mode |= 0x80000000;
debug(“mode(pressure>0): %x x: %d y: %dn”, mode, x, y);
} else
mode &= ~0x80000000;
debug(“the end of while (1), mode: %xn”, mode);
if (quit_pressed)
break;
当触摸笔点击屏幕时,samp.pressure 值为1,此时才会产⽣相应的操作:当mode为1(实际值为0x80000001)时,会调⽤line函数画线条,该函数最后⼀个参数为2,应该是对应前⾯palette数组的第3个颜⾊值,即⽩⾊。⽽当mode为0(实际值为0x80000000)时,即在屏幕上显⽰⼗字架者,除了将新采集到的坐标值赋与x、y外,还将mode和0x80000000按位或(“|”),这个值作⽤于while(1)循环。当触摸笔点击“Quit”时,即quit_pressed值为1,退出while(1)循环。
还记得前⾯显⽰⼗字架的代码吗?
/* Show the cross */
if ((mode & 15) != 1) {
put_cross(x, y, 2 | XORMODE);
}
当mode为0(实际值为0x80000000)时,它与15相与,结果为0,会显⽰⼗字架了。
在while(1)结束前将mode复原:
mode &= ~0x80000000;
最后,关闭显⽰屏。
现在看⼀下button_handle函数,为了更清晰地显⽰该函数中的层次,将⼏个⼤括号移动⼀下:
static int button_handle (struct ts_button *button, struct ts_sample *samp)
{
int inside = (samp->x >= button->x) && (samp->y >= button->y) &&
(samp->x < button->x + button->w) &&
(samp->y < button->y + button->h);
if (samp->pressure > 0)
{
if (inside)
{
if (!(button->flags & BUTTON_ACTIVE))
{
button->flags |= BUTTON_ACTIVE;
debug(“(inside button: !BUTTON_ACTIVE)button->flags:%dn”, button->flags);
button_draw (button);
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。