美文网首页
GT5688的手势唤醒执行流程分析

GT5688的手势唤醒执行流程分析

作者: 加菲猫Jack | 来源:发表于2019-03-27 22:26 被阅读0次

注:本操作基于gt1x_1.6版本代码

1、首先打开手势唤醒功能

CONFIG_GTP_GESTURE_WAKEUP  =1

同时,static long gt1x_ioctl函数中,gsture_enabled也要置1。

int gesture_enabled = 1;    /* module switch */

然而修改上面之后发现还是进入gesture_disabled。解决方案是需要修改如下两个位置for debug。gestures_flag值要从0x00改成0xFF,驱动调通以后这两个位置需要改成0、交由App控制

void gt1x_gesture_debug(int on) 
{
    if (on) {
        gesture_enabled = 1;
        memset(gestures_flag, 0xFF, sizeof(gestures_flag));
    } else {
        gesture_enabled = 0;
        memset(gestures_flag, 0xFF, sizeof(gestures_flag));
        gesture_doze_status = DOZE_DISABLED;
    }
    GTP_DEBUG("Gesture debug %s", on ? "on":"off");
}

2、手势部分驱动执行流程:
2-1、手势init,按下开机键或者息屏后整机进入待机休眠,驱动由正常模式转到doze模式
创建gseture节点

