文档章节

tslib机制分析

雨焰
 雨焰
发布于 2012/09/27 17:45
字数 2162
阅读 1301
收藏 2
tslib,其实从他的名字就可以看出它的,它是touchscreen的lib,其实这样还不够具体,其实它开始确实是为了touchscreen的鼠标驱动而发展起来的,且只是一个中间处理库,即将原始数据进行调整,比如触摸屏定位。只不过后来不知道什么原因,它火了,其他图形都支持这种方式,像高级版本的minigui,qt等成熟嵌入式图形系统。正因为如此,它也就不再局限于touchsrceen,只要是输入设备,只需在tslib里实现,标准的图形系统只需调用tslib的函数即可。
    刚开始时,我曾认为tslib属于驱动层,它将其他的输入设备数据处理后成为一个虚拟设备的数据,其他的图形系统只需使用这个虚拟的设备即可实现输入设备的读写操作了。后来发现tslib只不过是一个应用程软件,其他的图形系统使用的是tslib的函数,因此需要依赖这个库.如果大家移植过qt,估计还记得-no-mouse-linuxtp -qt-mouse-tslib -I/mnt/nfs/tslib/include -L/mnt/nfs/tslib/lib
其实这里就是用到tslib的库及头文件。
   下面说一下,tslib的原理。
  首先来看下tslib的源码结构
.
|-- AUTHORS
|-- COPYING
|-- ChangeLog
|-- INSTALL
|-- Makefile
|-- Makefile.am
|-- Makefile.in
|-- NEWS
|-- README
|-- aclocal.m4
|-- autogen-clean.sh
|-- autogen.sh
|-- autom4te.cache
|   |-- output.0
|   |-- output.1
|   |-- requests
|   |-- traces.0
|   `-- traces.1
|-- config.guess
|-- config.h
|-- config.h.in
|-- config.h.in~
|-- config.log
|-- config.status
|-- config.sub
|-- configure
|-- configure.in
|-- cscope.files
|-- cscope.out
|-- depcomp
|-- etc
|   |-- Makefile
|   |-- Makefile.am
|   |-- Makefile.in
|   `-- ts.conf
|-- install-sh
|-- libtool
|-- ltmain.sh
|-- missing
|-- plugins
|   |-- Makefile
|   |-- Makefile.am
|   |-- Makefile.in
|   |-- dejitter.c
|   |-- linear.c
|   |-- mousebuts.c
|   `-- variance.c
|-- src
|   |-- Makefile
|   |-- Makefile.am
|   |-- Makefile.in
|   |-- cscope.files
|   |-- cscope.out
|   |-- ts_attach.c
|   |-- ts_close.c
|   |-- ts_config.c
|   |-- ts_error.c
|   |-- ts_fd.c
|   |-- ts_load_module.c
|   |-- ts_open.c
|   |-- ts_parse_vars.c
|   |-- ts_read.c
|   |-- ts_read_raw.c
|   |-- tslib-filter.h
|   |-- tslib-private.h
|   `-- tslib.h
|-- stamp-h1
|-- tags
`-- tests
    |-- Makefile
    |-- Makefile.am
    |-- Makefile.in
    |-- fbutils.c
    |-- fbutils.h
    |-- font.h
    |-- font_8x16.c
    |-- font_8x8.c
    |-- ts_calibrate.c
    |-- ts_print.c
    |-- ts_print_raw.c
    `-- ts_test.c
  上面的src是核心,plugin是处理规则的实现,etc中是默认配置文件。
  我们一个tslib的具体实例来说明tslib的过程。
  比如我在Minigui1.6实现的tslib输入模块。
