1 /**
2 * @file lv_nuttx_touchscreen.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "lv_nuttx_touchscreen.h"
11
12 #if LV_USE_NUTTX
13
14 #if LV_USE_NUTTX_TOUCHSCREEN
15
16 #include <sys/types.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <debug.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <nuttx/input/touchscreen.h>
24 #include "../../lvgl_private.h"
25
26 /*********************
27 * DEFINES
28 *********************/
29
30 /**********************
31 * TYPEDEFS
32 **********************/
33
34 typedef struct {
35 /* fd should be defined at the beginning */
36 int fd;
37 struct touch_sample_s last_sample;
38 bool has_last_sample;
39 lv_indev_state_t last_state;
40 lv_indev_t * indev_drv;
41 } lv_nuttx_touchscreen_t;
42
43 /**********************
44 * STATIC PROTOTYPES
45 **********************/
46 static void indev_set_cursor(lv_indev_t * indev, int32_t size);
47 static void touchscreen_read(lv_indev_t * drv, lv_indev_data_t * data);
48 static void touchscreen_delete_cb(lv_event_t * e);
49 static lv_indev_t * touchscreen_init(int fd);
50
51 /**********************
52 * STATIC VARIABLES
53 **********************/
54
55 /**********************
56 * MACROS
57 **********************/
58
59 /**********************
60 * GLOBAL FUNCTIONS
61 **********************/
62
lv_nuttx_touchscreen_create(const char * dev_path)63 lv_indev_t * lv_nuttx_touchscreen_create(const char * dev_path)
64 {
65 lv_indev_t * indev;
66 int fd;
67
68 LV_ASSERT_NULL(dev_path);
69 LV_LOG_USER("touchscreen %s opening", dev_path);
70 fd = open(dev_path, O_RDONLY | O_NONBLOCK);
71 if(fd < 0) {
72 perror("Error: cannot open touchscreen device");
73 return NULL;
74 }
75
76 LV_LOG_USER("touchscreen %s open success", dev_path);
77
78 indev = touchscreen_init(fd);
79
80 if(indev == NULL) {
81 close(fd);
82 }
83
84 indev_set_cursor(indev, LV_NUTTX_TOUCHSCREEN_CURSOR_SIZE);
85
86 return indev;
87 }
88
89 /**********************
90 * STATIC FUNCTIONS
91 **********************/
92
indev_set_cursor(lv_indev_t * indev,int32_t size)93 static void indev_set_cursor(lv_indev_t * indev, int32_t size)
94 {
95 lv_obj_t * cursor_obj = lv_indev_get_cursor(indev);
96 if(size <= 0) {
97 if(cursor_obj) {
98 lv_obj_delete(cursor_obj);
99 lv_indev_set_cursor(indev, NULL);
100 }
101 }
102 else {
103 if(cursor_obj == NULL) {
104 cursor_obj = lv_obj_create(lv_layer_sys());
105 lv_obj_remove_style_all(cursor_obj);
106 lv_obj_set_style_radius(cursor_obj, LV_RADIUS_CIRCLE, 0);
107 lv_obj_set_style_bg_opa(cursor_obj, LV_OPA_50, 0);
108 lv_obj_set_style_bg_color(cursor_obj, lv_color_black(), 0);
109 lv_obj_set_style_border_width(cursor_obj, 2, 0);
110 lv_obj_set_style_border_color(cursor_obj, lv_palette_main(LV_PALETTE_GREY), 0);
111 }
112 lv_obj_set_size(cursor_obj, size, size);
113 lv_obj_set_style_translate_x(cursor_obj, -size / 2, 0);
114 lv_obj_set_style_translate_y(cursor_obj, -size / 2, 0);
115 lv_indev_set_cursor(indev, cursor_obj);
116 }
117 }
118
conv_touch_sample(lv_indev_t * drv,lv_indev_data_t * data,struct touch_sample_s * sample)119 static void conv_touch_sample(lv_indev_t * drv,
120 lv_indev_data_t * data,
121 struct touch_sample_s * sample)
122 {
123 lv_nuttx_touchscreen_t * touchscreen = drv->driver_data;
124 uint8_t touch_flags = sample->point[0].flags;
125
126 if(touch_flags & (TOUCH_DOWN | TOUCH_MOVE)) {
127 lv_display_t * disp = lv_indev_get_display(drv);
128 int32_t hor_max = lv_display_get_horizontal_resolution(disp) - 1;
129 int32_t ver_max = lv_display_get_vertical_resolution(disp) - 1;
130
131 data->point.x = LV_CLAMP(0, sample->point[0].x, hor_max);
132 data->point.y = LV_CLAMP(0, sample->point[0].y, ver_max);
133 touchscreen->last_state = LV_INDEV_STATE_PRESSED;
134 }
135 else if(touch_flags & TOUCH_UP) {
136 touchscreen->last_state = LV_INDEV_STATE_RELEASED;
137 }
138 }
139
touchscreen_read_sample(int fd,struct touch_sample_s * sample)140 static bool touchscreen_read_sample(int fd, struct touch_sample_s * sample)
141 {
142 int nbytes = read(fd, sample, sizeof(struct touch_sample_s));
143 return nbytes == sizeof(struct touch_sample_s);
144 }
145
touchscreen_read(lv_indev_t * drv,lv_indev_data_t * data)146 static void touchscreen_read(lv_indev_t * drv, lv_indev_data_t * data)
147 {
148 lv_nuttx_touchscreen_t * touchscreen = drv->driver_data;
149 struct touch_sample_s sample;
150
151 /*
152 * Note: Since it is necessary to avoid multi-processing click events
153 * caused by redundant continue_reading, a two-unit sample sliding window
154 * algorithm is used here. continue_reading is only activated when there
155 * are two points in the window.
156 */
157
158 /* If has last sample, use it first */
159 if(touchscreen->has_last_sample) {
160 conv_touch_sample(drv, data, &touchscreen->last_sample);
161 }
162 else {
163 /* Read first sample */
164 if(!touchscreen_read_sample(touchscreen->fd, &sample)) {
165 /* No sample available, return last state */
166 data->state = touchscreen->last_state;
167 return;
168 }
169
170 conv_touch_sample(drv, data, &sample);
171 }
172
173 /* Try to read next sample */
174 if(touchscreen_read_sample(touchscreen->fd, &sample)) {
175 /* Save last sample and let lvgl continue reading */
176 touchscreen->last_sample = sample;
177 touchscreen->has_last_sample = true;
178 data->continue_reading = true;
179 }
180 else {
181 /* No more sample available, clear last sample flag */
182 touchscreen->has_last_sample = false;
183 }
184
185 data->state = touchscreen->last_state;
186 }
187
touchscreen_delete_cb(lv_event_t * e)188 static void touchscreen_delete_cb(lv_event_t * e)
189 {
190 lv_indev_t * indev = (lv_indev_t *) lv_event_get_user_data(e);
191 lv_nuttx_touchscreen_t * touchscreen = lv_indev_get_driver_data(indev);
192 if(touchscreen) {
193 lv_indev_set_driver_data(indev, NULL);
194 lv_indev_set_read_cb(indev, NULL);
195 indev_set_cursor(indev, -1);
196 if(touchscreen->fd >= 0) {
197 close(touchscreen->fd);
198 touchscreen->fd = -1;
199 }
200 lv_free(touchscreen);
201 LV_LOG_USER("done");
202 }
203 }
204
touchscreen_init(int fd)205 static lv_indev_t * touchscreen_init(int fd)
206 {
207 lv_nuttx_touchscreen_t * touchscreen;
208 lv_indev_t * indev = NULL;
209
210 touchscreen = lv_malloc_zeroed(sizeof(lv_nuttx_touchscreen_t));
211 if(touchscreen == NULL) {
212 LV_LOG_ERROR("touchscreen_s malloc failed");
213 return NULL;
214 }
215
216 touchscreen->fd = fd;
217 touchscreen->last_state = LV_INDEV_STATE_RELEASED;
218 touchscreen->indev_drv = indev = lv_indev_create();
219
220 lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
221 lv_indev_set_read_cb(indev, touchscreen_read);
222 lv_indev_set_driver_data(indev, touchscreen);
223 lv_indev_add_event_cb(indev, touchscreen_delete_cb, LV_EVENT_DELETE, indev);
224 return indev;
225 }
226
227 #endif /*LV_USE_NUTTX_TOUCHSCREEN*/
228
229 #endif /* LV_USE_NUTTX*/
230