s32 gt1x_init_node(void)
{
...
    proc_entry = proc_create(GESTURE_NODE, 0666, NULL, &gt1x_fops);
    if (proc_entry == NULL) {
        GTP_ERROR("CAN't create proc entry /proc/%s.", GESTURE_NODE);
        return -1;
    } else {
        GTP_INFO("Created proc entry /proc/%s.", GESTURE_NODE);
    }
#endif

向系统注册KEY_GES_CUSTOM这个电源事件

#ifdef CONFIG_GTP_GESTURE_WAKEUP
    input_set_capability(tpd->dev, EV_KEY, KEY_GES_CUSTOM);
       input_set_capability(tpd->dev, EV_KEY, KEY_GES_REGULAR);
#endif

驱动由正常模式转到doze模式

#ifdef CONFIG_GTP_GESTURE_WAKEUP
    gesture_clear_wakeup_data();
    if (gesture_enabled) {
        gesture_enter_doze();
        gt1x_irq_enable();
        gt1x_halt = 0;
    } else
#endif
//系统进入休眠
int gt1x_suspend(void)
   {
       s32 ret = -1;
    if (update_info.status) {
        return 0;
    }
    GTP_INFO("Suspend start...");
}
//关闭中断
void gt1x_irq_disable(void)
{
    unsigned long flag;

    spin_lock_irqsave(&irq_lock, flag);
    if (tpd_irq_flag) {
        GTP_INFO("gt1x_irq_disable is %d", tpd_irq_flag);
        tpd_irq_flag = 0;
    }
    spin_unlock_irqrestore(&irq_lock, flag);
}
//读取IC状态
static ssize_t gt1x_gesture_data_write(struct file *filp, const char __user * buff, size_t len, loff_t * off)
{
    s32 ret = 0;

    GTP_DEBUG_FUNC();

    ret = copy_from_user(&gesture_enabled, buff, 1);
    if (ret) {
        GTP_ERROR("copy_from_user failed.");
        return -EPERM;
    }

    GTP_DEBUG("gesture enabled:%x, ret:%d", gesture_enabled, ret);

    return len;
}
//给0x8040发送8,IC进入最小化手势doze状态
int gesture_enter_doze(void)
{
    int retry = 0;

    GTP_DEBUG_FUNC();
    GTP_DEBUG("Entering doze mode...");
    while (retry++ < 5) {
        if (!gt1x_send_cmd(0x08, 0)) {
            gesture_doze_status = DOZE_ENABLED;
            GTP_DEBUG("Working in doze mode!");
            return 0;
        }
        msleep(10);
    }
    GTP_ERROR("Send doze cmd failed.");
    return -1;
}

2-2、唤醒流程:

#ifdef CONFIG_GTP_GESTURE_WAKEUP
        ret = gesture_event_handler(tpd->dev);
        if (ret >= 0) {
            gt1x_irq_enable();
            mutex_unlock(&i2c_access);
            continue;
        }
#endif

读取gesture寄存器状态

static ssize_t gt1x_gesture_data_read(struct file *file, char __user * page, size_t size, loff_t * ppos)
{
    s32 ret = -1;
    GTP_DEBUG("visit gt1x_gesture_data_read. ppos:%d", (int)*ppos);
    if (*ppos) {
        return 0;
    }
    if (size == 4) {
        ret = copy_to_user(((u8 __user *) page), "GT1X", 4);
        return 4;
    }
    ret = simple_read_from_buffer(page, size, ppos, &gesture_data, sizeof(gesture_data));

    GTP_DEBUG("Got the gesture data.");
    return ret;
}

按键处理函数中对手势坐标对比

s32 gesture_event_handler(struct input_dev * dev)
{

//做一些初始化,为为读取坐标等做准备
    u8 doze_buf[4] = { 0 }, ges_type;
    static int err_flag1 = 0, err_flag2 = 0;
    int len, extra_len, need_chk;
    unsigned int key_code;
    s32 ret = 0;

    if (DOZE_ENABLED != gesture_doze_status) {
        return -1;
    }
    
    /** package: -head 4B + track points + extra info- 
        * - head -
        *  doze_buf[0]: gesture type, 
        *  doze_buf[1]: number of gesture points ,
        *  doze_buf[2]: protocol type, 
        *  doze_buf[3]: gesture extra data length.
        */

//对0x814B寄存器进行读取操作
    ret = gt1x_i2c_read(GTP_REG_WAKEUP_GESTURE, doze_buf, 4);
    if (ret < 0) {
        return 0;
    }    
    ges_type = doze_buf[0];
    len = doze_buf[1];
    need_chk = doze_buf[2] & 0x80;
    extra_len = doze_buf[3];
//读取到寄存器获取到的值    
    GTP_DEBUG("0x%x = 0x%02X,0x%02X,0x%02X,0x%02X", GTP_REG_WAKEUP_GESTURE,
        doze_buf[0], doze_buf[1], doze_buf[2], doze_buf[3]);
    //对获取到的报点验证
    if (len > GESTURE_MAX_POINT_COUNT) {
        GTP_ERROR("Gesture contain too many points!(%d)", len);
        len = GESTURE_MAX_POINT_COUNT;
    }

    if (extra_len > 32) {
        GTP_ERROR("Gesture contain too many extra data!(%d)", extra_len);
        extra_len = 32;
    }

检测手指轨迹,符合条件即唤醒系统

    /* get gesture extra info */
    if (extra_len >= 0) {
        u8 ges_data[extra_len + 1];
        
        /* head 4 + extra data * 4 + chksum 1 */
        ret = gt1x_i2c_read(GTP_REG_WAKEUP_GESTURE + 4,
            ges_data, extra_len + 1);
        if (ret < 0) {
            GTP_ERROR("Read extra gesture data failed.");
            return 0;
        }
        
        if (likely(need_chk)) { /* calc checksum */
            bool val;

            ges_data[extra_len] += doze_buf[0] + doze_buf[1]
                + doze_buf[2] + doze_buf[3];

            val = calc_checksum(ges_data, extra_len + 1, CHKBITS_8);
            if (unlikely(!val)) { /* check failed */
                GTP_ERROR("Gesture checksum error.");
                if (err_flag1) {
                    err_flag1 = 0;
                    ret = 0;
                    goto clear_reg;
                } else {
                    /* just return 0 without clear reg, 
                                    this will receive another int, we
                                    check the data in the next frame */
                    err_flag1 = 1;
                    return 0;
                }
            }
            
            err_flag1 = 0;
        }
        
        mutex_lock(&gesture_data_mutex);
        memcpy(&gesture_data.data[4 + len * 4], ges_data, extra_len);
        mutex_unlock(&gesture_data_mutex);
    }
   /* gt1x_gesture_debug里的gestures_flag内存值要为0xFF,否则会一直进入以下打印:Gesture has been disabled*/
    /* check gesture type (if available?) */
    if (ges_type == 0 || !QUERYBIT(gestures_flag, ges_type)) {
        GTP_INFO("Gesture[0x%02X] has been disabled.", doze_buf[0]);
        doze_buf[0] = 0x00;
        gt1x_i2c_write(GTP_REG_WAKEUP_GESTURE, doze_buf, 1);
        gesture_enter_doze();
        return 0;
    }

    /* get gesture point data */
    if (len > 0) { /* coor num * 4 + chksum 2*/
        u8 ges_data[len * 4 + 2];

        ret = gt1x_i2c_read(GES_BUFFER_ADDR, ges_data, len * 4);
        if (ret < 0) {
            GTP_ERROR("Read gesture data failed.");
            return 0;
        }
        
        /* checksum reg for gesture point data */
        ret = gt1x_i2c_read(0x819F, &ges_data[len * 4], 2);
        if (ret < 0) {
            GTP_ERROR("Read gesture data failed.");
            return 0;
        }
        
        if (likely(need_chk)) {
            bool val = calc_checksum(ges_data,
               len * 4 + 2, CHKBITS_16);
            if (unlikely(!val)) { /* check failed */
                GTP_ERROR("Gesture checksum error.");
                if (err_flag2) {
                    err_flag2 = 0;
                    ret = 0;
                    goto clear_reg;
                } else {
                    err_flag2 = 1;
                    return 0;
                }
            }
            
            err_flag2 = 0;
        }
        
        mutex_lock(&gesture_data_mutex);
        memcpy(&gesture_data.data[4], ges_data, len * 4);
        mutex_unlock(&gesture_data_mutex);
    }

    mutex_lock(&gesture_data_mutex);
    gesture_data.data[0] = ges_type;    // gesture type
    gesture_data.data[1] = len;         // gesture points number
    gesture_data.data[2] = doze_buf[2] & 0x7F; // protocol type
    gesture_data.data[3] = extra_len;   // gesture date length
    mutex_unlock(&gesture_data_mutex);

    //获取键值,触发唤醒键来上报唤醒屏幕,清除0x814B状态
    /* get key code */
    key_code = ges_type < 16? KEY_GES_CUSTOM : KEY_GES_REGULAR;
    GTP_DEBUG("Gesture: 0x%02X, points: %d", doze_buf[0], doze_buf[1]);

    input_report_key(dev, key_code, 1);
    input_sync(dev);
    input_report_key(dev, key_code, 0);
    input_sync(dev);

clear_reg:
    doze_buf[0] = 0; // clear ges flag
    gt1x_i2c_write(GTP_REG_WAKEUP_GESTURE, doze_buf, 1);
    return ret;
}

endif // GTP_GESTURE_WAKEUP

移除gesture_node

remove_proc_entry(GESTURE_NODE, NULL);

唤醒TP

static void tpd_resume(struct device *h)

唤醒系统

static s32 gt1x_wakeup_sleep(void)
{
    GTP_DEBUG("Wake up begin.");
    gt1x_irq_disable();//关闭中断
    while (retry++ < 2) {
#ifdef CONFIG_GTP_GESTURE_WAKEUP
        if (gesture_enabled) {
            gesture_doze_status = DOZE_DISABLED;//doze状态更新为disabled
            ret = gt1x_reset_guitar();//复位
            if(!ret) {
                break;
            }
        } else
#endif
    /* wake up through int port */
          //使用中断GPIO唤醒          
  GTP_GPIO_OUTPUT(GTP_INT_PORT, gt1x_wakeup_level);
            msleep(5);

            /* Synchronize int IO */
            GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
            msleep(50);
            GTP_GPIO_AS_INT(GTP_INT_PORT);
            flag = 1;
...
}

相关文章

网友评论

      本文标题:GT5688的手势唤醒执行流程分析

      本文链接:https://www.haomeiwen.com/subject/kxmuyqtx.html