android 电容屏多点触控协议

多点触控协议
为了发挥新近的多点触摸和多用户设备的强大功能,为多点触摸定义一种上报详细数据的方法(比如有多个物体直接接触到设备的表面),是非常有必要的。多点触摸协议(multi-touch,MT),是的内核驱动可以对多个随意数量的触控事件上报详细的数据信息。

在Linxu内核中,手指信息被内核抽象为一个个ABS数据包,由驱动顺序的发送给应用。
多点触摸的ABS数据包通常由ABS_MT标志。驱动调用input_mt_sync发送SYN_MT_REPORT来表示一个ABS数据包结束。应用收到SYN_MT_REPORT事件后,会处理当前数据包并准备接收下一个数据包。如果本次多点触摸所有手指的数据包都发送完毕,需要调用input_sync发送SYN_REPORT,以通知上层本次多点触摸结束了。input_sync之后就进入了下一次多点触摸周期。
通常的多点触摸周期可以描述为:
ABS_MT_*|SYN_MT_REPORT|ABS_MT_*|SYN_MT_REPORT|SYN_REPORT
有些ABS_MT事件是必须实现的,如ABS_MT_POSITION_X和ABS_MT_POSITION_Y。而某些事件,如ABS_MT_TOUCH_MAJOR和ABS_MT_WIDTH_MAJOR是否需要实现则取决于具体的硬件。
ABS_MT_TOUCH_MAJOR表示了手指接触TP的直径的近似。ABS_MT_WIDTH_MAJOR是手指的直径的近似。当手指和触摸屏接触的越紧密,则压力越大,手指和屏幕接触的面积(直径)也会越大。而手指的直径通常是一个常量。这样ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR就可以用来表示压力了。而且这个值在[0,1)间。对于某些提供了压力值的TP,可以使用ABS_MT_PRESSURE来替代ABS_MT_TOUCH_MAJOR。
Event 原语

“接触”一词用来描述一个物体直接碰到另一个物体的表面。
ABS_MT_TOUCH_MAJOR描述了主接触面的长轴,它和X,Y同一个单位,如果一个面的分辨率为X*Y,则ABS_MT_TOUCH_MAJOR的最大值为sqrt(X^2+Y^2)
ABS_MT_TOUCH_MINOR描述了接触面的短轴,如果接触面是圆形,它可以不用。
ABS_MT_WIDTH_MAJOR描述了接触工具的长轴
ABS_MT_WIDTH_MINOR描述了接触工具的短轴
ABS_MT_TOUCH_MAJOR := max(X, Y)
ABS_MT_TOUCH_MINOR := min(X, Y)
ABS_MT_ORIENTATION := bool(X > Y)

以上四个参数可以用来生成额外的触摸信息,如ABS_MT_TOUCH_MAJOR/ABS_MT_WIDTH_MAJOR的比率可以用来描述压力。
ABS_MT_ORIENTATION
ABS_MT_POSITION_X接触面的中心点X坐标
ABS_MT_POSITION_Y接触面的中心点Y坐标
ABS_MT_TOOL_TYPE描述接触工具类型,很多内核驱动无法区分此参数如手指及笔,如果是这样,该参数可以不用,协议目前支持MT_TOOL_FINGER和MT_TOOL_PEN两种类型。
ABS_MT_BLOB_ID形状集ID,集合几个点以描述一个形状,很多驱动没有形状属性,此参数可以不用。
ABS_MT_TRACKING_ID描述了从接触开始到释放的整个过程的集合,如果设备不支持,此参数可是不用。


  触摸轨迹

  仅有少数设备可以明触的标识真实的trackingID,多数情况下 trackingID只能来标识一次触摸动作的过程。

  手势
  多点触摸指定的应用是创建手势动作, TOUCH和 WIDTH参数经常用来区别手指的压力和手指间的距离,另外 MINOR类的参数可以用来区别设备的接触面的大小(点接触还是面接触),ORIENTATION可以产生旋转事件。

基于硬件的能力,该协议被分为两种类型。对于只能处理匿名接触(type A)的设备,该协议描述了如何把所有的原始触摸数据发送给接收者。对于那些有能力跟踪并识别每个触摸点的设备(type B),该协议描述了如何把每个触摸点的单独更新通过事件slots发送给接受者。

详细的触控信息被按顺序地分割为多个ABS_MT事件数据包进行发送。只有ABS_MT事件信息被识别为触控数据包的一部分,因为这些事件在当前的单点触控(single-touch,ST)应用中是被忽略掉的,我们可以在现有的驱动中基于ST协议之上来实现MT协议。
对于type A设备的驱动,在每个数据包的结尾用input_mt_sync()对多个触控包进行分割,这将会产生一个SYN_MT_REPORT事件,它通知接收者接受当前的触控信息并准备接收下一个信息。
对于type B设备的驱动,在每个数据包的开始,通过调用input_mt_slot()进行分割,同时带入一个参数:slot。这会产生一个ABS_MT_SLOT事件,它通知接收者准备更新给定slot的信息。.
两种类型的驱动通常都通过调用input_sync()函数来标记一个多点触摸数据传送的结束,这通知接收者对从上一个EV_SYN/SYN_REPORT以来的所有累加事件作出响应,并准备接收新的一组事件/数据包。

