這段時間一直在忙工作的事情,Input子系統的第二篇博客姍姍來遲了。
將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協議,測試結果也是不准確的。
下面要說的與TP的多點觸摸(MT Multi-touch)的功能關系密切,沒有興趣的可以略過。由於這部分代碼不從事TP或者android的人是不會接觸到的,所以代碼就不貼出來了,有興趣的童鞋可以單獨交流O(∩_∩)O~
我們都知道,在支持MT的手機上多指滑動的時候,多條手指滑動過的軌跡彼此是不相交的,這也是我們所期望的。但這個功能究竟是如何實現的呢?看了上面的分析應該就知道,A/B兩種協議方式都可以實現該功能。
A協議不會使用slot,多指處理中,它的報點序列如下(每一個序列都以input_report_***函數實現):
點擊(此處)折疊或打開
- 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_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,應用收到這個信息后,就可以知道當前點屬於哪條線了。
手抬起來的時候又用什么樣的序列來通知系統呢,
點擊(此處)折疊或打開
- SYN_MT_REPORT
- SYN_REPORT
只有SYNC,沒有其它任何信息,系統就會認為此次事件為UP。
B協議使用了slot,還有一個新面孔TRACKING_ID.
點擊(此處)折疊或打開
- ABS_MT_SLOT 0
- ABS_MT_TRACKING_ID **
- ABS_MT_POSITION_X x[0]
- ABS_MT_POSITION_Y y[0]
- ABS_MT_SLOT 1
- ABS_MT_TRACKING_ID **
- ABS_MT_POSITION_X x[1]
- ABS_MT_POSITION_Y y[1]
- SYN_REPORT
沒有SYN_MT_REPORT,那么它用什么來跟蹤當前點屬於哪一條線呢,用的就是ABS_MT_TRACKING_ID,當前序列中某點的ID值,如果與前一次序列中某點的ID值相等,那么他們就屬於同一條線。既然如此,那么android系統中還需要做排序等運算嗎?當然不需要。那么手指全部抬起的時候序列又是怎樣的呢?
點擊(此處)折疊或打開
- ABS_MT_SLOT 0
- ABS_MT_TRACKING_ID -1
- SYN_REPORT
- ABS_MT_SLOT 1
- ABS_MT_TRACKING_ID -1
- SYN_REPORT
這里上報的ABS_MT_TRACKING_ID為-1,也只有這里該值才可以小於零,收到該值,系統就會清除對應的ID。看似簡單的兩個協議內容到這里就分析完畢了。
看了上面的分析,明顯可以看出B協議要由於A協議,但事實上並不如此簡單。B協議需要硬件上的支持,ID值並不是隨便賦值的,而是硬件上跟蹤了點的軌跡;如果硬件上滿足不了這個條件,那么采用B協議只能鬧成笑話。另外,B協議的復雜性如果掌握不好往往會帶來一些莫名其妙的問題,比如如果因為某些因素(同步等),在UP的時候少清除了一個slot的信息,那么下次單擊的時候你也會驚奇地發現竟然有兩個點(采用了B協議,slot已經保存了點信息,除非明確清除)。
希望本文對希望了解TP或者多點觸摸功能的童鞋有所幫助。
