linux的触摸屏之一(原理及APK调试)

从来好事天生俭,自古瓜儿苦后甜。这篇文章主要讲述linux的触摸屏之一:原理及APK调试相关的知识,希望能为你提供帮助。
(1)原理:本文抛开技术层次上来说说LINUX触摸屏设备驱动原理。触摸屏,就是用一块AD转换模块来将屏幕上的触摸信号转成数字信号。触摸屏常用的是四线电阻,当触摸时候,功能模块会将模拟信号转换成数字信号,就是通常说的AD转换。在LINUX中,通常是通过中断来读取这些数字的。触摸屏幕的时候,中断发生,LINUX通过串口或者I2C,SPI或者内部数据通道等去读取转换后的数字,然后把数值传给INPUT层。TP在进入休眠时,要关闭CTP的中断,防止误触发中断,导致异常。

为什么要校验?原因A,触摸屏与LCD显示屏是两个不同的物理器件。LCD处理的像素,例如我们通常所说的分辨率是600x800,实际就是指每行的宽度是600个像素,高度是800个像素,而触摸屏处理的数据是点的物理坐标,该坐标是通过触摸屏控制器采集到的。两者之间需要一定的转换。B,其次在安装触摸屏时,不可避免的存在着一定的误差,如旋转,平移的,这同样需要校正解决。C,再次,电阻式触摸屏的材料本身有差异而且随着时间的推移,其参数也会有所变化,因此需要经常性的校正(电容式触摸屏只需要一次校正即可)。

linux的触摸屏之一(原理及APK调试)

文章图片

比较常用的校验程序是TSLIB。通过TSLIB校验后,应用程序读取TSLIB里的数值,这个时候就能准确定位了。校正原理: 触摸屏的校正过程一般为:依次在屏幕的几个不同位置显示某种标记(如"+"),用触摸笔点击这些标记, 完成校正。如果PT(x, y)表示触摸屏上的一个点,PL(x, y)表示LCD上的一个点,校正的结果就是得到一个转换矩阵M,使PL(x, y) = M·PT(x, y)。最终,假设LCD三个点的坐标为(XL1, YL1),(XL2, YL2),(XL2, YL2), 对应触摸屏上的三个点是(XT1, YT1),(XT2, YT2),(XT3, YT3),则联立两个方程组为:
linux的触摸屏之一(原理及APK调试)

文章图片