无状态的type A协议和有状态的type B slot协议之间的主要区别是通过识别相同接触点来减低发送到用户空间的数据量。slot协议需要使用到ABS_MT_TRACKING_ID,它要不由硬件来提供,或者通过原始数据进行计算
对于type A设备,内核驱动应该根据设备表面上全部有效触控进行列举并生成事件。每个触控点数据包在这次事件流中的顺序并不重要。事件过滤和手指跟踪的工作留给用户空间来实现
对于type B设备,内核驱动应该把每一个识别出的触控和一个slot相关联,并使用该slot来传播触摸状态的改变。通过修改关联slot的ABS_MT_TRACKING_ID来达到对触摸点的创建,替换和销毁。一个非负数的跟踪id被解释为有效的触摸,-1则代表一个不再使用的slot。一个之前没有出现过的跟踪id被认为是一个新的接触点,当一个跟踪id不再出现时则认为该接触点已经被移除。因为只有变化的部分被传播,每个被启动的接触点的状态信息必须驻留在接收端。每当接收到一个MT事件,只需对当前slot的相关属性进行一次简单的更新即可

Protocol Example A
    对于一个两点触控的触摸信息,type A设备的最小的事件序列看起来就像下面这样:
    ABS_MT_POSITION_X x[0]
    ABS_MT_POSITION_Y y[0]
    SYN_MT_REPORT
    ABS_MT_POSITION_X x[1]
    ABS_MT_POSITION_Y y[1]
    SYN_MT_REPORT
    SYN_REPORT
     实际上,在移动其中一个触控点后的上报序列看起来是一样的、所有存在触控点的原始数据被发送,然后在它们之间用SYN_REPORT进行同步。
     当第一个接触点离开后,事件序列如下:
     ABS_MT_POSITION_X x[1]
     ABS_MT_POSITION_Y y[1]
     SYN_MT_REPORT
     SYN_REPORT
    当第二个接触点离开后,事件序列如下:
    SYN_MT_REPORT
    SYN_REPORT
    假如驱动在ABS_MT事件之外上报一个BTN_TOUCH 或ABS_PRESSURE事件,最后一个SYN_MT_REPORT可以省略掉,否则,最后的SYN_REPORT会被input核心层扔掉,结果就是一个0触控点事件被传到用户空间中。 
Protocol Example B
    对于一个两点触控的触摸信息,type B设备的最小的事件序列看起来就像下面这样:
     ABS_MT_SLOT 0
     ABS_MT_TRACKING_ID 45
     ABS_MT_POSITION_X x[0]
    ABS_MT_POSITION_Y y[0]
    ABS_MT_SLOT 1
    ABS_MT_TRACKING_ID 46
    ABS_MT_POSITION_X x[1]
    ABS_MT_POSITION_Y y[1]
    SYN_REPORT
    id 45的触控点在x方向移动后的事件序列如下:
    ABS_MT_SLOT 0
    ABS_MT_POSITION_X x[0]
    SYN_REPORT
    slot 0对应的接触点离开后,对应的事件序列如下:
    ABS_MT_TRACKING_ID -1
    SYN_REPORT
    上一个被修改的slot也是0,所以ABS_MT_SLOT被省略掉。这一消息移除了接触点45相关联的slot 0,于是接触点45被销毁,slot 0被释放后可以被另一个接触点重用。
     最后,第二个接触点离开后的时间序列如下:
     ABS_MT_SLOT 1
     ABS_MT_TRACKING_ID -1
     SYN_REPORT

 Android驱动之 Linux Input子系统之TP——A/B(Slot)协议
