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