BOOL Init2410Input (INPUT* input, const char* mdev, const char* mtype)
{
    /* mdev should be /dev/ts */
    printf("in tslib engineer");
    tsd = ts_open(mdev, 0);
    if (!tsd) {
    perror("ts_open");
    exit(1);
    }
    if (ts_config(tsd)) {
    perror("ts_config");
    exit(1);
    }
    input->update_mouse = mouse_update;
    input->get_mouse_xy = mouse_getxy;
    input->set_mouse_xy = NULL;
    input->get_mouse_button = mouse_getbutton;
    input->set_mouse_range = NULL;
//-----------------------------------
    input->update_keyboard = NULL;
    input->get_keyboard_state = NULL;
    input->set_leds = NULL;
    
//-----------------------------------
    input->wait_event = wait_event;
    mousex = 0;
    mousey = 0;
    ts_event.x = ts_event.y = ts_event.pressure = 0;
    return TRUE;
}
在初始化函数里打开设备这个是ts_open
struct tsdev *ts_open(const char *name, int nonblock)
{
    struct tsdev *ts;
    int flags = O_RDONLY;
    if (nonblock)
        flags |= O_NONBLOCK;
    ts = malloc(sizeof(struct tsdev));
    if (ts) {
#ifdef USE_INPUT_API
        int version;
        long bit;
#endif /* USE_INPUT_API */
        memset(ts, 0, sizeof(struct tsdev));
        ts->fd = open(name, flags);
        if (ts->fd == -1)
            goto free;
#ifdef USE_INPUT_API
        /* make sure we're dealing with a touchscreen device */
        if (ioctl(ts->fd, EVIOCGVERSION, &version)             version != EV_VERSION ||
            ioctl(ts->fd, EVIOCGBIT(0, sizeof(bit)*8), &bit)             !(bit & (1             ioctl(ts->fd, EVIOCGBIT(EV_ABS, sizeof(bit)*8), &bit)             !(bit & (1             !(bit & (1             !(bit & (1             goto close;
#endif /* USE_INPUT_API */
        __ts_attach(ts, &__ts_raw);
    }
    return ts;
#ifdef USE_INPUT_API
close:
    close(ts->fd);
#endif /* USE_INPUT_API */
free:
    free(ts);
    return NULL;
}
上面的就是直接使用一般open打开设备文件。大家请注意上面调用的__ts_attach这个函数。这个函数非常重要。
int __ts_attach(struct tsdev *ts, struct tslib_module_info *info)
{
    info->dev = ts;
    info->next = ts->list;
    ts->list = info;
    return 0;
}
它其实就是将输入设备的处理规则挂在设备的list链表上,然后当图形系统调用ts_read时,就按顺序执行了数据处理函数。上面我们可以看到添加了raw规则,就是读取raw数据,等下会详细讲解规则的执行流程。
  上面的ts_config函数就是添加其他规则的函数。
  int ts_config(struct tsdev *ts)
{
    char buf[80], *p;
    FILE *f;
    int line = 0, ret = 0;
    char *conffile;
    if( (conffile = getenv("TSLIB_CONFFILE")) != NULL) {
        f = fopen(conffile,"r");
    } else {
        f = fopen(TS_CONF, "r");//TS_CONF是默认值/etc/ts.conf
    }
    if (!f)
        return -1;
    while ((p = fgets(buf, sizeof(buf), f)) != NULL && ret == 0) {
        struct opt *opt;
        char *e, *tok;
        line++;
        /*
         * Did we read a whole line?
         */
        e = strchr(p, '\n');
        if (!e) {
            ts_error("%d: line too long", line);
            break;
        }
        /*
         * Chomp.
         */
        *e = '\0';
        tok = strsep(&p, " \t");
        /*
         * Ignore comments or blank lines.
         */
        if (!tok || *tok == '#')
            continue;
        /*
         * Search for the option.
         */
        for (opt = options; opt             if (strcasecmp(tok, opt->str) == 0) {
                ret = opt->fn(ts, p);
                break;
            }
        if (opt == options + NR_OPTS) {
            ts_error("%d: option `%s' not recognised", line, tok);
            ret = -1;
        }
    }
    fclose(f);
    return ret;
}
ts_config首先读取配置文件,比如前面的ts.conf文件。
#module mousebuts
module variance xlimit=50 ylimit=50 pthreshold=3
module dejitter xdelta=1 ydelta=1 pthreshold=3
module linear
然后解释,比如检测到有module关键词,就会执行ts_load_modules
static struct opt options[] = {
    { "module", ts_opt_module },
};
static int ts_opt_module(struct tsdev *ts, char *rest)
{
    char *tok = strsep(&rest, " \t");
    return ts_load_module(ts, tok, rest);
}
int ts_load_module(struct tsdev *ts, const char *module, const char *params)
{
    struct tslib_module_info * (*init)(struct tsdev *, const char *);
    struct tslib_module_info *info;
    char fn[1024];
    void *handle;
    int ret;
    char *plugin_directory=NULL;
    if( (plugin_directory = getenv("TSLIB_PLUGINDIR")) != NULL ) {
        //fn = alloca(sizeof(plugin_directory) + strlen(module) + 4);
        strcpy(fn,plugin_directory);
    } else {
        //fn = alloca(sizeof(PLUGIN_DIR) + strlen(module) + 4);
        strcpy(fn, PLUGIN_DIR);//默认TSLIB_HOME/share/plugin
    }
    strcat(fn, "/");
    strcat(fn, module);
    strcat(fn, ".so");
    handle = dlopen(fn, RTLD_NOW);
    if (!handle)
        return -1;
    init = dlsym(handle, "mod_init");
    if (!init) {
        dlclose(handle);
        return -1;
    }
    info = init(ts, params);
    if (!info) {
        dlclose(handle);
        return -1;
    }
    info->handle = handle;
    ret = __ts_attach(ts, info);
    if (ret) {
        info->ops->fini(info);
        dlclose(handle);
    }
    return ret;
}
ts_load_module就是根据ts.conf的内容加在具体模块,比如上面的具体的处理规则linear规则,这个就是大名鼎鼎的触摸屏校正处理插件,这是就会加载liner模块,并挂在到ts的list链表上,同时初始化这个插件模块。
struct tslib_module_info *mod_init(struct tsdev *dev, const char *params)
{
    struct tslib_linear *lin;
    struct stat sbuf;
    int pcal_fd;
    int a[7];
    char pcalbuf[200];
    int index;
    char *tokptr;
    char *calfile=NULL;
    char *defaultcalfile = "/etc/pointercal";
    lin = malloc(sizeof(struct tslib_linear));
    if (lin == NULL)
        return NULL;
    lin->module.ops = &linear_ops;
// Use default values that leave ts numbers unchanged after transform
    lin->a[0] = 1;
    lin->a[1] = 0;
    lin->a[2] = 0;
    lin->a[3] = 0;
    lin->a[4] = 1;
    lin->a[5] = 0;
    lin->a[6] = 1;
    lin->p_offset = 0;
    lin->p_mult   = 1;
    lin->p_div    = 1;
    lin->swap_xy  = 0;
    /*
     * Check calibration file
     */
    if( (calfile = getenv("TSLIB_CALIBFILE")) == NULL) calfile = defaultcalfile;
    if(stat(calfile,&sbuf)==0) {
        pcal_fd = open(calfile,O_RDONLY);
        read(pcal_fd,pcalbuf,200);
        lin->a[0] = atoi(strtok(pcalbuf," "));
        index=1;
        while(index            tokptr = strtok(NULL," ");
            if(*tokptr!='\0') {
                lin->a[index] = atoi(tokptr);
                index++;
            }
        }
#ifdef DEBUG
        printf("Linear calibration constants: ");
        for(index=0;indexa[index]);
        printf("\n");
#endif /*DEBUG*/
        close(pcal_fd);
    }
        
        
    /*
     * Parse the parameters.
     */
    if (tslib_parse_vars(&lin->module, linear_vars, NR_VARS, params)) {
        free(lin);
        return NULL;
    }
    return &lin->module;
}
大家对这个/etc/pointercal不陌生吧,这个就是touchscreen校正时生成的文件。
到此tslib配置完成。
当我们要读取鼠标值时,就要执行ts_read,
int ts_read(struct tsdev *ts, struct ts_sample *samp, int nr)
{
    int result;
//  int i;
//  result = ts->list->ops->read(ts->list, ts_read_private_samples, nr);
    result = ts->list->ops->read(ts->list, samp, nr);
//  for(i=0;i      samp  = ts_read_private_samples;
//  }
#ifdef DEBUG
    fprintf(stderr,"TS_READ----> x = %d, y = %d, pressure = %d\n", samp->x, samp->y, samp->pressure);
#endif
    return result;
}
我们可以看出,ts_read就是调用ts的list上的read函数。
比如我们前面添加Liner处理规则就会添加liner的处理函数到list上,这时就执行linear_read函数。
static int
linear_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
{
    struct tslib_linear *lin = (struct tslib_linear *)info;
    int ret;
    int xtemp,ytemp;
    ret = info->next->ops->read(info->next, samp, nr);
    if (ret >= 0) {
        int nr;
        for (nr = 0; nr             fprintf(stderr,"BEFORE CALIB--------------------> %d %d %d\n",samp->x, samp->y, samp->pressure);
#endif /*DEBUG*/
            xtemp = samp->x; ytemp = samp->y;
            samp->x =   ( lin->a[2] +
                    lin->a[0]*xtemp + 
                    lin->a[1]*ytemp ) / lin->a[6];
            samp->y =   ( lin->a[5] +
                    lin->a[3]*xtemp +
                    lin->a[4]*ytemp ) / lin->a[6];
            samp->pressure = ((samp->pressure + lin->p_offset)
                         * lin->p_mult) / lin->p_div;
            if (lin->swap_xy) {
                int tmp = samp->x;
                samp->x = samp->y;
                samp->y = tmp;
            }
        }
    }
    return ret;
}
大家请注意 info->next->ops->read,这个就相当于调用list的下一个处理函数。其实在这里它就会调用ts_raw(这个是ts_open添加的)规则的处理函数,因为ts_raw是最先添加的,所以它是最先执行的,其实也必须这样,因为ts_raw就是读取raw数据,肯定要先执行,要不后面的规则何来数据执行啊。
  这个就是执行ts_read_raw,这个用来读取raw数据。
然后一级一级让后面的处理规则处理数据,比如liner就是使用校正程序生成的数据处理源数据然后返回给图形系统,达到校正目的了。
到此将完了。
   其实上面可能大家看到#ifdef USE_INPUT_API宏,其实这个是用来告诉tslib这个输入设备是event设备,还是其他设备,因为他们的数据结构不一样。
   还有生成的plugin默认在tslib/share/plugin下
    event是Linux设备驱动的输入设备统一数据结构,比如当一个H360格式的usb鼠标接上时,它会生成两个设备,一个是H360设备驱动生成的,一个是input设备子系统生成的,其实他们就是同一个设备。比如我们常看见的event0,event1等就是input设备子系统生成的,他们肯定对应一个鼠标或键盘设备(mice,ts,keyboard)。
下面说下编译:
       ./autogen.sh
        ./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux  --prefix=/mnt/nfs/tslib --enable-inputapi=no 
       make
       make install
   在交叉编译TSLIB的时候出现了libtool:link: only absolute run-paths are allowed错误
解决方法:要修改/tslib/plugins/Makefile里面找rpath,找到将其注释并加上绝对路径。
找到:LDFLAGS :=$(LDFLAGS) -rpath $(PLUGIN_DIR)
修改为:
LDFLAGS :=$(LDFLAGS) -rpath `cd $(PLUGIN_DIR) && pwd`

本文转载自:http://blog.csdn.net/bingking88/article/details/7097908

雨焰
粉丝 58
博文 256
码字总数 46837
作品 0
新乡
程序员
私信 提问
QT5.7+tslib1.4库的交叉编译、移植到开发板ARM9上.......

这是自己第一次写博客,因为在编译的过程中遇到了很多挫折,出现了一个小的问题,查看了很多帖子,博客都没能解决,最后经过对源码的分析,各种打印跟踪,找到了原因,所以分享给大家,希望对...

goutaiping
2017/05/24
0
0
LinuxMint17.3配置全局变量

最近在编译tslib时,打算将tslib的安装目录分配到/usr/tslib目录 首先make是成功的,但是在sudo make install的时候出现找不到arm-none-linux-gnueabi相关的工具 分析得出sudo命令切换到roo...

中华大吉
2016/03/05
72
1
tslib-1.4在arm11上的交叉编译

Tslib校准原理 在采用触摸屏的移动终端中,触摸屏性能的调试是个重要问题之一,因为电磁噪声的缘 故,触摸屏容易存在点击不准确、有抖动等问题。 Tslib是一个开源的程序,能够为触摸屏驱动获...

mjrao
2012/04/26
0
0
触摸板库tslib的编译和配置

作为基本输入设备,触摸板几乎是交互式嵌入式系统的标配。当我们知道了可以通过设备节点读取触摸板数据后,我们需要进一步优化这些直接获取的原生数据,比如去抖、消噪、校准等。 优化触摸板...

林世霖
2016/10/25
0
0
android-- A10开发板--Tslib 移植心得体会

tslib,其实从他的名字就可以看出它的,它是touchscreen的lib,其实这样还不够具体,其实它开始确实是为了touchscreen的鼠标驱动而发展起来的,且只是一个中间处理库,即将原始数据进行调整,...

雨焰
2012/09/27
0
2

没有更多内容

加载失败,请刷新页面

加载更多

php 遇到 No input file specified的解决方法

(一)IIS Noinput file specified 方法一:改PHP.ini中的doc_root行,打开ini文件注释掉此行,然后重启IIS 方法二: 请修改php.ini 找到 ; cgi.force_redirect = 1 去掉前面分号,把后面的1...

chenhongjiang
今天
5
0
MySQL 基础

一、常用命令 在命令行中,配置好环境变量后,通过cmd可以直接进入mysql命令行模式,同时列举几种常用命令 # 进入mysql数据库,密码可以先不写,打完-p后再输入,防止被别人看到mysql -u账...

华山猛男
今天
6
0
简单的博客系统(四)Django请求HTML页面视图信息--基于函数的视图

1. 编写用于查询数据的功能函数 应用目录 下的 views.py 文件通常用于保存响应各种请求的函数或类 from django.shortcuts import renderfrom .models import BlogArticles# Create your ...

ZeroBit
今天
5
0
用脚本将本地照片库批量导入到Day One中

因为目前iCloud 空间已经不足,其中95%都是照片,之前入手了DayOne,且空间没有限制,订阅费一年也不少,再加上DayOne作为一款日记App 也比较有名,功能方面最大的就是地理视图与照片视图,尤...

在山的那边
昨天
23
0
jupyter部署安装

python373 -m ipykernel install --name python373 ipython kernelspec list sc create myjupyterservice binpath="D:\apply\Python373\Scripts\jupyter-notebook --config=V:/my_work/jupyt......

mbzhong
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部