zoukankan      html  css  js  c++  java
  • CTP多点触摸协议【转】

    转自:http://blog.chinaunix.net/uid-26403844-id-5063920.html

    linux kernel 2.6.30开始对多点触摸支持,最近高通要求所有CTP器件要用B 协议上报数据,协议A/B(slot)分析如下: 

    一、文档 
    多点触摸协议文档  kernel/Documentation/input/multi-touch-protocol.txt 


    二、协议分析 

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


    两种协议的使用: 

    Protocol Example A: 
    -------------------- 
    type A设备的最小的事件序列看起来就像下面这样 
    (可以通过adb shell getevent -lt /dev/input/event0 查看 eventX对应触摸屏): 

    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 
    只有SYNC,没有其它任何信息,系统就会认为此次事件为UP。 

      系统以SYN_MT_REPORT为一个点信息的结尾,收到一个点之后并不会立即处理, 而是一个事件完成之后才会处理, 
    SYN_REPORT就是这个事件的标志。A协议比较简单,我们也可以发现在上面的序列 中根本就没有轨迹跟踪的信息, 
    有的只是点坐标等信息,报上去的信息简单粗暴不需要什么顺序,系统根本无法识 别报上的点是属于哪一条线的, 
    事件过滤和手指跟踪的工作留给用户空间来实现。 

    Protocol Example B: 
    ------------------- 
    type B设备的最小的事件序列看起来就像下面这样: 
    ABS_MT_SLOT 0 
    ABS_MT_TRACKING_ID 46 
    ABS_MT_POSITION_X x[0] 
    ABS_MT_POSITION_Y y[0] 
    ABS_MT_SLOT 1 
    ABS_MT_TRACKING_ID 47 
    ABS_MT_POSITION_X x[1] 
    ABS_MT_POSITION_Y y[1] 
    SYN_REPORT 

    手抬起的时候如下样子: 
    ABS_MT_SLOT 0 
    ABS_MT_TRACKING_ID -1 
    SYN_REPORT 
    ABS_MT_SLOT 1 
    ABS_MT_TRACKING_ID -1 
    SYN_REPORT 

      对于协议B,内核驱动应该把每一个识别出的触控和一个slot相关联,并使用该 slot来传播触摸状态的改变,通过修改关联 
    slot的ABS_MT_TRACKING_ID来达到对触摸点的创建,替换和销毁。上报 ABS_MT_TRACKING_ID -1 系统会清除对应的ID和slot, 
    再次按下手指时分配新ID值(ID值是每次+1的) 

    和协议A相比没有SYN_MT_REPORT,那么它用什么来跟踪当前点属于哪一条线呢,用 的就是ABS_MT_TRACKING_ID,当前序列中 
    某点的ID值,如果与前一次序列中某点的ID值相等,那么他们就属于同一条线,应 用层就不用在去劳心劳神的算那个点是那条线上 
    的啦。如果按下并一直按同一个点,那么input子系统会做个处理来屏蔽上下两次 相同的点,减少IO的负担。 

      协议B明显优越于协议A,但注意协议B是需要硬件支持的,ID值并不是随便赋值 的,而是硬件上跟踪了点的轨迹,比如按下一个点 
    硬件会跟踪这个点的ID,只要不抬起上报的点都会和这个ID相关。 


    三、代码编写 

    Protocol A: 
    ------------------------------------------------------------------------------------- 
    注册: 
        set_bit(EV_SYN, input_dev->evbit); 
        set_bit(EV_KEY, input_dev->evbit); 
        set_bit(EV_ABS, input_dev->evbit); 
        set_bit(INPUT_PROP_DIRECT, input_dev->propbit); 
        input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, sensor_max_x, 0, 0); 
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, sensor_max_y, 0, 0); 
        input_register_device(input_dev); 

    上报: 
        for (finger = 0; finger < num_of_fingers; finger++) { 
            ...//读取计算x、y坐标,id值,触摸的状态 
            if (finger_down) { 
                input_report_abs(input_dev, ABS_MT_POSITION_X, x); 
                input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 
                input_mt_sync(input_dev); 
            } else { 
                input_mt_sync(input_dev); 
        } 

        input_sync(input_dev); 


        如果注册了ABS_MT_PRESSURE,上报时就要上报ABS_MT_PRESSURE。 
        如果注册了BTN_TOUCH, 上报时就要上报BTN_TOUCH, 1:按下  0:抬起 

    上报log: 

    按下一个点抬起 
    [     140.781791] EV_ABS       ABS_MT_POSITION_X 00000148 
    [     140.781801] EV_ABS       ABS_MT_POSITION_Y 0000044f 
    [     140.781805] EV_SYN       SYN_MT_REPORT 00000000 
    [     140.781807] EV_SYN       SYN_REPORT 00000000 
    [     140.796553] EV_SYN       SYN_MT_REPORT 00000000 
    [     140.796563] EV_SYN       SYN_REPORT           00000000 

    按下两个点抬起 
    [     245.011718] EV_ABS       ABS_MT_POSITION_X 00000102 
    [     245.011757] EV_ABS       ABS_MT_POSITION_Y 000003d0 
    [     245.011771] EV_SYN       SYN_MT_REPORT 00000000 
    [     245.011785] EV_ABS       ABS_MT_POSITION_X 00000220 
    [     245.011798] EV_ABS       ABS_MT_POSITION_Y 00000419 
    [     245.011810] EV_SYN       SYN_MT_REPORT 00000000 
    [     245.011819] EV_SYN       SYN_REPORT 00000000 
    [     245.025296] EV_SYN       SYN_MT_REPORT 00000000 
    [     245.025311] EV_SYN       SYN_MT_REPORT 00000000 
    [     245.025313] EV_SYN       SYN_REPORT           00000000 



    Protocol B: 
    ---------------------------------------------------------------------------------- 
    注册: 
        set_bit(EV_SYN, input_dev->evbit); 
        set_bit(EV_KEY, input_dev->evbit); 
        set_bit(EV_ABS, input_dev->evbit); 
        set_bit(INPUT_PROP_DIRECT, input_dev->propbit); 
        input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, sensor_max_x, 0, 0); 
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, sensor_max_y, 0, 0); 
        input_mt_init_slots(input_dev, num_of_fingers);   //和A相比多注册slot 
        input_register_device(input_dev); 

        如果注册了ABS_MT_PRESSURE,上报时就要上报ABS_MT_PRESSURE。 

    上报: 
        for (finger = 0; finger < num_of_fingers; finger++) { 
            ...//读取计算x、y坐标和id,触摸的状态 
            input_mt_slot(input_dev, id); 
            if (finger_down) { 
                input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); 
                input_report_abs(input_dev, ABS_MT_POSITION_X, x); 
                input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 
            } else {  //finger_up 
                input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0); 
            } 
        } 

        input_mt_report_pointer_emulation(input_dev, false); 
        input_sync(input_dev); 

    上报log: 
    按下一个点抬起 
    [      78.541863] EV_ABS       ABS_MT_TRACKING_ID   00000007 按下分配ID 
    [      78.541928] EV_ABS       ABS_MT_POSITION_X 0000021b 
    [      78.541944] EV_ABS       ABS_MT_POSITION_Y 00000442 
    [      78.541981] EV_SYN       SYN_REPORT 00000000 
    [      78.605574] EV_ABS       ABS_MT_TRACKING_ID   ffffffff 抬起释放ID  ID=-1释放 
    [      78.605595] EV_SYN       SYN_REPORT           00000000 

    再次按下一个点抬起 
    [      98.324526] EV_ABS       ABS_MT_TRACKING_ID   00000008 按下分配ID  上一次的ID +1 
    [      98.324590] EV_ABS       ABS_MT_POSITION_X 000000c8 
    [      98.324605] EV_ABS       ABS_MT_POSITION_Y 0000037a 
    [      98.324641] EV_SYN       SYN_REPORT 00000000 
    [      98.388583] EV_ABS       ABS_MT_TRACKING_ID   ffffffff 抬起释放ID  ID=-1释放 
    [      98.388603] EV_SYN       SYN_REPORT           00000000 

    两个点同时按下抬起 
    [     208.775409] EV_ABS       ABS_MT_SLOT          00000000 多点时标示 属于哪个slot   标示slot 0 
    [     208.775462] EV_ABS       ABS_MT_TRACKING_ID   0000000e 分配ID 
    [     208.775484] EV_ABS       ABS_MT_POSITION_X 00000215 
    [     208.775498] EV_ABS       ABS_MT_POSITION_Y 0000037c 
    [     208.775533] EV_SYN       SYN_REPORT 00000000 
    [     208.859516] EV_ABS       ABS_MT_SLOT          00000001 标示slot 1 
    [     208.859534] EV_ABS       ABS_MT_TRACKING_ID   0000000f 分配ID 上一 次ID +1 
    [     208.859538] EV_ABS       ABS_MT_POSITION_X 000000e6 
    [     208.859541] EV_ABS       ABS_MT_POSITION_Y 0000031f 
    [     208.859550] EV_SYN       SYN_REPORT 00000000 
    [     208.873597] EV_ABS       ABS_MT_SLOT 00000000 
    [     208.873637] EV_ABS       ABS_MT_TRACKING_ID   ffffffff 释放slot0 的ID 
    [     208.873659] EV_ABS       ABS_MT_SLOT 00000001 
    [     208.873667] EV_ABS       ABS_MT_TRACKING_ID   ffffffff 释放slot1 的ID 
    [     208.873688] EV_SYN       SYN_REPORT           00000000 

    代码分析: 
    input_mt_slot()根据ID注册一个slot 

    static inline void input_mt_slot(struct input_dev *dev, int slot) 

        input_event(dev, EV_ABS, ABS_MT_SLOT, slot); 



    input_mt_report_slot_state()分配ABS_MT_TRACKING_ID 
    void input_mt_report_slot_state(struct input_dev *dev, 
            unsigned int tool_type, bool active) 

        struct input_mt_slot *mt; 
        int id; 

        if (!dev->mt || !active) {                //如果active 为0就上报 ABS_MT_TRACKING_ID = -1表示手指抬起 
            input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); 
            return; 
        } 

        mt = &dev->mt[dev->slot]; 
        id = input_mt_get_value(mt, ABS_MT_TRACKING_ID); 
        if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)//如果是从新触摸的点即上一次ABS_MT_TRACKING_ID=-1 
            id = input_mt_new_trkid(dev); //就从新分配ABS_MT_TRACKING_ID, 新ID上在上一次的基础上+1 
    //如果手指没抬起,即ABS_MT_TRACKING_ID大于0,ABS_MT_TRACKING_ID本次并没 有改变即还在一个轨迹上 
        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); 
        input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); 


    input_mt_report_pointer_emulation(input_dev, false); 文档中写函数是用来 检测驱动是否能报告比slot还多的触控点。 

  • 相关阅读:
    Linux文件属性
    [Oracle] Listener的动态注册
    jQuery easyUI Pagination控件自定义div分页(不用datagrid)
    桂林电子科技大学出校流量控制器Android版1.0.0
    php使用check box
    Python windows ping
    Python selenium chrome 环境配置
    Linux wget auto login and backup database
    PyQt4 ShowHMDB show sqlite3 with QTableWidget summary
    PyQt4 py2exe 打包 HardwareManager
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5413724.html
Copyright © 2011-2022 走看看