将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围大多数用到input子系统的开发人员也不甚理解;另一方面是由于这部分知识一旦扩展到TP(触摸屏Touch Panel)的多点触摸就要与Middleware/Framework一起结合起来看才能完全掌握,复杂性所在。这里的Middleware/Framework是针对android来说的,本人从事android这几个层次的工作,所以就从android的角度来讲讲这部分内容,其他系统虽然代码不同,但原理上是完全一样的。
      B协议又称为slot协议,那么input子系统里面使用的slot是什么,A/B协议究竟是如何划分的?
      slot直译为位置、槽,有两层含义,一层是位置,另一层是容器。在Input子系统中,它扮演的就是这两个角色。它产生于这样一个背景:
      如果从Device获取的当前数据与上一个数据相同,我们有必要再上报当前数据吗?如果我们不管两次数据是否一致都上报,那就是A协议;如果我们选择不上报,那么既然需要比较,总需要把上一次数据存起来吧,slot就是做这个事情的,显然这就是Slot(B)协议。
      其实到这里,对TP不感兴趣的童鞋可以不继续向下看了,了解了两个协议的区别看或者写一般模块的代码不会有问题了。需要注意的是,想要测试Device驱动的input部分是否正常的时候,假如使用的是B协议,input_report数据的时候要记得每次都要report不同的值,否则在HAL层是看不到数据不停上报的,因为前后两个数据相同的时候,B协议是不会上报到系统的。另外,在上层测试数据上报频率的时候,采用  数据总量/时间差  的方法,如果驱动采用的是B协议,测试结果也是不准确的。
       我们都知道,在支持MT的手机上多指滑动的时候,多条手指滑动过的轨迹彼此是不相交的,这也是我们所期望的。但这个功能究竟是如何实现的呢?看了上面的分析应该就知道,A/B两种协议方式都可以实现该功能。
      A协议不会使用slot,多指处理中,它的报点序列如下(每一个序列都以input_report_***函数实现):

1.ABS_MT_POSITION_X x[0]
2.ABS_MT_POSITION_Y y[0]
3.SYN_MT_REPORT
4.ABS_MT_POSITION_X x[1]
5.ABS_MT_POSITION_Y y[1]
6.SYN_MT_REPORT
7.…
8.SYN_REPORT
       上面的序列中需要说明的是系统以SYN_MT_REPORT为一个点的信息的结尾,以SYN_REPORT为一次事件的结尾。也就是说多指触摸的时候,android的中间件部分每收到一次SYN_MT_REPORT就形成一个点信息,收到一个点之后并不会立即处理,而是一个事件完成之后才会处理,SYN_REPORT就是这个事件的标志。A协议比较简单,我们也可以发现在上面的序列中根本就没有轨迹跟踪的信息,有的只是点坐标等信息,那么系统如果去判断当前的多个点各属于哪一条线呢?
       我们假设前一次事件共有5个点,本次触摸也有5个点,系统会分别计算前一次5个点与本次5个点的距离,distance[prev_i, curr_j] (i=0,1,...,4; j=0,1,...4),这样会产生总共5*5=25个数字。然后对这25个数字进行排序,android用的是堆排序。(我们在系统上如果用多指,一般最多也是双值,也就是4个数据,这里采用了堆排序,不知是出于什么情况考虑,感觉换个方法可能更实用些。)下面的任务就是判断哪些当前点与前一次的点最近,那么赋予它们相同的id,应用收到这个信息后,就可以知道当前点属于哪条线了。
       手抬起来的时候又用什么样的序列来通知系统呢,
1.SYN_MT_REPORT
2.SYN_REPORT
       只有SYNC,没有其它任何信息,系统就会认为此次事件为UP。
 B协议使用了slot,还有一个新面孔TRACKING_ID.
1.ABS_MT_SLOT 0
2.ABS_MT_TRACKING_ID **
3.ABS_MT_POSITION_X x[0]
4.ABS_MT_POSITION_Y y[0]
5.ABS_MT_SLOT 1
6.ABS_MT_TRACKING_ID **
7.ABS_MT_POSITION_X x[1]
8.ABS_MT_POSITION_Y y[1]
9.SYN_REPORT
      没有SYN_MT_REPORT,那么它用什么来跟踪当前点属于哪一条线呢,用的就是ABS_MT_TRACKING_ID,当前序列中某点的ID值,如果与前一次序列中某点的ID值相等,那么他们就属于同一条线。既然如此,那么android系统中还需要做排序等运算吗?当然不需要。那么手指全部抬起的时候序列又是怎样的呢?     

1.ABS_MT_SLOT 0
2.ABS_MT_TRACKING_ID -1
3.SYN_REPORT
4.ABS_MT_SLOT 1
5.ABS_MT_TRACKING_ID -1
6.SYN_REPORT
  这里上报的ABS_MT_TRACKING_ID为-1,也只有这里该值才可以小于零,收到该值,系统就会清除对应的ID。看似简单的两个协议内容到这里就分析完毕了。
      看了上面的分析,明显可以看出B协议要由于A协议,但事实上并不如此简单。B协议需要硬件上的支持,ID值并不是随便赋值的,而是硬件上跟踪了点的轨迹;如果硬件上满足不了这个条件,那么采用B协议只能闹成笑话。另外,B协议的复杂性如果掌握不好往往会带来一些莫名其妙的问题,比如如果因为某些因素(同步等),在UP的时候少清除了一个slot的信息,那么下次单击的时候你也会惊奇地发现竟然有两个点(采用了B协议,slot已经保存了点信息,除非明确清除)。

你可能感兴趣的:(linux_driver)