1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2017-08-08     Yang        the first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <finsh.h>
14 
15 #ifdef RT_USING_RTGUI
16 #include <rtgui/event.h>
17 #include <rtgui/rtgui_server.h>
18 #endif
19 
20 #include "board.h"
21 
22 #include "fsl_iocon.h"
23 #include "fsl_gpio.h"
24 #include "fsl_i2c.h"
25 #include "fsl_gint.h"
26 
27 #define LCD_WIDTH               480
28 #define LCD_HEIGHT              272
29 #define BSP_TOUCH_SAMPLE_HZ     30
30 
31 #define I2CBUS_NAME  "i2c2"
32 
33 #if 0
34 #define FTDEBUG      rt_kprintf
35 #else
36 #define FTDEBUG(...)
37 #endif
38 
39 #define TOUCH_SLP_TIME          (RT_TICK_PER_SECOND * 5)
40 
41 #define FT5206_TS_ADDR          0x38
42 #define TP_MAX_TOUCH_POINT      2
43 
44 enum ft5x0x_ts_regs
45 {
46     FT5X0X_REG_THGROUP                  = 0x80,
47     FT5X0X_REG_THPEAK                   = 0x81,
48     FT5X0X_REG_THCAL                    = 0x82,
49     FT5X0X_REG_THWATER                  = 0x83,
50     FT5X0X_REG_THTEMP                   = 0x84,
51     FT5X0X_REG_THDIFF                   = 0x85,
52     FT5X0X_REG_CTRL                     = 0x86,
53     FT5X0X_REG_TIMEENTERMONITOR         = 0x87,
54     FT5X0X_REG_PERIODACTIVE             = 0x88,
55     FT5X0X_REG_PERIODMONITOR            = 0x89,
56     FT5X0X_REG_HEIGHT_B                 = 0x8a,
57     FT5X0X_REG_MAX_FRAME                = 0x8b,
58     FT5X0X_REG_DIST_MOVE                = 0x8c,
59     FT5X0X_REG_DIST_POINT               = 0x8d,
60     FT5X0X_REG_FEG_FRAME                = 0x8e,
61     FT5X0X_REG_SINGLE_CLICK_OFFSET      = 0x8f,
62     FT5X0X_REG_DOUBLE_CLICK_TIME_MIN    = 0x90,
63     FT5X0X_REG_SINGLE_CLICK_TIME        = 0x91,
64     FT5X0X_REG_LEFT_RIGHT_OFFSET        = 0x92,
65     FT5X0X_REG_UP_DOWN_OFFSET           = 0x93,
66     FT5X0X_REG_DISTANCE_LEFT_RIGHT      = 0x94,
67     FT5X0X_REG_DISTANCE_UP_DOWN         = 0x95,
68     FT5X0X_REG_ZOOM_DIS_SQR             = 0x96,
69     FT5X0X_REG_RADIAN_VALUE             = 0x97,
70     FT5X0X_REG_MAX_X_HIGH               = 0x98,
71     FT5X0X_REG_MAX_X_LOW                = 0x99,
72     FT5X0X_REG_MAX_Y_HIGH               = 0x9a,
73     FT5X0X_REG_MAX_Y_LOW                = 0x9b,
74     FT5X0X_REG_K_X_HIGH                 = 0x9c,
75     FT5X0X_REG_K_X_LOW                  = 0x9d,
76     FT5X0X_REG_K_Y_HIGH                 = 0x9e,
77     FT5X0X_REG_K_Y_LOW                  = 0x9f,
78     FT5X0X_REG_AUTO_CLB_MODE            = 0xa0,
79     FT5X0X_REG_LIB_VERSION_H            = 0xa1,
80     FT5X0X_REG_LIB_VERSION_L            = 0xa2,
81     FT5X0X_REG_CIPHER                   = 0xa3,
82     FT5X0X_REG_G_MODE                   = 0xa4,
83     FT5X0X_REG_PMODE                    = 0xa5, /* Power Consume Mode */
84     FT5X0X_REG_FIRMID                   = 0xa6,
85     FT5X0X_REG_STATE                    = 0xa7,
86     FT5X0X_REG_VENDID                   = 0xa8,
87     FT5X0X_REG_ERR                      = 0xa9,
88     FT5X0X_REG_CLB                      = 0xaa,
89 };
90 
91 #define CTRL_NOAUTO_MONITOR    0x00
92 #define CTRL_AUTO_MONITOR      0x01
93 
94 #define PMODE_ACTIVE           0x00
95 #define PMODE_MONITOR          0x01
96 #define PMODE_STANDBY          0x02
97 #define PMODE_HIBERNATE        0x03
98 
99 #define G_MODE_POLLING         0x00
100 #define G_MODE_TRIGGER         0x01
101 
102 typedef enum _touch_event
103 {
104     kTouch_Down = 0,    /*!< The state changed to touched. */
105     kTouch_Up = 1,      /*!< The state changed to not touched. */
106     kTouch_Contact = 2, /*!< There is a continuous touch being detected. */
107     kTouch_Reserved = 3 /*!< No touch information available. */
108 } touch_event_t;
109 
110 typedef struct _touch_point
111 {
112     touch_event_t TOUCH_EVENT; /*!< Indicates the state or event of the touch point. */
113     uint8_t TOUCH_ID; /*!< Id of the touch point. This numeric value stays constant between down and up event. */
114     uint16_t TOUCH_X; /*!< X coordinate of the touch point */
115     uint16_t TOUCH_Y; /*!< Y coordinate of the touch point */
116 } touch_point_t;
117 
118 typedef struct _ft5406_touch_point
119 {
120     uint8_t XH;
121     uint8_t XL;
122     uint8_t YH;
123     uint8_t YL;
124     uint8_t RESERVED[2];
125 } ft5406_touch_point_t;
126 
127 typedef struct _ft5406_touch_data
128 {
129     uint8_t GEST_ID;
130     uint8_t TD_STATUS;
131     ft5406_touch_point_t TOUCH;
132 } ft5406_touch_data_t;
133 
134 #define TOUCH_POINT_GET_EVENT(T) ((touch_event_t)((T).XH >> 6))
135 #define TOUCH_POINT_GET_ID(T) ((T).YH >> 4)
136 #define TOUCH_POINT_GET_X(T) ((((T).XH & 0x0f) << 8) | (T).XL)
137 #define TOUCH_POINT_GET_Y(T) ((((T).YH & 0x0f) << 8) | (T).YL)
138 
139 static struct rt_i2c_bus_device *_i2c_bus;
140 static struct rt_semaphore _tp_sem;
141 
_ft5406_read(unsigned char cmd,void * buf,size_t len)142 static int _ft5406_read(unsigned char cmd,
143                         void *buf,
144                         size_t len)
145 {
146     struct rt_i2c_msg msgs[2];
147 
148     msgs[0].addr  = FT5206_TS_ADDR;
149     msgs[0].flags = RT_I2C_WR;
150     msgs[0].buf   = &cmd;
151     msgs[0].len   = sizeof(cmd);
152 
153     msgs[1].addr  = FT5206_TS_ADDR;
154     msgs[1].flags = RT_I2C_RD;
155     msgs[1].buf   = buf;
156     msgs[1].len   = len;
157 
158     if (rt_i2c_transfer(_i2c_bus, msgs, 2) == 2)
159         return len;
160     else
161         return -1;
162 }
163 
ft5406_read_touch(touch_point_t * dp)164 static int ft5406_read_touch(touch_point_t *dp)
165 {
166     ft5406_touch_data_t touch_data;
167 
168     _ft5406_read(0, &touch_data, sizeof(ft5406_touch_data_t));
169 
170     dp->TOUCH_X = TOUCH_POINT_GET_Y(touch_data.TOUCH);
171     dp->TOUCH_Y = TOUCH_POINT_GET_X(touch_data.TOUCH);
172 
173     FTDEBUG(" ==> status : %d (%d, %d)\n", touch_data.TD_STATUS, dp->TOUCH_X, dp->TOUCH_Y);
174 
175     if (touch_data.TD_STATUS != 0)
176         return 0;
177     else
178         return -1;
179 }
180 
_touch_session()181 static void _touch_session()
182 {
183     touch_point_t tpd;
184 #ifdef RT_USING_RTGUI
185     struct rtgui_event_mouse emouse;
186 #endif
187 
188     ft5406_read_touch(&tpd);
189 
190 #ifdef RT_USING_RTGUI
191     emouse.parent.sender = RT_NULL;
192     emouse.wid = RT_NULL;
193 
194     emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
195     emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
196     emouse.x = tpd.TOUCH_X;
197     emouse.y = tpd.TOUCH_Y;
198     emouse.ts = rt_tick_get();
199     emouse.id = emouse.ts;
200     if (emouse.id == 0) emouse.id = 1;
201     rtgui_server_post_event(&emouse.parent, sizeof(emouse));
202 #endif
203 
204     do
205     {
206         rt_thread_delay(RT_TICK_PER_SECOND / BSP_TOUCH_SAMPLE_HZ);
207         if (ft5406_read_touch(&tpd) != 0)
208             break;
209 
210 #ifdef RT_USING_RTGUI
211         emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION;
212         emouse.x = tpd.TOUCH_X;
213         emouse.y = tpd.TOUCH_Y;
214         emouse.ts = rt_tick_get();
215         rtgui_server_post_event(&emouse.parent, sizeof(emouse));
216 #endif
217     }
218     while (1);
219 
220 #ifdef RT_USING_RTGUI
221     /* Always send touch up event. */
222     emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
223     emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP;
224     emouse.x = tpd.TOUCH_X;
225     emouse.y = tpd.TOUCH_Y;
226     emouse.ts = rt_tick_get();
227     rtgui_server_post_event(&emouse.parent, sizeof(emouse));
228 #endif
229 
230     //} while (rt_sem_take(&_tp_sem, TOUCH_SLP_TIME) == RT_EOK);
231 }
232 
touch_down(void)233 void touch_down(void)
234 {
235     rt_sem_release(&_tp_sem);
236 }
237 
_touch(void * p)238 static void _touch(void *p)
239 {
240     int io_s;
241 
242     gpio_pin_config_t pin_config =
243     {
244         kGPIO_DigitalInput, 0,
245     };
246 
247     CLOCK_EnableClock(kCLOCK_Gpio4);
248 
249     /* Enable touch panel controller */
250     GPIO_PinInit(GPIO, 4, 0, &pin_config);
251 
252     while(1)
253     {
254         rt_thread_delay(RT_TICK_PER_SECOND / 60);
255 
256         io_s = GPIO_ReadPinInput(GPIO, 4, 0);
257         if (io_s == 0)
258         {
259             _touch_session();
260         }
261         else
262             continue;
263     }
264 }
265 
ft5406_hw_init(void)266 int ft5406_hw_init(void)
267 {
268     rt_thread_t tid;
269     rt_device_t dev;
270 
271     dev = rt_device_find(I2CBUS_NAME);
272     if (!dev) return -1;
273 
274     if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
275         return -1;
276 
277     FTDEBUG("ft5406 set i2c bus to %s\n", I2CBUS_NAME);
278     _i2c_bus = (struct rt_i2c_bus_device *)dev;
279 
280     {
281         gpio_pin_config_t pin_config =
282         {
283             kGPIO_DigitalOutput, 0,
284         };
285 
286         CLOCK_EnableClock(kCLOCK_Gpio2);
287 
288         /* Enable touch panel controller */
289         GPIO_PinInit(GPIO, 2, 27, &pin_config);
290         GPIO_WritePinOutput(GPIO, 2, 27, 1);
291         rt_thread_delay(50);
292         GPIO_WritePinOutput(GPIO, 2, 27, 0);
293         rt_thread_delay(50);
294         GPIO_WritePinOutput(GPIO, 2, 27, 1);
295     }
296 
297     rt_sem_init(&_tp_sem, "touch", 0, RT_IPC_FLAG_FIFO);
298     tid = rt_thread_create("touch", _touch, RT_NULL,
299                            2048, 10, 20);
300     if (!tid)
301     {
302         rt_device_close(dev);
303         return -1;
304     }
305 
306     rt_thread_startup(tid);
307 
308     return 0;
309 }
310 INIT_APP_EXPORT(ft5406_hw_init);
311