本文是作者对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 caught/n", 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函数。

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);
        }

这里可能会发生一个非常经典的出错提示信息,有兴趣的可以看看这篇文章:

Linu移植随笔:由ts_config:Success想到的

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:%d/n", 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 %6d/n", 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: %d/n", mode, x, y);
else
        mode &= ~0x80000000;
debug("the end of while (1), mode: %x/n", 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:%d/n", button->flags);
                                button_draw (button);
                        }
                }
                else if (button->flags & BUTTON_ACTIVE)
                {
                        button->flags &= ~BUTTON_ACTIVE;
                        debug("(outside button BUTTON_ACTIVE)button->flags:%d/n", button->flags);
                        button_draw (button);
                }
        }
        else if (button->flags & BUTTON_ACTIVE)
        {
                button->flags &= ~BUTTON_ACTIVE;
                debug("(pressure == 0 return here)button->flags:%d/n", button->flags);
                button_draw (button);
                return 1;
        }

return 0;
}

inside为1时表示触摸笔点击的坐标位于按钮之内,前面已经写出几个按钮的坐标范围了。当触摸笔接触屏幕时,即pressure>0,如果落点位于按钮范围之内,假如按钮是非激活状态,则激活按钮(设置flags为BUTTON_ACTIVE),反之,则不激活按钮。flags的值主要是用于显示按钮的各种颜色(即边框、填充色及字符串颜色),详细可以看代码。

当释放触摸笔时,如果按钮激活的话,返回值为1,这时才能让 if (button_handle (&buttons [i], &samp))语句继续执行。如果不是的话,返回0(当触摸笔在不是按钮处乱点、乱画时,应该就是这种情况)。

至此,这个文件大约胡乱分析完了。不过,我们只知道由ts_read得到坐标的采样,却不知道从何处而来。下面就跟踪坐标采样的过程。

ret = ts_read(ts, &samp, 1);

将坐标信息放到samp结构体中,ts_read函数来自ts_read.c文件,只有一个关键语句:

result = ts->list->ops->read(ts->list, samp, nr);

其中ts->list->ops成员为tslib_ops结构体指针,该结构体定义如下:

struct tslib_ops {
        int (*read)(struct tslib_module_info *inf, struct ts_sample *samp, int nr);
        int (*fini)(struct tslib_module_info *inf);
};

它有两个函数指针,其中的read就是要实现的。线索到此似乎断了。因为函数指针也是指针(这是废话,请无视之),它总得要指向一个东西才行,但是这里却找不到。

不过,前面提及到ts_config函数,这个函数就是读取指定的文件ts.conf(由TSLIB_CONFFILE环境变量指定)。这个文件很简单,就是一些模块信息,比如输入设备,可以用module_raw input指定input,或者用module_raw h3600指定使用HP iPaq h3600,等等。ts.conf文件由ts_config.c文件的ts_config函数读取,由于实际中使用的是input模块,ts.conf文件第一行为module_raw input,由

else if (strcasecmp(tok, "module_raw") == 0) {
        module_name = strsep(&p, " /t");
        ret = ts_load_module_raw(ts, module_name, p);
}

读取模块名称并加载。

input模块使用的是input_raw.c文件,该文件中有如下结构体的定义:

static const struct tslib_ops __ts_input_ops = {
        .read        = ts_input_read,
        .fini        = ts_input_fini,
};

它使用的正是结构体tslib_ops,变量名称为__ts_input_ops。该变量在同一文件的input_mod_init函数中使用到。

i->module.ops = &__ts_input_ops;
        i->current_x = 0;
        i->current_y = 0;
        i->current_p = 0;
        i->sane_fd = 0;
        i->using_syn = 0;
        i->grab_events = 0;

而这个函数大约可以理解为Linux驱动程序中的xxx_init函数。同样地,__ts_input_ops中的fini指针指向的ts_input_fini函数可以理解为xxx_exit函数。

至此,除了触摸屏的驱动程序和tslib读取坐标函数外,其它表面上看得到的东西已经大致了解了。本文也该结束了。附图一张:

触摸屏测试——来自latelee.org

(图中字体颜色不清楚,后4行颜色分别是红、绿、蓝、黄)

后记:

网上很流行代码分析,特别是Linux、U-Boot,那些文章讲的都很详细。不过,这篇分析tslib库中的一个测试程序的文章,没什么深度,也不详细。主要原因是作者水平有限,很多东西都不懂,说来惭愧,连按位与、按位或,都要亲自用代码测试一次才敢写出结论。此外,文中也有许多猜测的地方,主要是由于作者经过实践,看到了结果,因此想当然地认为结论是这样。“纸上得来终觉浅,绝知此事要躬行”,但也可能会由于一些错误的认识而导致错误的实践结果。作者接触tslib时日不多,本文完成时间花费约3到4天时间。

小子无知,虽不妄自菲薄,但亦诚惶诚恐,如履薄冰。

最新后记:

在本文即将完成之时,由于误操作,使得开发板的文件系统引导不起来,文中代码所示例的调试信息无法演示。版本控制再次引导作者的注意,由此而学习git,并且有了初步的认识。关于未来更多的学习及文章,请继续关注迟思堂工作室

主要参考:

1、tslib库的很多代码;

2、开发板上的系统、触摸屏上显示的数据、串口上显示的坐标及调试信息。