这样,触摸屏的校正实际上就是解上面的方程组,得到6个系数:A、B、C、D、E、F。而上面方程组按照克莱姆法则解即可。在得到6个系数后,以后通过触摸屏得到的所有坐标,带入公式(1)中就可以得到LCD上以像素表示的坐标。
实际上,在校正时,采集的触摸屏的点坐标有一定的误差,也就是说采集几个三组点坐标,分别计算A、B、C、D、E、F,其结果不尽相同。在tslib的ts_calibrate中,采集了五组点坐标,具体代码参见ts_calibrate.c中的perform_calibration()。一般来说,采集的点越多,校正的精确性就越高。只是采集点过多就会冗余,对校正精确性的提高作用很少,反而增加了计算时间。
归结过程如下:
android 的坐标转换处理:This implementation is a linear transformation using 7 parameters
(a, b, c, d, e, f and s) to transform the device coordinates (Xd, Yd) into screen coordinates (Xs, Ys) using the following equations:
s*Xs = a*Xd + b*Yd + c
s*Ys = d*Xd + e*Yd + f
其中:Xs,Ys:LCD坐标;Xd,Yd:触摸屏坐标。
(2)调试:触摸屏一直定位不准,会有偏移。同事经过一段时间的调试之后,解决了此问题。解决方式如下:
1,原理:Calibrate: 下载tslibonandroid,通过它来在屏幕上显示五个坐标,点击这五个坐标,得到需要的7个参数,实现坐标转换。
过程:icon(apk)-> jni-> *.so(tslib)-> 生成校正参数(a0~a6)。校正时候,必须通知driver,校正完成或者校正失败都要通知driver。而touchdriver每次上电后需要读取一次校正参数,如果读取失败则使用默认参数。
2,改动:
- 在$kernel/driver/input/touchscreen/s3c-ts.c,添加跟上层cupcake接口的函数。
- 改动$kernel/dirver/char/vt_ioctl.c
- 在$cupcake/development/中添加calibrate整个文件夹(实现java icon和JNI调用),该文件夹负责生成一个android应用软件apk
- 在$cupcake/external/中添加tslibonandroid整个文件夹(实现生成校正参数)
- 在$cupcake/vendor/sec/smdk6410/init.rc,改动跟touch screen相关文件的属性权限。
把kernel和cupcake完整编译后,烧录进板子。cupcake会在out/target/product/smdk6410/obj/APPS/Calibrate_intermediates下生成一个对应的apk文件,将该apk文件改名后安装入平台,点击即可运行与WINCE相似的校准过程。
3,程序过程:
A,点击APK,开始运行程序。在Calibrate.java中:onCreate-》tsmainloop。同时:
public native void tsmainloop(); //JNI函数申明
System.loadLibrary("calibrate-jni"); //载入库libcalibrate-jni.o
B,JNI的C函数原型定义在com_android_calibrate_Calibrate.cpp中:
#include "../../../external/tslibonandroid/tests/calibratejni.h" //该文件所在的文件夹作为当前目录回退3层再进入其他子目录
static void tsmainloop(JNIEnv *env, jobject object)
{
ts_main();
}
在该文件中,还定义了方法跟class:
static const char *classPathName = "com/android/calibrate/Calibrate"; //指向该CPP被调用的class
static JNINativeMethod methods[] = {
{"tsmainloop", "()V", (void*)tsmainloop },
};
完成JNI的注册。
C,在external/tslibonandroid/tests路径下的ts_calibrate.c完成TSLIB过程,如下:
#define TSLIB_TSDEVICE"/dev/input/event1"//内核为TS分配的INPUT设备名
#define DEVICE_NAME"/dev/myts"//要访问的TS字符设备名
#define TSLIB_CALIBFILE"/system/etc/pointercal"
#define TS_POINTERCAL"/system/etc/pointercal"//最终需要用到的pointercal文件,写入7个参数
#define TSLIB_CONFFILE"/system/etc/tslib/ts.conf"//tslib中的配置文件
typedefstruct {
int x[5], xfb[5]; //x方向的触摸屏参数,LCD参数
int y[5], yfb[5]; //y方向的触摸屏参数,LCD参数
int a[7]; //存储那七个参数
} calibration;
ts_main()
{
calibration cal;
char cal_buffer[256];
char buffer[5] = "OK";
int fd = open("/dev/myts",O_RDWR); //打开内核定义的TS字符设备,写入OK字符
write(fd,buffer,2);
close(fd);

struct tsdev *ts = ts_open(getenv("TSLIB_TSDEVICE"),0)//打开内核TS设备
ts_config(ts); //读取ts.conf,给ts配置
open_framebuffer(); //打开显示设备,准备画图
put_string_center (xres / 2, yres / 4, "TSLIB calibration utility", 1); //在屏幕中心放置字符串
put_string_center (xres / 2, yres / 4 + 20, "Touch crosshair to calibrate", 2); //表示程序运行开始
clearbuf(ts); //清空TS

get_sample (ts, & cal, 0, 50,50,"Top left");
get_sample (ts, & cal, 1, xres - 50, 50,"Top right");
get_sample (ts, & cal, 2, xres - 50, yres - 50, "Bot right");
get_sample (ts, & cal, 3, 50,yres - 50, "Bot left"); //按照左上,右上,右下,左下,中五个次序,读取采样值,按
get_sample (ts, & cal, 4, xres / 2,yres / 2,"Center"); //0,1,2,3,4这个index编号存储在cal变量中

if (perform_calibration (& cal))//如果校验成功
{
cal_fd = open (getenv("TSLIB_CALIBFILE"), O_CREAT | O_RDWR,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
//打开系统的pointercal文件
sprintf (cal_buffer,"%d %d %d %d %d %d %d",cal.a[1], cal.a[2], cal.a[0],cal.a[4], cal.a[5], cal.a[3], cal.a[6]);
//把cal的7个参数值组合到cal_buffer变量中
write (cal_fd, cal_buffer, strlen (cal_buffer) + 1); //写入7个参数到pointercal文件中
}
strcpy(buffer,"END");
fd = open("/dev/myts",O_RDWR);
printf("fd: %d/n",fd);
write(fd,buffer,3);
close(fd); //写END到内字符设备myts中
}
====================================================================================================
在调试melfas的TP驱动时,发现I2C速度是个比较关键的因素。太快和太慢都有问题,80K恰好,否则会出现点一次多次响应和上报数据超出范围等奇怪现象。
====================================================================================================
如果横屏的安卓系统转了90度,变成竖屏了,这是软件可以调整的。但是TP的原点(0,0)是不会变的(这是固件决定好的),尽管对于横屏和竖屏,TP的起始点肯定有差别,但是可以通过上报数据的修改来解决这个问题。方法为:
上报函数中的
input_report_abs(tpd-> dev, ABS_MT_POSITION_X, x);
input_report_abs(tpd-> dev, ABS_MT_POSITION_Y, y); //800X480的固件
改成:
input_report_abs(tpd-> dev, ABS_MT_POSITION_X, 480-y);
input_report_abs(tpd-> dev, ABS_MT_POSITION_Y, x);
实现TP的XY反的对调。
对应的,TP虚拟按键的区域也要反,也就是每个按钮XY中点的值。而且还可能值也要适当调整。
【linux的触摸屏之一(原理及APK调试)】

    推荐阅读