1 /**
2  * @file lv_nuttx_entry.h
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_nuttx_entry.h"
10 
11 #if LV_USE_NUTTX
12 
13 #include <time.h>
14 #include <nuttx/tls.h>
15 #include <nuttx/clock.h>
16 #include <syslog.h>
17 #include <pthread.h>
18 #include "lv_nuttx_cache.h"
19 #include "lv_nuttx_image_cache.h"
20 #include "../../core/lv_global.h"
21 #include "lv_nuttx_profiler.h"
22 
23 #include "../../../lvgl.h"
24 
25 /*********************
26  *      DEFINES
27  *********************/
28 
29 #define nuttx_ctx_p (LV_GLOBAL_DEFAULT()->nuttx_ctx)
30 
31 #if (LV_USE_FREETYPE || LV_USE_THORVG)
32     #define LV_NUTTX_MIN_STACK_SIZE (32 * 1024)
33 #else
34     #define LV_NUTTX_MIN_STACK_SIZE (8 * 1024)
35 #endif
36 
37 /**********************
38  *      TYPEDEFS
39  **********************/
40 
41 /**********************
42  *  STATIC PROTOTYPES
43  **********************/
44 
45 static uint32_t millis(void);
46 #if LV_USE_LOG
47     static void syslog_print(lv_log_level_t level, const char * buf);
48 #endif
49 static void check_stack_size(void);
50 
51 #ifdef CONFIG_LV_USE_NUTTX_LIBUV
52     static void lv_nuttx_uv_loop(lv_nuttx_result_t * result);
53 #endif
54 
55 /**********************
56  *  STATIC VARIABLES
57  **********************/
58 
59 /**********************
60  *      MACROS
61  **********************/
62 
63 /**********************
64  *   GLOBAL FUNCTIONS
65  **********************/
66 
67 #if LV_ENABLE_GLOBAL_CUSTOM
68 
69 static int lv_nuttx_tlskey = -1;
70 
lv_global_free(void * data)71 static void lv_global_free(void * data)
72 {
73     if(data) {
74         free(data);
75     }
76 }
77 
lv_global_default(void)78 lv_global_t * lv_global_default(void)
79 {
80     lv_global_t * data = NULL;
81 
82     if(lv_nuttx_tlskey < 0) {
83         lv_nuttx_tlskey = task_tls_alloc(lv_global_free);
84     }
85 
86     if(lv_nuttx_tlskey >= 0) {
87         data = (lv_global_t *)task_tls_get_value(lv_nuttx_tlskey);
88         if(data == NULL) {
89             data = (lv_global_t *)calloc(1, sizeof(lv_global_t));
90             task_tls_set_value(lv_nuttx_tlskey, (uintptr_t)data);
91         }
92     }
93     return data;
94 }
95 #endif
96 
lv_nuttx_dsc_init(lv_nuttx_dsc_t * dsc)97 void lv_nuttx_dsc_init(lv_nuttx_dsc_t * dsc)
98 {
99     if(dsc == NULL)
100         return;
101 
102     lv_memzero(dsc, sizeof(lv_nuttx_dsc_t));
103     dsc->fb_path = "/dev/fb0";
104     dsc->input_path = "/dev/input0";
105 
106 #ifdef CONFIG_UINPUT_TOUCH
107     dsc->utouch_path = "/dev/utouch";
108 #endif
109 }
110 
lv_nuttx_init(const lv_nuttx_dsc_t * dsc,lv_nuttx_result_t * result)111 void lv_nuttx_init(const lv_nuttx_dsc_t * dsc, lv_nuttx_result_t * result)
112 {
113     nuttx_ctx_p = lv_malloc_zeroed(sizeof(lv_nuttx_ctx_t));
114     LV_ASSERT_MALLOC(nuttx_ctx_p);
115 
116 #if LV_USE_LOG
117     lv_log_register_print_cb(syslog_print);
118 #endif
119     lv_tick_set_cb(millis);
120 
121     check_stack_size();
122 
123     lv_nuttx_cache_init();
124 
125     lv_nuttx_image_cache_init(LV_USE_NUTTX_INDEPENDENT_IMAGE_HEAP);
126 
127 #if LV_USE_PROFILER && LV_USE_PROFILER_BUILTIN
128     lv_nuttx_profiler_init();
129 #endif
130 
131     if(result) {
132         lv_memzero(result, sizeof(lv_nuttx_result_t));
133     }
134 
135 #if !LV_USE_NUTTX_CUSTOM_INIT
136 
137     if(dsc && dsc->fb_path) {
138         lv_display_t * disp = NULL;
139 
140 #if LV_USE_NUTTX_LCD
141         disp = lv_nuttx_lcd_create(dsc->fb_path);
142 #else
143         disp = lv_nuttx_fbdev_create();
144         if(lv_nuttx_fbdev_set_file(disp, dsc->fb_path) != 0) {
145             lv_display_delete(disp);
146             disp = NULL;
147         }
148 #endif
149         if(result) {
150             result->disp = disp;
151         }
152     }
153 
154     if(dsc) {
155 #if LV_USE_NUTTX_TOUCHSCREEN
156         if(dsc->input_path) {
157             lv_indev_t * indev = lv_nuttx_touchscreen_create(dsc->input_path);
158             if(result) {
159                 result->indev = indev;
160             }
161         }
162 
163         if(dsc->utouch_path) {
164             lv_indev_t * indev = lv_nuttx_touchscreen_create(dsc->utouch_path);
165             if(result) {
166                 result->utouch_indev = indev;
167             }
168         }
169 #endif
170     }
171 
172 #else
173 
174     lv_nuttx_init_custom(dsc, result);
175 #endif
176 }
177 
lv_nuttx_run(lv_nuttx_result_t * result)178 void lv_nuttx_run(lv_nuttx_result_t * result)
179 {
180 #ifdef CONFIG_LV_USE_NUTTX_LIBUV
181     lv_nuttx_uv_loop(&ui_loop, result);
182 #else
183     while(1) {
184         uint32_t idle;
185         idle = lv_timer_handler();
186 
187         /* Minimum sleep of 1ms */
188         idle = idle ? idle : 1;
189         usleep(idle * 1000);
190     }
191 #endif
192 }
193 
194 #ifdef CONFIG_SCHED_CPULOAD
195 
lv_nuttx_get_idle(void)196 uint32_t lv_nuttx_get_idle(void)
197 {
198     struct cpuload_s cpuload;
199     int ret = clock_cpuload(0, &cpuload);
200     if(ret < 0) {
201         LV_LOG_WARN("clock_cpuload failed: %d", ret);
202         return 0;
203     }
204 
205     uint32_t idle = cpuload.active * 100 / cpuload.total;
206     LV_LOG_TRACE("active = %" LV_PRIu32 ", total = %" LV_PRIu32,
207                  cpuload.active, cpuload.total);
208 
209     return idle;
210 }
211 
212 #endif
213 
lv_nuttx_deinit(lv_nuttx_result_t * result)214 void lv_nuttx_deinit(lv_nuttx_result_t * result)
215 {
216 #if !LV_USE_NUTTX_CUSTOM_INIT
217     if(result) {
218         if(result->disp) {
219             lv_display_delete(result->disp);
220             result->disp = NULL;
221         }
222 
223         if(result->indev) {
224             lv_indev_delete(result->indev);
225             result->indev = NULL;
226         }
227 
228         if(result->utouch_indev) {
229             lv_indev_delete(result->utouch_indev);
230             result->utouch_indev = NULL;
231         }
232     }
233 #else
234     lv_nuttx_deinit_custom(result);
235 #endif
236 
237     if(nuttx_ctx_p) {
238         lv_nuttx_cache_deinit();
239         lv_nuttx_image_cache_deinit();
240 
241         lv_free(nuttx_ctx_p);
242         nuttx_ctx_p = NULL;
243     }
244 }
245 
246 /**********************
247  *   STATIC FUNCTIONS
248  **********************/
249 
millis(void)250 static uint32_t millis(void)
251 {
252     struct timespec ts;
253 
254     clock_gettime(CLOCK_MONOTONIC, &ts);
255     uint32_t tick = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
256 
257     return tick;
258 }
259 
260 #if LV_USE_LOG
syslog_print(lv_log_level_t level,const char * buf)261 static void syslog_print(lv_log_level_t level, const char * buf)
262 {
263     static const int priority[LV_LOG_LEVEL_NUM] = {
264         LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT
265     };
266 
267     syslog(priority[level], "[LVGL] %s", buf);
268 }
269 #endif
270 
271 #ifdef CONFIG_LV_USE_NUTTX_LIBUV
lv_nuttx_uv_loop(lv_nuttx_result_t * result)272 static void lv_nuttx_uv_loop(lv_nuttx_result_t * result)
273 {
274     uv_loop_t loop;
275     lv_nuttx_uv_t uv_info;
276     void * data;
277 
278     uv_loop_init(&loop);
279 
280     lv_memzero(&uv_info, sizeof(uv_info));
281     uv_info.loop = &loop;
282     uv_info.disp = result->disp;
283     uv_info.indev = result->indev;
284 #ifdef CONFIG_UINPUT_TOUCH
285     uv_info.uindev = result->utouch_indev;
286 #endif
287 
288     data = lv_nuttx_uv_init(&uv_info);
289     uv_run(loop, UV_RUN_DEFAULT);
290     lv_nuttx_uv_deinit(&data);
291 }
292 #endif
293 
check_stack_size(void)294 static void check_stack_size(void)
295 {
296     pthread_t tid = pthread_self();
297     ssize_t stack_size = pthread_get_stacksize_np(tid);
298     LV_LOG_USER("tid: %d, Stack size : %zd", (int)tid, stack_size);
299 
300     if(stack_size < LV_NUTTX_MIN_STACK_SIZE) {
301         LV_LOG_ERROR("Stack size is too small. Please increase it to %d bytes or more.",
302                      LV_NUTTX_MIN_STACK_SIZE);
303     }
304 }
305 
306 #endif /*LV_USE_NUTTX*/
307 
308