最后附上经过修改(只是稍微修改一下下而已)的ts_test.c源代码:

迟 记于4月下旬

Linux移植随笔:对tslib库的ts_test测试程序代码的一点分析相关推荐

  1. Linux移植随笔 tslib

    前段时间让Tslib搞晕头了,原来一切都是版本惹的祸.本文只是一个随笔,随笔者,随意用笔写下心得而已,因此不必较真.正如我所欣赏的"乘兴而来,兴尽而返"一样.--估计当年王子猷是赏 ...

  2. Linux移植随笔:终于解决Tslib的问题了【转】

    转自:http://www.latelee.org/embedded-linux/porting-linux-tslib.html 前段时间让Tslib搞晕头了,原来一切都是版本惹的祸.本文只是一个随 ...

  3. Linux移植随笔:终于解决Tslib的问题了

    前段时间让Tslib搞晕头了,原来一切都是版本惹的祸.本文只是一个随笔,随笔者,随意用笔写下心得而已,因此不必较真.正如我所欣赏的"乘兴而来,兴尽而返"一样.--估计当年王子猷是赏 ...

  4. Linux移植随笔:又遇困难

    前段时间没有发表这方面的文章,是因为在搞qtopia-2.2.0,区分QT那几个版本花了一点时间,编译qtopia也花了一点时间.点滴之间,才发现时间悄然逝去. 上次u-boot移植时也遇到困难,这次 ...

  5. Linux移植随笔:git的使用

    昨天搞了一天的yaffs2文件系统挂载,结果还是挂载不上去.收获之一是知道如何使用git下载源代码. 以前下载的yaffs2源代码在新的内核中编译不通过,而又不知道如何下载yaffs2的源代码包,只好 ...

  6. Linux移植随笔:让内核支持nor flash

    内核:linux-2.6.37.3 nor flash芯片:SST39VF6401B 网上有文章说了如何让linux内核支持nor flash.不过那些转载的文章中没有头文件(因为使用了<尖括号 ...

  7. linux安装配置软件厂库,Centos8 安装 Gogs 代码仓库管理工具

    Gogs 的目标是打造一个最简单.最快速和最轻松的方式搭建自助 Git 服务.使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发,并且支持 Go 语言支持的所有平台,包括Linux.Mac ...

  8. 海思linux中编译,基于海思开发环境,交叉编译,安装tslib库

    环境:Ubuntu-18.04 64位 交叉编译器:arm-hisiv600-linux tslib版本:tslib-1.4 一.安装交叉编译器 [注意]本文中使用 Hi3531D 的 V600 编译 ...

  9. 交叉编译 for arm-linux-gcc... no,QT4.8.6、tslib库移植到arm上配置出错!求大神指点

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 操作系统:Ubuntu14.04 LTS ; Qt版本:Qt4.8.6 for embedded 交叉编译器:arm-linux-gcc-v6-vfp-2 ...

最新文章

  1. 改变自己从学习linux开始
  2. WINCE6.0+S3C6410下的DM9000A驱动
  3. 正则表达式匹配非字母或者数字
  4. 黑龙江省:2025年将建成5G基站11.4万个,15万数据中心机架
  5. 抑郁症自测量表测试软件,快来测测抑郁--抑郁自评量表 (此表是是收费工具,我献给大家)...
  6. VSCODE远程连接服务器,远程开发。
  7. apache的poi中设置Excel的单元格样式(HSSFCellStyle)和表格(HSSFSheet)
  8. 京瓷1125打印机清零_怎么设置京瓷1125MFP打印机ip地址
  9. 微信小程序开源框架wxSortPickerView:微信小程序首字母排序选择表
  10. EDA和数据挖掘实战:漫威与 DC电影收视率和票房分析
  11. 苹果系统是通过服务器推送消息,客户端技术:一文带你了解iOS消息推送机制
  12. 上帝模式下的shellcode
  13. 移动UI设计-表单设计
  14. python读取HTML文本文件
  15. [渝粤教育] 中国地质大学 生产与作业管理 复习题 (2)
  16. Ubuntu 14.04 配置 Java SE jdk-7u55
  17. (链表解决)13个人围成一圈,从第一个人开始顺序报号1,2,3,凡报到3的人,退出圈子,找出最后留在圈子里的人的序号。
  18. 做一个优秀的时间管理者
  19. 20180402-F · US Tuition Costs · pheatmap 绘制热图 · R 语言数据可视化 案例 源码
  20. 网页设计技巧:如何做好图片与文字的配合?

热门文章

  1. 三星宣布华大九天成为其晶圆代工生态系统SAFE EDA合作伙伴
  2. 北交所开市工作准备就绪 定于2021年11月15日开市
  3. Twitter进军NFT领域 发布并赠送7款NFT数字艺术品
  4. 研究机构:苹果M1芯片代工订单占台积电5nm工艺25%产能
  5. 花2.9元买一包头绳,收到一张3元好评返现卡,我凌乱了……
  6. 产业链人士:存储芯片平均售价有望在明年一季度停止下滑 随后趋于稳定
  7. 华为Mate 40系列还有新升级:有望首发66W超级快充
  8. 和平精英、宾果消消消等多款游戏APP存隐私不合规行为
  9. 任正非给华为代表处CFO定位:能力不够的赶快补
  10. 14家文化机构联合抖音、今日头条启动“都来读书”计划