1 /**
2 * @file lv_nuttx_libuv.c
3 */
4
5 /*********************
6 * INCLUDES
7 *********************/
8 #include "lv_nuttx_libuv.h"
9
10 #include "../../lvgl.h"
11 #include "../../lvgl_private.h"
12
13 #if LV_USE_NUTTX
14 #include <stdlib.h>
15
16 #if LV_USE_NUTTX_LIBUV
17 #include <uv.h>
18
19 /*********************
20 * DEFINES
21 *********************/
22
23 /**********************
24 * TYPEDEFS
25 **********************/
26
27 typedef struct {
28 int fd;
29 bool polling;
30 uv_poll_t fb_poll;
31 uv_poll_t vsync_poll;
32 } lv_nuttx_uv_fb_ctx_t;
33
34 typedef struct {
35 int fd;
36 uv_poll_t input_poll;
37 lv_indev_t * indev;
38 } lv_nuttx_uv_input_ctx_t;
39
40 typedef struct {
41 uv_timer_t uv_timer;
42 lv_nuttx_uv_fb_ctx_t fb_ctx;
43 lv_nuttx_uv_input_ctx_t input_ctx;
44 int32_t ref_count;
45 } lv_nuttx_uv_ctx_t;
46
47 /**********************
48 * STATIC PROTOTYPES
49 **********************/
50
51 static void lv_nuttx_uv_timer_cb(uv_timer_t * handle);
52 static int lv_nuttx_uv_timer_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx);
53 static void lv_nuttx_uv_timer_deinit(lv_nuttx_uv_ctx_t * uv_ctx);
54
55 static void lv_nuttx_uv_vsync_poll_cb(uv_poll_t * handle, int status, int events);
56 static void lv_nuttx_uv_disp_poll_cb(uv_poll_t * handle, int status, int events);
57 static void lv_nuttx_uv_disp_refr_req_cb(lv_event_t * e);
58 static int lv_nuttx_uv_fb_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx);
59 static void lv_nuttx_uv_fb_deinit(lv_nuttx_uv_ctx_t * uv_ctx);
60
61 static void lv_nuttx_uv_input_poll_cb(uv_poll_t * handle, int status, int events);
62 static int lv_nuttx_uv_input_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx);
63 static void lv_nuttx_uv_input_deinit(lv_nuttx_uv_ctx_t * uv_ctx);
64
65 /**********************
66 * STATIC VARIABLES
67 **********************/
68
69 /**********************
70 * MACROS
71 **********************/
72
73 /**********************
74 * GLOBAL FUNCTIONS
75 **********************/
76
lv_nuttx_uv_init(lv_nuttx_uv_t * uv_info)77 void * lv_nuttx_uv_init(lv_nuttx_uv_t * uv_info)
78 {
79 lv_nuttx_uv_ctx_t * uv_ctx;
80 int ret;
81
82 uv_ctx = lv_malloc_zeroed(sizeof(lv_nuttx_uv_ctx_t));
83 LV_ASSERT_MALLOC(uv_ctx);
84 if(uv_ctx == NULL) return NULL;
85
86 if((ret = lv_nuttx_uv_timer_init(uv_info, uv_ctx)) < 0) {
87 LV_LOG_ERROR("lv_nuttx_uv_timer_init fail : %d", ret);
88 goto err_out;
89 }
90
91 if((ret = lv_nuttx_uv_fb_init(uv_info, uv_ctx)) < 0) {
92 LV_LOG_ERROR("lv_nuttx_uv_fb_init fail : %d", ret);
93 goto err_out;
94 }
95
96 if((ret = lv_nuttx_uv_input_init(uv_info, uv_ctx)) < 0) {
97 LV_LOG_ERROR("lv_nuttx_uv_input_init fail : %d", ret);
98 goto err_out;
99 }
100
101 return uv_ctx;
102
103 err_out:
104 lv_free(uv_ctx);
105 return NULL;
106 }
107
lv_nuttx_uv_deinit(void ** data)108 void lv_nuttx_uv_deinit(void ** data)
109 {
110 lv_nuttx_uv_ctx_t * uv_ctx = *data;
111
112 if(uv_ctx == NULL) return;
113 lv_nuttx_uv_input_deinit(uv_ctx);
114 lv_nuttx_uv_fb_deinit(uv_ctx);
115 lv_nuttx_uv_timer_deinit(uv_ctx);
116 *data = NULL;
117 LV_LOG_USER("Done");
118 }
119
120 /**********************
121 * STATIC FUNCTIONS
122 **********************/
123
lv_nuttx_uv_timer_cb(uv_timer_t * handle)124 static void lv_nuttx_uv_timer_cb(uv_timer_t * handle)
125 {
126 uint32_t sleep_ms;
127
128 sleep_ms = lv_timer_handler();
129
130 if(sleep_ms == LV_NO_TIMER_READY) {
131 uv_timer_stop(handle);
132 return;
133 }
134
135 /* Prevent busy loops. */
136
137 if(sleep_ms == 0) {
138 sleep_ms = 1;
139 }
140
141 LV_LOG_TRACE("sleep_ms = %" LV_PRIu32, sleep_ms);
142 uv_timer_start(handle, lv_nuttx_uv_timer_cb, sleep_ms, 0);
143 }
144
lv_nuttx_uv_timer_resume(void * data)145 static void lv_nuttx_uv_timer_resume(void * data)
146 {
147 uv_timer_t * timer = (uv_timer_t *)data;
148 if(timer)
149 uv_timer_start(timer, lv_nuttx_uv_timer_cb, 0, 0);
150 }
151
lv_nuttx_uv_timer_init(lv_nuttx_uv_t * uv_info,lv_nuttx_uv_ctx_t * uv_ctx)152 static int lv_nuttx_uv_timer_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx)
153 {
154 uv_loop_t * loop = uv_info->loop;
155
156 LV_ASSERT_NULL(uv_ctx);
157 LV_ASSERT_NULL(loop);
158
159 uv_ctx->uv_timer.data = uv_ctx;
160 uv_timer_init(loop, &uv_ctx->uv_timer);
161 uv_ctx->ref_count++;
162 uv_timer_start(&uv_ctx->uv_timer, lv_nuttx_uv_timer_cb, 1, 1);
163
164 lv_timer_handler_set_resume_cb(lv_nuttx_uv_timer_resume, &uv_ctx->uv_timer);
165 return 0;
166 }
167
lv_nuttx_uv_deinit_cb(uv_handle_t * handle)168 static void lv_nuttx_uv_deinit_cb(uv_handle_t * handle)
169 {
170 lv_nuttx_uv_ctx_t * uv_ctx = handle->data;
171 if(--uv_ctx->ref_count <= 0) {
172 LV_LOG_USER("Done");
173 lv_free(uv_ctx);
174 }
175 }
176
lv_nuttx_uv_timer_deinit(lv_nuttx_uv_ctx_t * uv_ctx)177 static void lv_nuttx_uv_timer_deinit(lv_nuttx_uv_ctx_t * uv_ctx)
178 {
179 lv_timer_handler_set_resume_cb(NULL, NULL);
180 uv_close((uv_handle_t *)&uv_ctx->uv_timer, lv_nuttx_uv_deinit_cb);
181 LV_LOG_USER("Done");
182 }
183
lv_nuttx_uv_vsync_poll_cb(uv_poll_t * handle,int status,int events)184 static void lv_nuttx_uv_vsync_poll_cb(uv_poll_t * handle, int status, int events)
185 {
186 LV_UNUSED(handle);
187 LV_UNUSED(status);
188 LV_UNUSED(events);
189
190 lv_display_t * d;
191 d = lv_display_get_next(NULL);
192 while(d) {
193 lv_display_send_event(d, LV_EVENT_VSYNC, NULL);
194 d = lv_display_get_next(d);
195 }
196 }
197
lv_nuttx_uv_disp_poll_cb(uv_poll_t * handle,int status,int events)198 static void lv_nuttx_uv_disp_poll_cb(uv_poll_t * handle, int status, int events)
199 {
200 lv_nuttx_uv_fb_ctx_t * fb_ctx = &((lv_nuttx_uv_ctx_t *)(handle->data))->fb_ctx;
201
202 LV_UNUSED(status);
203 LV_UNUSED(events);
204 uv_poll_stop(handle);
205 lv_display_refr_timer(NULL);
206 fb_ctx->polling = false;
207 }
208
lv_nuttx_uv_disp_refr_req_cb(lv_event_t * e)209 static void lv_nuttx_uv_disp_refr_req_cb(lv_event_t * e)
210 {
211 lv_nuttx_uv_fb_ctx_t * fb_ctx = lv_event_get_user_data(e);
212
213 if(fb_ctx->polling) {
214 return;
215 }
216 fb_ctx->polling = true;
217 uv_poll_start(&fb_ctx->fb_poll, UV_WRITABLE, lv_nuttx_uv_disp_poll_cb);
218 }
219
lv_nuttx_uv_fb_init(lv_nuttx_uv_t * uv_info,lv_nuttx_uv_ctx_t * uv_ctx)220 static int lv_nuttx_uv_fb_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx)
221 {
222 uv_loop_t * loop = uv_info->loop;
223 lv_display_t * disp = uv_info->disp;
224
225 LV_ASSERT_NULL(uv_ctx);
226 LV_ASSERT_NULL(disp);
227 LV_ASSERT_NULL(loop);
228
229 lv_nuttx_uv_fb_ctx_t * fb_ctx = &uv_ctx->fb_ctx;
230 fb_ctx->fd = *(int *)lv_display_get_driver_data(disp);
231
232 if(fb_ctx->fd <= 0) {
233 LV_LOG_USER("skip uv fb init.");
234 return 0;
235 }
236
237 if(!disp->refr_timer) {
238 LV_LOG_ERROR("disp->refr_timer is NULL");
239 return -EINVAL;
240 }
241
242 /* Remove default refr timer. */
243
244 lv_timer_delete(disp->refr_timer);
245 disp->refr_timer = NULL;
246
247 fb_ctx->fb_poll.data = uv_ctx;
248 uv_poll_init(loop, &fb_ctx->fb_poll, fb_ctx->fd);
249 uv_ctx->ref_count++;
250 uv_poll_start(&fb_ctx->fb_poll, UV_WRITABLE, lv_nuttx_uv_disp_poll_cb);
251
252 fb_ctx->vsync_poll.data = uv_ctx;
253 uv_poll_init(loop, &fb_ctx->vsync_poll, fb_ctx->fd);
254 uv_ctx->ref_count++;
255 uv_poll_start(&fb_ctx->vsync_poll, UV_PRIORITIZED, lv_nuttx_uv_vsync_poll_cb);
256
257 LV_LOG_USER("lvgl fb loop start OK");
258
259 /* Register for the invalidate area event */
260
261 lv_event_add(&disp->event_list, lv_nuttx_uv_disp_refr_req_cb, LV_EVENT_REFR_REQUEST, fb_ctx);
262
263 return 0;
264 }
265
lv_nuttx_uv_fb_deinit(lv_nuttx_uv_ctx_t * uv_ctx)266 static void lv_nuttx_uv_fb_deinit(lv_nuttx_uv_ctx_t * uv_ctx)
267 {
268 /* should remove event */
269 lv_nuttx_uv_fb_ctx_t * fb_ctx = &uv_ctx->fb_ctx;
270 if(fb_ctx->fd > 0) {
271 uv_close((uv_handle_t *)&fb_ctx->fb_poll, lv_nuttx_uv_deinit_cb);
272 uv_close((uv_handle_t *)&fb_ctx->vsync_poll, lv_nuttx_uv_deinit_cb);
273 }
274 LV_LOG_USER("Done");
275 }
276
lv_nuttx_uv_input_poll_cb(uv_poll_t * handle,int status,int events)277 static void lv_nuttx_uv_input_poll_cb(uv_poll_t * handle, int status, int events)
278 {
279 lv_indev_t * indev = ((lv_nuttx_uv_ctx_t *)(handle->data))->input_ctx.indev;
280
281 if(status < 0) {
282 LV_LOG_WARN("input poll error: %s ", uv_strerror(status));
283 return;
284 }
285
286 if(events & UV_READABLE) {
287 lv_indev_read(indev);
288 }
289 }
290
lv_nuttx_uv_input_init(lv_nuttx_uv_t * uv_info,lv_nuttx_uv_ctx_t * uv_ctx)291 static int lv_nuttx_uv_input_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx)
292 {
293 uv_loop_t * loop = uv_info->loop;
294 lv_indev_t * indev = uv_info->indev;
295
296 if(indev == NULL) {
297 LV_LOG_USER("skip uv input init.");
298 return 0;
299 }
300
301 LV_ASSERT_NULL(uv_ctx);
302 LV_ASSERT_NULL(loop);
303
304 if(lv_indev_get_mode(indev) == LV_INDEV_MODE_EVENT) {
305 LV_LOG_ERROR("input device has been running in event-driven mode");
306 return -EINVAL;
307 }
308
309 lv_nuttx_uv_input_ctx_t * input_ctx = &uv_ctx->input_ctx;
310 input_ctx->fd = *(int *)lv_indev_get_driver_data(indev);
311 if(input_ctx->fd <= 0) {
312 LV_LOG_ERROR("can't get valid input fd");
313 return 0;
314 }
315
316 input_ctx->indev = indev;
317 lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT);
318
319 input_ctx->input_poll.data = uv_ctx;
320 uv_poll_init(loop, &input_ctx->input_poll, input_ctx->fd);
321 uv_ctx->ref_count++;
322 uv_poll_start(&input_ctx->input_poll, UV_READABLE, lv_nuttx_uv_input_poll_cb);
323
324 LV_LOG_USER("lvgl input loop start OK");
325
326 return 0;
327 }
328
lv_nuttx_uv_input_deinit(lv_nuttx_uv_ctx_t * uv_ctx)329 static void lv_nuttx_uv_input_deinit(lv_nuttx_uv_ctx_t * uv_ctx)
330 {
331 lv_nuttx_uv_input_ctx_t * input_ctx = &uv_ctx->input_ctx;
332 if(input_ctx->fd > 0) {
333 uv_close((uv_handle_t *)&input_ctx->input_poll, lv_nuttx_uv_deinit_cb);
334 }
335 LV_LOG_USER("Done");
336 }
337
338 #endif /*LV_USE_NUTTX_LIBUV*/
339
340 #endif /*LV_USE_NUTTX*/
341