作者:黃思華 地址:華僑大學信息學院
說明:因爲最近做PDA,要實現攝像頭功能,而我的開發板mini2440,只有一個USB,而我的攝像頭是USB的,鼠標沒辦法用了,只能用觸摸筆,而觸摸座標非常不準,首先想到了qt下用的tslib,網上找了一下,還真有minigui+tslib的觸摸屏較正方案。經過幾天的實驗,我在V1.6.0上用tslib加SMDK2410實現了觸摸屏較正,也在V1.6.10上用tslib+dummy作爲ial實現了觸摸屏較正。此文先總結介紹minigui V1.6.10 + tslib 完美觸摸屏較正方案。
由於在libminigui 中沒有發佈2410.c,2410.h等,以前版本是有的,所以要用SMDK2410作爲ial有些困難,我做過實驗失敗了,不想弄了,就用dummy+tslib解決吧。說了這麼多,下面是詳細步驟:
硬件環境:
Host:X86PC
Target:友善之臂mini2440開發板
軟件環境:
Host:VMware虛擬機下的redhat linux 9.0(完全安裝)
Target:arm-linux kernel:linux-2.6.13
Crosstool: arm-linux-gcc-3.4.1
一、移植tslib1.3
(1) 第一步:下載source code並解壓
我用的是tslib-1.3.tar.bz2。
下載地址:http://download.csdn.net/source/673898
(2) 第二步:針對底層驅動修改配置信息
./autogen.sh (這步會生產configure文件)
./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux --prefix=/home/huangsihua/tslib/build --enable-inputapi=no
其中最後一項--enable-inputapi=no 是由於驅動不支持ioctl操作,如果不改最後會有如下現象:
我在板子上運行./ts_test的時候,總是提示我:ts_open: No such file or directory?
(3) 第三步:修改源碼
1、 修改/tslib/plugins/Makefile裏面找rpath
將LDFLAGS :=$(LDFLAGS) -rpath $(PLUGIN_DIR)
修改爲:
LDFLAGS :=$(LDFLAGS) -rpath `cd $(PLUGIN_DIR) && pwd`(這個可是頓號)
否則make時報如下錯:
make的時候libtool:link: only absolute run-paths are allowed
2、修改src/ts_read_raw.c中的 char *defaulttseventtype="UCB1x00";改爲char *defaulttseventtype="H3600",因爲我的觸摸屏驅動對應此結構。
3、修改tslib源碼的tests/ts_calibrate.c的getxy函數中修改一些代碼。如下
static int getxy(struct tsdev *ts, int *x, int *y)
{
..................................................................
..................................................................
修改的代碼
/* Read until we get a touch. */
do {
if (ts_read_raw(ts, &samp[0], 1) < 0) {
perror("ts_read");
close_framebuffer();
exit(1);
}
} while (samp[0].pressure > 0);
do {
if (ts_read_raw(ts, &samp[0], 1) < 0) {
perror("ts_read");
close_framebuffer();
exit(1);
}
} while (samp[0].pressure == 0);
printf("Took %d samples.../n",index);
..................................................................
..................................................................
}
我發現tslib與minigui中對於壓力參數的規定剛好相反,tslib規定samp[0].pressure> 0是按下,samp[0].pressure == 0是手鬆開而事實是相反的
如果不改就會出現在運行./ts_calibrate程序時不能有效校準,這個一定得注意!!!!!!!!!!!!!!!
4、修改在tslib/plugins/mousebuts.c 的mousebuts_read函數中一段代碼
//if(t>60)
//{
//dest->pressure=1000;
//buts->fLeftBut=0;
//}
//else
//{
dest->pressure=0;
buts->fLeftBut=2;
//}
要將紅色的部分註釋掉,否則以後運行minigui時對按鈕的操作時,如果對一個按鈕進行點擊時,並把光標停在按鈕的上面
它就會不斷的觸發按鈕的點擊事件,這當然不是我們想要得到的結果
(4)編譯與安裝
make
make install
經過安裝步驟後,進入…./tslib/build 目錄下可以看到如下幾個文件夾:
bin、etc、share、lib、include
● # ls bin/
ts_calibrate ts_print ts_test ts_print_raw
● # ls etc/
ts.conf
這裏建議配置爲(我就是用的這個配置,效果還不錯):
module mousebuts
#module variance xlimit=20 ylimit=20 pthreshold=3
#module dejitter xdelta=20 ydelta=20 pthreshold=3
module linear
若實際運行時發現抖動比較厲害,可以採用下面的配置:
module mousebuts
#module variance xlimit=20 ylimit=20 pthreshold=3
module dejitter xdelta=20 ydelta=20 pthreshold=3
module linear
● # ls lib/
libts-0.0.so.0 libts-0.0.so.0.1.0 libts.la libts.so
● # ls share/ts/
plugins/
將lib及include的內容COPY至/usr/local/arm/3.4.1/arm-linux/[lib、include]中。
同時在/opt/FriendlyARM/mini2440/root_nfs下建立一個目錄tslib
mkdir tslib
將主機…../tslib/build/下的五個文件夾COPY至該目錄下
至此tslib交叉編譯安裝完畢。
二、修改dummy.c重新配置編譯libminigui(即tslib和minigui的鏈接)
完成了對 tslib 的交叉編譯之後,
下一步的事情就是改寫 MiniGUI 的 IAL 引擎。MiniGUI自帶的 IAL 輸入引擎中,有一個叫做 dummy.c。爲了儘可能簡單,在這裏爲簡單起見就在其基礎上稍作修改,使之符合我們的要求即可。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "common.h"
#include "tslib.h"
#ifdef _DUMMY_IAL
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/kd.h>
#include "ial.h"
#include "dummy.h"
#ifndef _DEBUG
#define _DEBUG // for debugging
#endif
/* for storing data reading from /dev/touchScreen/0raw */
typedef struct {
unsigned short pressure;
unsigned short x;
unsigned short y;
unsigned short pad;
} TS_EVENT;
static unsigned char state [NR_KEYS];
static int mousex = 0;
static int mousey = 0;
static TS_EVENT ts_event;
static struct tsdev *ts;
/************************ Low Level Input Operations **********************/
/*
* Mouse operations -- Event
*/
static int mouse_update(void)
{
return 1;
}
static void mouse_getxy(int *x, int* y)
{
if (mousex < 0) mousex = 0;
if (mousey < 0) mousey = 0;
if (mousex > 239) mousex = 239;
if (mousey > 319) mousey = 319;
#ifdef _DEBUG
// printf ("mousex = %d, mousey = %d/n", mousex, mousey);
#endif
*x = mousex;
*y = mousey;
}
static int mouse_getbutton(void)
{
return ts_event.pressure;
}
#ifdef _LITE_VERSION
static int wait_event (int which, int maxfd, fd_set *in, fd_set *out, fd_set *except, struct timeval *timeout)
#else
static int wait_event (int which, fd_set *in, fd_set *out, fd_set *except,
struct timeval *timeout)
#endif
{
struct ts_sample sample;
int ret = 0;
int fd;
fd_set rfds;
int e;
if (!in) {
in = &rfds;
FD_ZERO (in);
}
fd = ts_fd(ts);
if ((which & IAL_MOUSEEVENT) && fd >= 0) {
FD_SET (fd, in);
#ifdef _LITE_VERSION
if (fd > maxfd) maxfd = fd;
#endif
}
#ifdef _LITE_VERSION
e = select (maxfd + 1, in, out, except, timeout) ;
#else
e = select (FD_SETSIZE, in, out, except, timeout) ;
#endif
if (e > 0) {
// input events is coming
if (fd > 0 && FD_ISSET (fd, in)) {
FD_CLR (fd, in);
ts_event.x=0;
ts_event.y=0;
ret = ts_read(ts, &sample, 1);
if (ret < 0) {
perror("ts_read()");
exit(-1);
}
ts_event.x = sample.x;
ts_event.y = sample.y;
ts_event.pressure = (sample.pressure > 0 ? 4:0);
// if (ts_event.pressure > 0 &&
if((ts_event.x >= 0 && ts_event.x <= 239) &&
(ts_event.y >= 0 && ts_event.y <= 319)) {
mousex = ts_event.x;
mousey = ts_event.y;
// printf("ts_event.x is %d, ts_event.y is %d------------------------------------->/n",ts_event.x ,ts_event.y);
}
//#ifdef _DEBUG
// if (ts_event.pressure > 0) {
// printf ("mouse down: ts_event.x = %d, ts_event.y = %d,ts_event.pressure = %d/n",ts_event.x,ts_event.y,ts_event.pressure);
// }
//#endif
ret |= IAL_MOUSEEVENT;
return (ret);
}
}
else if (e < 0) {
return -1;
}
return (ret);
}
BOOL InitDummyInput(INPUT* input, const char* mdev, const char* mtype)
{
char *ts_device = NULL;
if ((ts_device = getenv("TSLIB_TSDEVICE")) != NULL) {
// open touch screen event device in blocking mode
ts = ts_open(ts_device, 0);
} else {
#ifdef USE_INPUT_API
ts = ts_open("/dev/input/0raw", 0);
#else
ts = ts_open("/dev/touchscreen/ucb1x00", 0);
#endif
}
#ifdef _DEBUG
printf ("TSLIB_TSDEVICE is open!!!!!!!!!!!/n");
#endif
if (!ts) {
perror("ts_open()");
exit(-1);
}
if (ts_config(ts)) {
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->wait_event = wait_event;
mousex = 0;
mousey = 0;
ts_event.x = ts_event.y = ts_event.pressure = 0;
return TRUE;
}
void TermDummyInput(void)
{
if (ts)
ts_close(ts);
}
#endif /* _DUMMY_IAL */
修改好minigui的引擎文件後就可以對minigui進行重新編譯了,因爲用到了 tslib 庫,所以必須在編譯的時候告訴 MiniGUI 到哪裏去找到 tslib 相關的頭文件和共享庫文件。具體做法如下所示:
[[email protected]]# ./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux --disable-galqvfb --disable-galecoslcd --disable-vbfsupport --prefix=/usr/local/arm/3.4.1/arm-linux CFLAGS="-I/usr/local/arm/3.4.1/arm-linux/include -L/usr/local/arm/3.4.1/arm-linux/lib -lts"
[root@ libminigui-1.6.10]# make
[root@ libminigui-1.6.10]# make install
這裏說一下爲什麼要指定 CFLAGS 標誌。其實,通過指定這個標誌,告訴編譯器應該到哪裏去找 tslib 有關的頭文件和共享文件, -lts則告訴鏈接器最後生成的 MiniGUI 的共享庫文件最後要和 ts 庫(ts 是 touchscreen 的縮寫)鏈接。
將生成的minigui的庫從/usr/local/arm/3.4.1/arm-linux/lib COPY到/opt/FriendlyARM/mini2440/root_nfs/lib下。
[Root]# cp /usr/local/arm/3.4.1/arm-linux/etc/MiniGUI.cfg /home/fp/nfs/usr/local/etc/ 記住,保持目錄結構的一致
修改 MiniGUI.cfg ,如下
[system]
# IAL engine
ial_engine=dummy // 這裏修改,我用的是觸摸屏,所以就用dummy肯定不會錯
mdev=/dev/input/ts0 //解摸屏
mtype=none
[fbcon]
defaultmode=240x320-16bpp // 根據你的LCD大小自己設置,設置錯誤minigui 就啓動不了。
這樣我們就把tslib和minigui通過dummy鏈接好了。
三、測試
重編譯我我修改製作的PDA程序並將它和res文件COPY到/opt/FreindlyARM/mini2440/root_nfs/usr/local/下,打開超級終端,打開開發板,按回車進入VIVI,輸入NFS啓動命令:
param set linux_cmd_line "console=ttySAC0 root=/dev/nfs nfsroot=192.168.1.111:/opt/FriendlyARM/root_nfs ip=192.168.1.70:192.168.1.111:192.168.1.111:255.255.255.0:sbc2440.arm9.net:eth0:off"
同時在終端輸入擴展命令:
export QWS_MOUSE_PROTO=TPanel:/dev/input/event0
export V_ROOT=/tslib
#export TSLIB_TSEVENTTYPE=H3600
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event0
export TSLIB_CALIBFILE=$V_ROOT/etc/pointercal
export TSLIB_CONFFILE=$V_ROOT/etc/ts.conf
export TSLIB_PLUGINDIR=$V_ROOT/share/ts/plugins
export LD_LIBRARY_PATH=$V_ROOT/lib:$LD_LIBRARY_PATH
當然你也可以把這一串加到profile文件,讓開發板在啓動時運行這些命令。
最後進入程序所在目錄運行
./PDA就可以了,效果非常不錯,堪稱完美。
有點長哦, minigui V1.6.10 + tslib 觸摸屏較正完美解決方案,歡迎大家提出意見和更好的方案。
EMAIL:[email protected]
本人CSDN博客http://blog.csdn.net/huangsihua
參考文章:myleeming CSDN博客minigui+tslib編譯全過程