1262 lines
36 KiB
C
1262 lines
36 KiB
C
/*
|
|
* Privileged & confidential All Rights/Copyright Reserved by FocalTech.
|
|
* ** Source code released bellows and hereby must be retained as
|
|
* FocalTech's copyright and with the following disclaimer accepted by
|
|
* Receiver.
|
|
*
|
|
* "THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
* EVENT SHALL THE FOCALTECH'S AND ITS AFFILIATES'DIRECTORS AND OFFICERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* The initial work you should do is to implement the i2c communication function based on your platform:
|
|
* platform_i2c_write() and platform_i2c_read().
|
|
*
|
|
* In your system, you should register a interrupt at initialization stage(The interrupt trigger mode is
|
|
* falling-edge mode), then interrupt handler will run while host detects the falling-edge of INT port.
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Included header files
|
|
*****************************************************************************/
|
|
/* #include "touch_panel/ft3x68/ft3x68.h" */
|
|
#include "ft3x68.h"
|
|
|
|
#if TCFG_TP_FT3X68_ENABLE
|
|
|
|
#define _IIC_USE_HW
|
|
#include "iic_api.h"
|
|
|
|
|
|
#define LOG_TAG "[TP]"
|
|
#define PRINTF(format, ...) printf(format, ## __VA_ARGS__)
|
|
#if 0
|
|
#define log_info(format, ...) PRINTF(LOG_TAG "info:" format, ## __VA_ARGS__)
|
|
#define log_debug(format, ...) PRINTF(LOG_TAG "debug:" format, ## __VA_ARGS__)
|
|
#define log_error(format, ...) PRINTF(LOG_TAG "error:" format, ## __VA_ARGS__)
|
|
#else
|
|
#define log_info(format, ...) //PRINTF(LOG_TAG "info:" format, ## __VA_ARGS__)
|
|
#define log_debug(format, ...)
|
|
#define log_error(format, ...) PRINTF(LOG_TAG "error:" format, ## __VA_ARGS__)
|
|
#endif
|
|
|
|
#define abs(x) __builtin_abs(x)//((x)>0?(x):-(x) )
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Private constant and macro definitions using #define
|
|
*****************************************************************************/
|
|
#define FTS_CMD_START_DELAY 12
|
|
#define FTS_DEV_SLAVE_ADDR (0x38<<1)
|
|
/* register address */
|
|
#define FTS_REG_WORKMODE 0x00
|
|
#define FTS_REG_WORKMODE_FACTORY_VALUE 0x40
|
|
#define FTS_REG_WORKMODE_SCAN_VALUE 0xC0
|
|
#define FTS_REG_FLOW_WORK_CNT 0x91
|
|
#define FTS_REG_POWER_MODE 0xA5
|
|
#define FTS_REG_GESTURE_EN 0xD0
|
|
#define FTS_REG_GESTURE_ENABLE 0x01
|
|
#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3
|
|
|
|
/*Max point numbers of gesture trace*/
|
|
#define MAX_POINTS_GESTURE_TRACE 6
|
|
/*Length of gesture information*/
|
|
#define MAX_LEN_GESTURE_INFO (MAX_POINTS_GESTURE_TRACE * 4 + 2)
|
|
|
|
/*Max point numbers of touch trace*/
|
|
#define MAX_POINTS_TOUCH_TRACE 2
|
|
/*Length of touch information*/
|
|
#define MAX_LEN_TOUCH_INFO (MAX_POINTS_TOUCH_TRACE * 6 + 2)
|
|
|
|
/*Max touch points that touch controller supports*/
|
|
#define FTS_MAX_POINTS_SUPPORT 1
|
|
|
|
#define TP_FPS 60
|
|
|
|
#define VK_MIN (VK_X < VK_Y ? VK_X : VK_Y)
|
|
#define VK_MAX (VK_X > VK_Y ? VK_X : VK_Y)
|
|
|
|
// 滑屏阈值
|
|
/* #define VK_X_MOVE (VK_MIN/5) */
|
|
/* #define VK_Y_MOVE (VK_MIN/5) */
|
|
/* #define VK_X_Y_DIFF (VK_MIN/10) */
|
|
|
|
// 惯性阈值
|
|
/* #define ENERGY_XDISTANCE 4//(VK_MIN/30) */
|
|
/* #define ENERGY_YDISTANCE 4//(VK_MIN/30) */
|
|
|
|
#define ENERGY_NUM 3 //取最后n次中最大差值
|
|
#define ENERGY_T_MS (1000000/TP_FPS/1000)
|
|
|
|
// reset gpio
|
|
#define CST816S_RESET_H() gpio_set_mode(IO_PORT_SPILT(TCFG_TP_RESET_IO), PORT_OUTPUT_HIGH)
|
|
#define CST816S_RESET_L() gpio_set_mode(IO_PORT_SPILT(TCFG_TP_RESET_IO), PORT_OUTPUT_LOW)
|
|
|
|
// iic
|
|
#define CST816S_IIC_DELAY 1
|
|
#define CST816S_IIC_ADDR 0x46
|
|
#define SLAVE_DEV_ADDR (0x15) //固有,不可配置,用于 chipID 读取,固件烧录操作
|
|
|
|
#define PER_LEN 512
|
|
#define CST816S_UPGRADE_ADD (0x6A) /* 7-bit i2c addr */
|
|
#define HYN_I2C_ADDR 0x15 /* 7-bit i2c addr */ //0x38
|
|
|
|
#define I2C_MASTER_CI2C0 0
|
|
#define i2c_t uint8_t
|
|
|
|
typedef enum {
|
|
TP_RUN_STEP_STOP = 0,
|
|
TP_RUN_STEP_INIT,
|
|
TP_RUN_STEP_RUN_IDLE,
|
|
TP_RUN_STEP_RUN,
|
|
} TP_RUN_STEP_E;
|
|
|
|
// iic
|
|
typedef struct {
|
|
u8 init;
|
|
/* u16 iic_delay; */
|
|
hw_iic_dev iic_hdl;
|
|
} ft_param;
|
|
|
|
// 惯性
|
|
struct touch_kinetic_energy {
|
|
u16 x;
|
|
u16 y;
|
|
};
|
|
|
|
static struct touch_kinetic_energy tke[ENERGY_NUM]; // 惯性
|
|
|
|
static volatile TP_RUN_STEP_E tp_step = TP_RUN_STEP_STOP;
|
|
/* static u8 tp_last_staus = ELM_EVENT_TOUCH_UP; // 状态记录 */
|
|
/* static int tp_down_cnt = 0; // 长按计数 */
|
|
static bool touch_flag = 0; // 触摸标记
|
|
static OS_SEM touch_sem; // 触摸中断post
|
|
|
|
static ft_param module_param = {0}; // iic
|
|
#define __this (&module_param)
|
|
|
|
|
|
static void ctp_delay_us(unsigned int time)
|
|
{
|
|
udelay(time);
|
|
}
|
|
static void ctp_delay_ms(unsigned short time)
|
|
{
|
|
if (time >= 10) {
|
|
os_time_dly(time / 10 + 1);
|
|
} else {
|
|
mdelay(time);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Private variables/functions
|
|
*****************************************************************************/
|
|
static struct fts_ts_data _fts_data = {
|
|
.suspended = 0,
|
|
.gesture_support = FTS_GESTURE_EN,
|
|
.esd_support = 1,
|
|
/* .iic_hdl = 0, */
|
|
.iic_delay = 70,
|
|
.int_io_init = 0,
|
|
};
|
|
|
|
static int fts_gpio_interrupt_handler(void);
|
|
/*****************************************************************************
|
|
* Global variable or extern global variabls/functions
|
|
*****************************************************************************/
|
|
struct fts_ts_data *fts_data = &_fts_data;
|
|
void mdelay(u32 ms);
|
|
void delay(volatile u32 t);
|
|
/*delay, unit: millisecond */
|
|
void fts_msleep(unsigned long msec)
|
|
{
|
|
mdelay(msec);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
platform_tp_deal
|
|
*****************************************************************************/
|
|
void ctp_enter_sleep(void)
|
|
{
|
|
fts_ts_suspend();
|
|
}
|
|
void ctp_exit_sleep(void)
|
|
{
|
|
fts_ts_resume();
|
|
}
|
|
|
|
static u8 tp_last_staus = ELM_EVENT_TOUCH_UP;
|
|
static int tp_down_cnt = 0;
|
|
#ifndef abs
|
|
#define abs(x) ((x)>0?(x):-(x) )
|
|
#endif
|
|
|
|
#undef log_info
|
|
#define log_info(fmt, ...)
|
|
|
|
#define ENERGY_XDISTANCE 15
|
|
#define ENERGY_YDISTANCE 15
|
|
#define ENERGY_TIME 20 //ms
|
|
/* struct touch_kinetic_energy { */
|
|
/* int t1; */
|
|
/* int x1; */
|
|
/* int y1; */
|
|
|
|
/* int t2; */
|
|
/* int x2; */
|
|
/* int y2; */
|
|
/* }; */
|
|
/* static struct touch_kinetic_energy tke = {0}; */
|
|
|
|
static void touch_info_reset()
|
|
{
|
|
tp_last_staus = ELM_EVENT_TOUCH_UP;
|
|
tp_down_cnt = 0;
|
|
}
|
|
static void tke_start(int x, int y)
|
|
{
|
|
memcpy(&tke[0], &tke[1], sizeof(struct touch_kinetic_energy) * (ENERGY_NUM - 1));
|
|
|
|
tke[ENERGY_NUM - 1].x = x;
|
|
tke[ENERGY_NUM - 1].y = y;
|
|
log_info("tke start %d, %d\n", x, y);
|
|
}
|
|
|
|
static void tke_stop(int x, int y, struct touch_event *up_t)
|
|
{
|
|
struct touch_event t = {0};
|
|
int tke_x = 0;
|
|
int tke_y = 0;
|
|
u8 xdir, ydir;
|
|
|
|
|
|
for (int i = 0; i < (ENERGY_NUM - 1); i++) {
|
|
if ((tke[i].x == 0xffff) || (tke[i].y == 0xffff)) {
|
|
continue;
|
|
}
|
|
int tmp_x = (int)tke[i + 1].x - (int)tke[i].x;
|
|
int tmp_y = (int)tke[i + 1].y - (int)tke[i].y;
|
|
if (abs(tke_x) < abs(tmp_x)) {
|
|
tke_x = tmp_x;
|
|
}
|
|
if (abs(tke_y) < abs(tmp_y)) {
|
|
tke_y = tmp_y;
|
|
}
|
|
log_info("[%d], x:0x%x, y:0x%x", i, tke[i].x, tke[i].y);
|
|
log_info("stke %d, %d\n", tke_x, tke_y);
|
|
}
|
|
log_info("stke end %d, %d\n", tke_x, tke_y);
|
|
|
|
if (((abs(tke_x) >= ENERGY_XDISTANCE) || abs(tke_y) >= ENERGY_YDISTANCE)) {
|
|
up_t->has_energy = 1;
|
|
ui_touch_msg_post(up_t);
|
|
|
|
if (abs(tke_x) < ENERGY_XDISTANCE) {
|
|
tke_x = 0;
|
|
}
|
|
if (abs(tke_y) < ENERGY_YDISTANCE) {
|
|
tke_y = 0;
|
|
}
|
|
xdir = (tke_x < 0) ? 1 : 2;
|
|
ydir = (tke_y < 0) ? 1 : 2;
|
|
/* printf("xdir %d, ydir %d\n", xdir, ydir); */
|
|
|
|
t.event = ELM_EVENT_TOUCH_ENERGY;
|
|
t.x = (tke_x << 16) | (ENERGY_T_MS & 0xffff);
|
|
t.y = (tke_y << 16) | (ydir << 8) | (xdir & 0xff);
|
|
ui_touch_msg_post(&t);
|
|
|
|
/* printf("tke out %d, %d, %d, %d, %d\n", (t.x & 0xffff), (t.x >> 16), (t.y >> 16), (t.y & 0xff), (t.y >> 8) & 0xff); */
|
|
|
|
} else {
|
|
//在这里发送up消息,因为没有惯性,所以直接发送
|
|
ui_touch_msg_post(up_t);
|
|
}
|
|
|
|
memset(&tke, 0xff, sizeof(tke));
|
|
|
|
}
|
|
|
|
|
|
struct touch_info {
|
|
int y;
|
|
int x;
|
|
int p;
|
|
int id;
|
|
int count;
|
|
};
|
|
|
|
#if TCFG_LCD_FLIP_ENABLE
|
|
#define Y_MIRROR 0
|
|
#define X_MIRROR 0
|
|
#else
|
|
#define Y_MIRROR 1
|
|
#define X_MIRROR 1
|
|
#endif
|
|
#define SW_X_Y 1
|
|
#define VK_Y 466
|
|
#define VK_X 466
|
|
#define VK_Y_MOVE 100//227
|
|
#define VK_X_MOVE 100//227
|
|
#define VK_X_Y_DIFF 47
|
|
#define X_SINGLE_MOVE 0 //单次滑动距离上限阈值,用于过滤多点触摸时误发L/R_MOVE事件 0 关闭 ;阈值,根据tp实际情况调整
|
|
#define Y_SINGLE_MOVE 0 //y方向过滤
|
|
|
|
|
|
|
|
static void tpd_down(int raw_x, int raw_y, int x, int y, int p)
|
|
{
|
|
struct touch_event t;
|
|
static int first_x = 0;
|
|
static int first_y = 0;
|
|
static u8 move_flag = 0;
|
|
|
|
if (x < 0) {
|
|
x = 0;
|
|
}
|
|
if (x > (VK_X - 1)) {
|
|
x = VK_X - 1;
|
|
}
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
if (y > (VK_Y - 1)) {
|
|
y = VK_Y - 1;
|
|
}
|
|
#if Y_MIRROR
|
|
x = VK_X - x - 1;
|
|
#endif
|
|
|
|
#if X_MIRROR
|
|
y = VK_Y - y - 1;
|
|
#endif
|
|
|
|
if ((tp_last_staus == ELM_EVENT_TOUCH_DOWN) && (x == first_x) && (y == first_y)) {
|
|
tp_down_cnt++;
|
|
if (tp_down_cnt < 30) {
|
|
return;
|
|
}
|
|
tp_last_staus = ELM_EVENT_TOUCH_HOLD;
|
|
tp_down_cnt = 0;
|
|
|
|
t.event = tp_last_staus;
|
|
t.x = x;
|
|
t.y = y;
|
|
ui_touch_msg_post(&t);
|
|
return;
|
|
}
|
|
|
|
log_info("D[%4d %4d %4d]\n", x, y, p);
|
|
if (tp_last_staus != ELM_EVENT_TOUCH_UP) {
|
|
int x_move = abs(x - first_x);
|
|
int y_move = abs(y - first_y);
|
|
|
|
if (!move_flag && (x_move >= VK_X_MOVE || y_move >= VK_Y_MOVE) && (abs(x_move - y_move) >= VK_X_Y_DIFF)) {
|
|
if (x_move > y_move) {
|
|
if (x > first_x) {
|
|
tp_last_staus = ELM_EVENT_TOUCH_R_MOVE;
|
|
} else {
|
|
tp_last_staus = ELM_EVENT_TOUCH_L_MOVE;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (y > first_y) {
|
|
tp_last_staus = ELM_EVENT_TOUCH_D_MOVE;
|
|
} else {
|
|
tp_last_staus = ELM_EVENT_TOUCH_U_MOVE;
|
|
}
|
|
}
|
|
move_flag = 1;
|
|
} else {
|
|
if ((x == first_x) && (y == first_y)) {
|
|
return;
|
|
}
|
|
tp_last_staus = ELM_EVENT_TOUCH_MOVE;
|
|
/* return; */
|
|
}
|
|
/* tp_last_staus = ELM_EVENT_TOUCH_HOLD; */
|
|
tke_start(x, y);
|
|
} else {
|
|
tp_last_staus = ELM_EVENT_TOUCH_DOWN;
|
|
first_x = x;
|
|
first_y = y;
|
|
move_flag = 0;
|
|
tke_start(x, y);
|
|
}
|
|
|
|
t.event = tp_last_staus;
|
|
t.x = x;
|
|
t.y = y;
|
|
ui_touch_msg_post(&t);
|
|
}
|
|
|
|
static void tpd_up(int raw_x, int raw_y, int x, int y, int p)
|
|
{
|
|
struct touch_event t = {0};
|
|
|
|
if (tp_last_staus == ELM_EVENT_TOUCH_UP) {
|
|
return ; // 重复
|
|
}
|
|
|
|
if (x < 0) {
|
|
x = 0;
|
|
}
|
|
if (x > (VK_X - 1)) {
|
|
x = VK_X - 1;
|
|
}
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
if (y > (VK_Y - 1)) {
|
|
y = VK_Y - 1;
|
|
}
|
|
|
|
#if Y_MIRROR
|
|
x = VK_X - x - 1;
|
|
#endif
|
|
|
|
#if X_MIRROR
|
|
y = VK_Y - y - 1;
|
|
#endif
|
|
|
|
log_info("U[%4d %4d %4d]\n", x, y, 0);
|
|
tp_last_staus = ELM_EVENT_TOUCH_UP;
|
|
tp_down_cnt = 0;
|
|
t.event = tp_last_staus;
|
|
t.x = x;
|
|
t.y = y;
|
|
|
|
//不在这里发送up消息,在tke_stop里面!!!
|
|
/* ui_touch_msg_post(&t); */
|
|
|
|
tke_stop(x, y, &t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* reset chip
|
|
*****************************************************************************/
|
|
static int fts_hw_reset(uint8_t msec)
|
|
{
|
|
/*firsty. set reset_pin low, and then delay 10ms*/
|
|
gpio_write(TCFG_TP_RESET_IO, 0);
|
|
fts_msleep(10);
|
|
|
|
/*secondly. set reset_pin high, and then delay 200ms*/
|
|
gpio_write(TCFG_TP_RESET_IO, 1);
|
|
fts_msleep(msec);
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Initialize i2c
|
|
*****************************************************************************/
|
|
static int platform_i2c_init(void)
|
|
{
|
|
/*Initialize I2C bus, you should implement it based on your platform*/
|
|
/* iic_init(fts_data->iic_hdl); */
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Initialize reset pin
|
|
*****************************************************************************/
|
|
static int platform_reset_pin_cfg(void)
|
|
{
|
|
/*Initialize reset_pin, you should implement it based on your platform*/
|
|
|
|
/*firstly,set the reset_pin to output mode*/
|
|
/*secondly,set the reset_pin to low */
|
|
if (TCFG_TP_RESET_IO == NO_CONFIG_PORT) {
|
|
return -1;
|
|
}
|
|
/* gpio_set_hd0(TCFG_TP_RESET_IO, 1); //set_strengh 0x01 */
|
|
gpio_hw_set_direction(IO_PORT_SPILT(TCFG_TP_RESET_IO), 0); //set dir_output
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Initialize gpio interrupt, and set trigger mode to falling edge.
|
|
*****************************************************************************/
|
|
static int platform_interrupt_gpio_init(void)
|
|
{
|
|
/*Initialize gpio interrupt , and the corresponding interrupt function is fts_gpio_interrupt_handler,
|
|
you should implement it based on your platform*/
|
|
|
|
|
|
/*firstly,set int_pin to input mode with pull-up*/
|
|
/*secondly,and set int_pin's trigger mode to falling edge trigger */
|
|
if (TCFG_TP_INT_IO == NO_CONFIG_PORT) {
|
|
return -1;
|
|
}
|
|
if (fts_data->int_io_init == 0) {
|
|
/* port_edge_wkup_set_callback_by_index(1, fts_gpio_interrupt_handler); // 序号需要和板级配置中的wk_param对应上 */
|
|
fts_data->int_io_init = 1;
|
|
} else {
|
|
/* power_wakeup_index_enable(1, true);//中断使能 */
|
|
}
|
|
/* gpio_set_pull_up(TCFG_TP_INT_IO, 1); */
|
|
/* gpio_set_die(TCFG_TP_INT_IO, 1); */
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* TP power on
|
|
*****************************************************************************/
|
|
static void fts_power_on(void)
|
|
{
|
|
/*refer to ic datasheet*/
|
|
/* if (TCFG_TP_POWER_IO == NO_CONFIG_PORT) { */
|
|
/* return ; */
|
|
/* } */
|
|
printf("fts power on\n");
|
|
/* gpio_hw_direction_output(IO_PORT_SPILT(TCFG_TP_POWER_IO), 1); */
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Initialize timer and set to interrupt mode which period is 1 second
|
|
*****************************************************************************/
|
|
static int platform_interrupt_timer_init(void)
|
|
{
|
|
|
|
/*Initialize timer and set to interrupt mode which period is 1 second,
|
|
and the corresponding interrupt function is fts_timer_interrupt_handler,
|
|
you should implement it based on your platform*/
|
|
return 0;
|
|
}
|
|
/* ------------------------------------------------------------------------------------*/
|
|
//* @brief platform_i2c_write
|
|
/* ------------------------------------------------------------------------------------*/
|
|
u16 platform_i2c_write(u8 *buf, u16 len)
|
|
{
|
|
u16 i = 0;
|
|
iic_start(__this->iic_hdl);
|
|
if (0 == iic_tx_byte(__this->iic_hdl, FTS_DEV_SLAVE_ADDR)) {
|
|
iic_stop(__this->iic_hdl);
|
|
FTS_ERROR("%s tx slave_addr error\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
/* delay(fts_data ->iic_delay); */
|
|
delay(70);
|
|
if (0 == iic_tx_byte(__this->iic_hdl, buf[i])) {
|
|
iic_stop(__this->iic_hdl);
|
|
FTS_ERROR("%s tx buf error\n", __func__);
|
|
return -2;
|
|
}
|
|
}
|
|
iic_stop(__this->iic_hdl);
|
|
return i;
|
|
}
|
|
/* ------------------------------------------------------------------------------------*/
|
|
//* @brief platform_i2c_read
|
|
/* ------------------------------------------------------------------------------------*/
|
|
u16 platform_i2c_read(u8 *buf, u16 len)
|
|
{
|
|
u16 i = 0;
|
|
iic_start(__this->iic_hdl);
|
|
if (0 == iic_tx_byte(__this->iic_hdl, FTS_DEV_SLAVE_ADDR + 1)) {
|
|
iic_stop(__this->iic_hdl);
|
|
FTS_ERROR("%s tx slave_addr error\n", __func__);
|
|
return -1;
|
|
}
|
|
for (i = 0; i < len - 1; i++) {
|
|
/* delay(fts_data->iic_delay); */
|
|
delay(70);
|
|
*buf++ = iic_rx_byte(__this->iic_hdl, 1, NULL);
|
|
}
|
|
i++;
|
|
*buf = iic_rx_byte(__this->iic_hdl, 0, NULL);
|
|
iic_stop(__this->iic_hdl);
|
|
|
|
return i;
|
|
}
|
|
/*****************************************************************************
|
|
* Name: fts_write
|
|
* Brief:
|
|
* Write function via I2C bus, you should implement it based on your platform.
|
|
*
|
|
* The code below is only a sample code, a pseudo code. you must implement it
|
|
* following standard I2C protocol based on your platform
|
|
*
|
|
*
|
|
* Input: @addr: the command or register address
|
|
* @data: the data buffer, data buffer can be NULL for commands without data fields.
|
|
* @datalen: length of data buffer
|
|
* Output:
|
|
* Return:
|
|
* return 0 if success, otherwise error code.
|
|
*****************************************************************************/
|
|
int fts_write(uint8_t addr, uint8_t *data, uint16_t datalen)
|
|
{
|
|
/*TODO based your platform*/
|
|
int ret = 0;
|
|
uint8_t txbuf[256] = { 0 };
|
|
uint16_t txlen = 0;
|
|
int i = 0;
|
|
|
|
if (datalen >= 256) {
|
|
FTS_ERROR("txlen(%d) fails", datalen);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&txbuf[0], &addr, 1);
|
|
txlen = 1;
|
|
if (data && datalen) {
|
|
memcpy(&txbuf[txlen], data, datalen);
|
|
txlen += datalen;
|
|
}
|
|
|
|
/*call platform_i2c_write function to transfer I2C package to TP controller
|
|
*platform_i2c_write() is different for different platform, based on your platform.
|
|
*/
|
|
for (i = 0; i < 3; i++) {
|
|
ret = platform_i2c_write(txbuf, txlen);
|
|
if (ret < 0) {
|
|
FTS_ERROR("platform_i2c_write(%d) fails,ret:%d,retry:%d", addr, ret, i);
|
|
continue;
|
|
} else {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_read
|
|
* Brief:
|
|
* Read function via I2C bus, you should implement it based on your platform.
|
|
*
|
|
* The code below is only a sample code, a pseudo code. you must implement it
|
|
* following standard I2C protocol based on your platform
|
|
*
|
|
*
|
|
* Input: @addr: the command or register data
|
|
* @datalen: length of data buffer
|
|
* Output:
|
|
* @data: the data buffer read from TP controller
|
|
* Return:
|
|
* return 0 if success, otherwise error code.
|
|
*****************************************************************************/
|
|
int fts_read(uint8_t addr, uint8_t *data, uint16_t datalen)
|
|
{
|
|
/*TODO based your platform*/
|
|
int ret = 0;
|
|
int i = 0;
|
|
|
|
if (!data || !datalen) {
|
|
FTS_ERROR("data is null, or datalen is 0");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
/*call platform_i2c_write function to transfer I2C package to TP controller
|
|
*platform_i2c_write() is different for different platform, based on your platform.
|
|
*/
|
|
ret = platform_i2c_write(&addr, 1);
|
|
/* ret = system_iic_read_nbytes(__this->iic_hdl, HYN_I2C_ADDR, &addr, 1, data, datalen); */
|
|
if (ret < 0) {
|
|
FTS_ERROR("platform_i2c_write(0x%x) fails,ret:%d,retry:%d", addr, ret, i);
|
|
continue;
|
|
}
|
|
|
|
|
|
/*call platform_i2c_read function to transfer I2C package to read data from TP controller
|
|
*platform_i2c_read() is different for different platform, based on your platform.
|
|
*/
|
|
ret = platform_i2c_read(data, datalen);
|
|
if (ret < 0) {
|
|
FTS_ERROR("platform_i2c_read(0x%x) fails,ret:%d,retry:%d", addr, ret, i);
|
|
continue;
|
|
}
|
|
|
|
ret = 0;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_write_reg
|
|
* Brief:
|
|
* write function via I2C bus, you should implement it based on your platform.
|
|
*
|
|
* The code below is only a sample code, a pseudo code. you must implement it
|
|
* following standard I2C protocol based on your platform
|
|
*
|
|
*
|
|
* Input: @addr: the command or register address
|
|
* @val: the data write to TP controller
|
|
* Return:
|
|
* return 0 if success, otherwise error code.
|
|
*****************************************************************************/
|
|
int fts_write_reg(uint8_t addr, uint8_t val)
|
|
{
|
|
return fts_write(addr, &val, 1);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_read_reg
|
|
* Brief:
|
|
* read function via I2C bus, you should implement it based on your platform.
|
|
*
|
|
* The code below is only a sample code, a pseudo code. you must implement it
|
|
* following standard I2C protocol based on your platform
|
|
*
|
|
*
|
|
* Input: @addr: the command or register address
|
|
* Output:
|
|
* @val: the data read from TP controller
|
|
* Return:
|
|
* return 0 if success, otherwise error code.
|
|
*****************************************************************************/
|
|
int fts_read_reg(uint8_t addr, uint8_t *val)
|
|
{
|
|
return fts_read(addr, val, 1);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_check_id
|
|
* Brief:
|
|
* The function is used to check id.
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
* return 0 if check id successfully, otherwise error code.
|
|
*****************************************************************************/
|
|
static int fts_check_id(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
uint8_t chip_id[2] = { 0 };
|
|
|
|
|
|
/*delay 200ms,wait fw*/
|
|
fts_msleep(200);
|
|
|
|
/*get chip id*/
|
|
fts_read_reg(FTS_REG_CHIP_ID, &chip_id[0]);
|
|
fts_read_reg(FTS_REG_CHIP_ID2, &chip_id[1]);
|
|
if ((FTS_CHIP_IDH == chip_id[0]) && (FTS_CHIP_IDL == chip_id[1])) {
|
|
FTS_INFO("get ic information, chip id = 0x%02x%02x", chip_id[0], chip_id[1]);
|
|
return 0;
|
|
}
|
|
|
|
/*get boot id*/
|
|
FTS_INFO("fw is invalid, need read boot id");
|
|
ret = fts_write_reg(0x55, 0xAA);
|
|
if (ret < 0) {
|
|
FTS_ERROR("start cmd write fail");
|
|
return ret;
|
|
}
|
|
|
|
fts_msleep(FTS_CMD_START_DELAY);
|
|
ret = fts_read(FTS_CMD_READ_ID, chip_id, 2);
|
|
if ((ret == 0) && ((FTS_CHIP_IDH == chip_id[0]) && (FTS_CHIP_IDL == chip_id[1]))) {
|
|
FTS_INFO("get ic information, boot id = 0x%02x%02x", chip_id[0], chip_id[1]);
|
|
ret = 0;
|
|
} else {
|
|
FTS_ERROR("read boot id fail,read:0x%02x%02x", chip_id[0], chip_id[1]);
|
|
return -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_esdcheck_algorithm
|
|
* Brief:
|
|
* The function is use to esd check.It should be called in timer interrupt handler.
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
*****************************************************************************/
|
|
static void fts_esdcheck_process(void)
|
|
{
|
|
uint8_t reg_value = 0;
|
|
static uint8_t flow_work_hold_cnt = 0;
|
|
static uint8_t flow_work_cnt_last = 0;
|
|
|
|
/* 1. check power state, if suspend, no need check esd */
|
|
if (fts_data->suspended == 1) {
|
|
FTS_DEBUG("In suspend, not check esd");
|
|
/* because in suspend state, when upgrade FW, will
|
|
* active ESD check(active = 1); when resume, don't check ESD again
|
|
*/
|
|
return ;
|
|
}
|
|
|
|
/* 2. In factory mode, can't check esd */
|
|
fts_read_reg(FTS_REG_WORKMODE, ®_value);
|
|
if ((reg_value == FTS_REG_WORKMODE_FACTORY_VALUE) || (reg_value == FTS_REG_WORKMODE_SCAN_VALUE)) {
|
|
FTS_DEBUG("in factory mode(%x), no check esd", reg_value);
|
|
return ;
|
|
}
|
|
|
|
/* 3. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */
|
|
fts_read_reg(FTS_REG_FLOW_WORK_CNT, ®_value);
|
|
if (flow_work_cnt_last == reg_value) {
|
|
flow_work_hold_cnt++;
|
|
} else {
|
|
flow_work_hold_cnt = 0;
|
|
}
|
|
|
|
flow_work_cnt_last = reg_value;
|
|
|
|
/* 4. If need hardware reset, then handle it here */
|
|
if (flow_work_hold_cnt >= 5) {
|
|
FTS_DEBUG("ESD, Hardware Reset");
|
|
flow_work_hold_cnt = 0;
|
|
fts_hw_reset(200);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_gesture_process
|
|
* Brief:
|
|
* The function is used to read and parse gesture information. It should be
|
|
* called in gpio interrupt handler while system is in suspend state.
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
* return 0 if getting and parsing gesture successfully,
|
|
* return 1 if gesture isn't enabled in FW,
|
|
* otherwise error code.
|
|
*****************************************************************************/
|
|
static int fts_gesture_process(void)
|
|
{
|
|
int ret = 0;
|
|
uint8_t i = 0;
|
|
uint8_t base = 0;
|
|
uint8_t regaddr = 0;
|
|
uint8_t value = 0xFF;
|
|
uint8_t buf[MAX_LEN_GESTURE_INFO] = { 0 };
|
|
uint8_t gesture_id = 0;
|
|
|
|
/*Read a byte from register 0xD0 to confirm gesture function in FW is enabled*/
|
|
ret = fts_read_reg(FTS_REG_GESTURE_EN, &value);
|
|
if ((ret < 0) || (value != FTS_REG_GESTURE_ENABLE)) {
|
|
FTS_DEBUG("gesture isn't enable in fw, don't process gesture");
|
|
return 1;
|
|
}
|
|
|
|
/*Read 26 bytes from register 0xD3 to get gesture information*/
|
|
regaddr = FTS_REG_GESTURE_OUTPUT_ADDRESS;
|
|
ret = fts_read(regaddr, buf, MAX_LEN_GESTURE_INFO);
|
|
if (ret < 0) {
|
|
FTS_DEBUG("read gesture information from reg0xD3 fails");
|
|
return ret;
|
|
}
|
|
|
|
/*get gesture_id, and the gestrue_id table provided by our technicians */
|
|
gesture_id = buf[0];
|
|
|
|
/* Now you have parsed the gesture information, you can recognise the gesture type based on gesture id.
|
|
* You can do anything you want to do, for example,
|
|
* gesture id 0x24, so the gesture type id "Double Tap", now you can inform system to wake up
|
|
* from gesture mode.
|
|
*/
|
|
|
|
/*TODO...(report gesture to system)*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* print touch buffer read from register address 0x01
|
|
*****************************************************************************/
|
|
static void log_touch_buf(uint8_t *buf, uint32_t buflen)
|
|
{
|
|
int i = 0;
|
|
int count = 0;
|
|
char tmpbuf[512] = { 0 };
|
|
|
|
for (i = 0; i < buflen; i++) {
|
|
count += snprintf(tmpbuf + count, 1024 - count, "%02X,", buf[i]);
|
|
if (count >= 1024) {
|
|
break;
|
|
}
|
|
}
|
|
FTS_DEBUG("point buffer:%s", tmpbuf);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* print touch points information of this interrupt
|
|
*****************************************************************************/
|
|
static void log_touch_info(struct fts_ts_event *events, uint8_t event_nums)
|
|
{
|
|
uint8_t i = 0;
|
|
|
|
for (i = 0; i < event_nums; i++) {
|
|
FTS_DEBUG("[%d][%d][%d,%d,%d]%d", events[i].id, events[i].type, events[i].x,
|
|
events[i].y, events[i].p, events[i].area);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_touch_process
|
|
* Brief:
|
|
* The function is used to read and parse touch points information. It should be
|
|
* called in gpio interrupt handler while system is in display(normal) state.
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
* return 0 if getting and parsing touch points successfully, otherwise error code.
|
|
*****************************************************************************/
|
|
static int fts_touch_process(void)
|
|
{
|
|
int ret = 0;
|
|
uint8_t i = 0;
|
|
uint8_t base = 0;
|
|
uint8_t regaddr = 0x01;
|
|
uint8_t buf[MAX_LEN_TOUCH_INFO];/*A maximum of two points are supported*/
|
|
uint8_t point_num = 0;
|
|
uint8_t touch_event_nums = 0;
|
|
uint8_t point_id = 0;
|
|
struct fts_ts_event events[FTS_MAX_POINTS_SUPPORT]; /* multi-touch */
|
|
|
|
|
|
/*read touch information from reg0x01*/
|
|
ret = fts_read(regaddr, buf, MAX_LEN_TOUCH_INFO);
|
|
if (ret < 0) {
|
|
FTS_DEBUG("Read touch information from reg0x01 fails");
|
|
return ret;
|
|
}
|
|
|
|
/*print touch buffer, for debug usage*/
|
|
log_touch_buf(buf, MAX_LEN_TOUCH_INFO);
|
|
|
|
if ((buf[1] == 0xFF) && (buf[2] == 0xFF) && (buf[3] == 0xFF)) {
|
|
FTS_INFO("FW initialization, need recovery");
|
|
if (fts_data->gesture_support && fts_data->suspended) {
|
|
fts_write_reg(FTS_REG_GESTURE_EN, FTS_REG_GESTURE_ENABLE);
|
|
}
|
|
}
|
|
|
|
/*parse touch information based on register map*/
|
|
memset(events, 0xFF, sizeof(struct fts_ts_event) * FTS_MAX_POINTS_SUPPORT);
|
|
point_num = buf[1] & 0x0F;
|
|
if (point_num > FTS_MAX_POINTS_SUPPORT) {
|
|
FTS_DEBUG("invalid point_num(%d)", point_num);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < MAX_POINTS_TOUCH_TRACE; i++) {
|
|
base = 2 + i * 6;
|
|
point_id = buf[base + 2] >> 4;
|
|
if (point_id >= MAX_POINTS_TOUCH_TRACE) {
|
|
break;
|
|
}
|
|
|
|
events[i].x = ((buf[base] & 0x0F) << 8) + buf[base + 1];
|
|
events[i].y = ((buf[base + 2] & 0x0F) << 8) + buf[base + 3];
|
|
events[i].id = point_id;
|
|
events[i].type = (buf[base] >> 6) & 0x03;
|
|
events[i].p = buf[base + 4];
|
|
events[i].area = buf[base + 5];
|
|
if (((events[i].type == 0) || (events[i].type == 2)) & (point_num == 0)) {
|
|
FTS_DEBUG("abnormal touch data from fw");
|
|
return -2;
|
|
}
|
|
|
|
touch_event_nums++;
|
|
}
|
|
|
|
if (touch_event_nums == 0) {
|
|
FTS_DEBUG("no touch point information(%02x)", buf[1]);
|
|
return -3;
|
|
}
|
|
|
|
/*print touch information*/
|
|
log_touch_info(events, touch_event_nums);
|
|
|
|
/*Now you have get the touch information, you can report anything(X/Y coordinates...) you want to system*/
|
|
/*TODO...(report touch information to system)*/
|
|
/*Below sample code is a pseudo code*/
|
|
for (i = 0; i < touch_event_nums; i++) {
|
|
if ((events[i].type == 0) || (events[i].type == 2)) {
|
|
/* The event of point(point id is events[i].id) is down event, the finger of this id stands for is
|
|
* pressing on the screen.*/
|
|
/*TODO...(down event)*/
|
|
#if SW_X_Y
|
|
tpd_down(events[i].y, events[i].x, events[i].y, events[i].x, 0);
|
|
#else
|
|
tpd_down(events[i].x, events[i].y, events[i].x, events[i].y, 0);
|
|
#endif
|
|
} else {
|
|
/*TODO...(up event)*/
|
|
#if SW_X_Y
|
|
tpd_up(events[i].y, events[i].x, events[i].y, events[i].x, 0);
|
|
#else
|
|
tpd_up(events[i].x, events[i].y, events[i].x, events[i].y, 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* An interrupt handler, will be called while the voltage of INT Port changes from high to low(falling-edge trigger mode).
|
|
* The program reads touch data or gesture data from TP controller, and then sends it into system.
|
|
*****************************************************************************/
|
|
static int fts_gpio_interrupt_handler(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (fts_data->gesture_support && fts_data->suspended) {
|
|
/*if gesture is enabled, interrupt handler should process gesture at first*/
|
|
ret = fts_gesture_process();
|
|
if (ret == 0) {
|
|
FTS_DEBUG("success to process gesture.");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*if gesture isn't enabled, the handler should process touch points*/
|
|
fts_touch_process();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* An interrupt handler, will be called while the timer interrupt trigger , the code based on your platform.
|
|
* The program use to check esd.
|
|
*****************************************************************************/
|
|
static void fts_timer_interrupt_handler(void)
|
|
{
|
|
/* esd check */
|
|
fts_esdcheck_process();
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_suspend
|
|
* Brief: System suspends and update the suspended state
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
* return 0 if enter suspend successfully, otherwise error code
|
|
*****************************************************************************/
|
|
int fts_ts_suspend(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (fts_data->suspended) {
|
|
FTS_INFO("Already in suspend state");
|
|
return 0;
|
|
}
|
|
|
|
if (fts_data->gesture_support) {
|
|
/*Host writes 0x01 to register address 0xD0 to enable gesture function while system suspends.*/
|
|
ret = fts_write_reg(FTS_REG_GESTURE_EN, FTS_REG_GESTURE_ENABLE);
|
|
if (ret < 0) {
|
|
FTS_ERROR("enable gesture fails.ret:%d", ret);
|
|
} else {
|
|
FTS_INFO("enable gesture success.");
|
|
}
|
|
} else {
|
|
/*Host writes 0x03 to register address 0xA5 to enter into sleep mode.*/
|
|
ret = fts_write_reg(FTS_REG_POWER_MODE, 0x03);
|
|
if (ret < 0) {
|
|
FTS_ERROR("system enter sleep mode fails.ret:%d", ret);
|
|
} else {
|
|
FTS_INFO("system enter sleep mode success.");
|
|
}
|
|
}
|
|
|
|
fts_data->suspended = 1;
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_resume
|
|
* Brief: System resume and update the suspended state
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
* return 0 if enter resume successfully, otherwise error code
|
|
*****************************************************************************/
|
|
int fts_ts_resume(void)
|
|
{
|
|
if (!fts_data->suspended) {
|
|
FTS_INFO("Already in resume state");
|
|
return 0;
|
|
}
|
|
|
|
fts_data->suspended = 0;
|
|
fts_hw_reset(200);
|
|
touch_info_reset();
|
|
return 0;
|
|
}
|
|
|
|
/* static void ctp_delay_us(unsigned int time) */
|
|
/* { */
|
|
/* udelay(time); */
|
|
/* } */
|
|
/* static void ctp_delay_ms(unsigned short time) */
|
|
/* { */
|
|
/* if (time >= 10) { */
|
|
/* os_time_dly(time / 10 + 1); */
|
|
/* } else { */
|
|
/* mdelay(time); */
|
|
/* } */
|
|
/* } */
|
|
|
|
/*------------------
|
|
* tp中断配置
|
|
* -----------------*/
|
|
static void tp_irq_callback(enum gpio_port port, u32 pin, enum gpio_irq_edge edge)
|
|
{
|
|
printf("port%d.%d:%d-cb1\n", port, pin, edge);
|
|
|
|
touch_flag = 1;
|
|
os_sem_post(&touch_sem);
|
|
}
|
|
|
|
struct gpio_irq_config_st tp_int_irq_config = {
|
|
.pin = NO_CONFIG_PORT,
|
|
.irq_edge = PORT_IRQ_EDGE_FALL,
|
|
.callback = tp_irq_callback,
|
|
.irq_priority = 3,
|
|
};
|
|
|
|
|
|
|
|
void tp_irq_init(void)
|
|
{
|
|
u8 port_x = TCFG_TP_INT_IO / IO_GROUP_NUM;
|
|
u16 port_pin_x = BIT(TCFG_TP_INT_IO % IO_GROUP_NUM);
|
|
tp_int_irq_config.pin = port_pin_x;
|
|
|
|
log_debug("[%s] port_x:%x, port_pin_x:%x", __func__, port_x, port_pin_x);
|
|
gpio_set_mode(IO_PORT_SPILT(TCFG_TP_INT_IO), PORT_INPUT_PULLUP_10K);
|
|
gpio_irq_config(port_x, &tp_int_irq_config);
|
|
}
|
|
|
|
void tp_irq_deinit(void)
|
|
{
|
|
gpio_irq_deinit(IO_PORT_SPILT(TCFG_TP_INT_IO));
|
|
gpio_set_mode(IO_PORT_SPILT(TCFG_TP_INT_IO), PORT_HIGHZ);
|
|
}
|
|
|
|
static void fts_ts_hw_init(void)
|
|
{
|
|
u8 buf[1];
|
|
u8 reg_addr[1];
|
|
int i;
|
|
int ret;
|
|
|
|
memset(&tke, 0xff, sizeof(tke));
|
|
|
|
printf("fts3x68 init...\n");
|
|
ret = system_iic_init(__this->iic_hdl, get_iic_config(__this->iic_hdl));
|
|
printf("[%s] iic_init ret:%d", __func__, ret);
|
|
|
|
platform_reset_pin_cfg();
|
|
|
|
fts_power_on();
|
|
|
|
fts_hw_reset(0);
|
|
touch_info_reset();
|
|
/* ctp_delay_ms(100); */
|
|
|
|
fts_check_id();
|
|
/* buf[0] = 0; */
|
|
/* reg_addr[0] = 0xa7; */
|
|
/* system_iic_read_nbytes(__this->iic_hdl, HYN_I2C_ADDR, ®_addr[0], 1, &buf[0], 1); */
|
|
/* printf("tp id : 0x%x\n", buf[0]); */
|
|
|
|
/* buf[0] = 0; */
|
|
/* reg_addr[0] = 0xa9; */
|
|
/* system_iic_read_nbytes(__this->iic_hdl, HYN_I2C_ADDR, ®_addr[0], 1, &buf[0], 1); */
|
|
/* printf("tp version : 0x%x\n", buf[0]); */
|
|
|
|
/* if (!fts_ts_upgrade()) { */
|
|
/* log_error("fts3x68 upgrade fail!\n"); */
|
|
/* } */
|
|
|
|
/* fts_hw_reset(2); */
|
|
}
|
|
|
|
static void touch_interupt_task(void *p)
|
|
{
|
|
int sem_timeout = 0;
|
|
|
|
fts_ts_hw_init();
|
|
os_sem_create(&touch_sem, 0);
|
|
tp_irq_init();
|
|
|
|
while (1) {
|
|
tp_step = TP_RUN_STEP_RUN_IDLE;
|
|
os_sem_pend(&touch_sem, sem_timeout);
|
|
tp_step = TP_RUN_STEP_RUN;
|
|
|
|
if (touch_flag) {
|
|
touch_flag = 0;
|
|
/* fts_read(); */
|
|
fts_touch_process();
|
|
/* fts_esdcheck_process(); */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void fts_ts_wait_init()
|
|
{
|
|
while (tp_step == TP_RUN_STEP_INIT) {
|
|
os_time_dly(1);
|
|
}
|
|
}
|
|
|
|
void fts_ts_init(void)
|
|
{
|
|
tp_step = TP_RUN_STEP_INIT;
|
|
task_create(touch_interupt_task, NULL, "touch_task");
|
|
}
|
|
|
|
void fts_ts_deinit()
|
|
{
|
|
fts_ts_wait_init();
|
|
|
|
}
|
|
|
|
static u8 tp_idle_query(void)
|
|
{
|
|
return !tp_step;
|
|
}
|
|
REGISTER_LP_TARGET(tp_lp_target) = {
|
|
.name = "tp_cst816d",
|
|
.is_idle = tp_idle_query,
|
|
};
|
|
|
|
|
|
|
|
#endif
|