1
2 /*
3 * Copyright (c) 2006-2021, RT-Thread Development Team
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date Author Notes
9 * 2020-11-09 bigmagic first version
10 */
11
12 #include "lcd_console.h"
13 #include "lcd_font_20.h"
14
15 #define LCD_CONSOLE_FLUSH_NOW 1
16
17 #define CONSOLE_NAME "hdmi"
18 #define COLOR_DELTA 0.05
19
20 #ifndef LCD_CONSOLE_FLUSH_NOW
21 static rt_thread_t console_flush_thread_tid = RT_NULL;
22 #define CONSOLE_FLUSH_THREAD_STACK_SIZE (1024)
23 #define CONSOLE_FLUSH_THREAD_PRIORITY (20)
24 #define CONSOLE_FLUSH_THREAD_TIMESLICE (10)
25 #define LCD_CONSOLE_DELAY (100) //100ms
26 #endif
27
28 static rt_device_t console_dev = RT_NULL;
29
30 static fb_t console_fb;
31 static rt_uint8_t* virt_buffer;
32
33 static rt_uint32_t CHAR_W = 8;
34 static rt_uint32_t CHAR_H = 20;
35
36 static int prev_x_offset = 0;
37
newline(fb_t * fb)38 static void newline(fb_t* fb)
39 {
40 uint8_t* to;
41 uint8_t* from;
42 int i;
43 fb->y++;
44 fb->x = 5 * fb->depth;
45
46 if (fb->y == (fb->height / CHAR_H))
47 {
48 to = (uint8_t*) fb->vaddr;
49 from = to + (CHAR_H * fb->pitch);
50
51 for (i = 0; i < ((fb->height - CHAR_H) * fb->pitch); i++)
52 {
53 *to++ = *from++;
54 }
55
56 if(fb->depth >= 3)
57 {
58 uint32_t *addr_32bit = (uint32_t*) (fb->vaddr) + (fb->height - CHAR_H) * fb->width;
59
60 for (i = 0; i < (CHAR_H * fb->width); i++)
61 {
62 *addr_32bit++ = fb->back;
63 }
64 }
65 else
66 {
67 uint16_t *addr_16bit = (uint16_t*) (fb->vaddr) + (fb->height - CHAR_H) * fb->width;
68
69 for (i = 0; i < (CHAR_H * fb->width); i++)
70 {
71 *addr_16bit++ = fb->back;
72 }
73 }
74 fb->y = fb->y - 1;
75 }
76 }
77
78
fb_draw_char(fb_t * fb,char s)79 static void fb_draw_char(fb_t *fb, char s)
80 {
81 unsigned char* addr = (unsigned char*) fb->vaddr;
82 unsigned char *glyph = (unsigned char *)lcd_console_font_dejavu_20_glyph_bitmap + lcd_console_font_dejavu_20_glyph_dsc[s - 32].glyph_index;
83 CHAR_W = lcd_console_font_dejavu_20_glyph_dsc[s - 32].w_px;
84
85 fb->x = fb->x + prev_x_offset * fb->depth;
86
87 int i, j, line, mask, bytesperline = (CHAR_W + 7) / 8;
88 int kk = (bytesperline) * 8;
89 prev_x_offset = CHAR_W + 2;
90 // calculate the offset on screen
91 int offs = (fb->y * CHAR_H * fb->pitch) + fb->x;
92
93 // display a character
94 for (j = 0; j < CHAR_H; j++)
95 {
96 // display one row
97 line = offs;
98 mask = 1;
99 mask = 0x80;
100 for (i = 0; i < kk; i++)
101 {
102 if(fb->depth >= 3)
103 {
104 *((unsigned int*) (addr + line)) = ((int) *(glyph + ((i)/8)) * 1) & mask ? fb->fore : fb->back;
105 }
106 else
107 {
108 *((unsigned short*) (addr + line)) = ((int) *(glyph + ((i)/8)) * 1) & mask ? fb->fore : fb->back;
109 }
110
111 mask >>= 1;
112 if(mask == 0)
113 {
114 mask = 0x80;
115 }
116 line += fb->depth;
117 }
118 // adjust to next line
119 glyph += bytesperline;
120 offs += fb->pitch;
121 }
122 }
123
fb_print(char * s)124 void fb_print(char *s)
125 {
126 fb_t *fb = &console_fb;
127 // draw next character if it's not zero
128 while (*s)
129 {
130 // handle carrige return
131 if (*s == '\r')
132 {
133 fb->x = 5 * fb->depth;
134 }
135 else if (*s == '\n')
136 {
137 newline(fb);
138 }
139 else if (*s == '\t')
140 {
141 //tab is 8 spaces
142 if((fb->x + 8 * fb->depth) < (fb->width) * fb->depth)
143 {
144 fb->x = fb->x + 8 * fb->depth;
145 }
146 }
147 else if (*s == '\b')
148 {
149 if (fb->x > 5 * fb->depth)
150 {
151 fb->x = fb->x - prev_x_offset * fb->depth;
152 fb_draw_char(fb, ' ');
153 }
154 }
155 else if((fb->x + prev_x_offset * fb->depth + 5 * fb->depth) >= (fb->width * fb->depth))
156 {
157 newline(fb);
158 fb_draw_char(fb, *s);
159 }
160 else
161 {
162 fb_draw_char(fb, *s);
163 }
164 s++;
165 }
166
167 #ifdef LCD_CONSOLE_FLUSH_NOW
168 rt_memcpy((void *)fb->paddr, (void *)fb->vaddr, fb->size);
169 if(console_dev != RT_NULL)
170 {
171 rt_device_control(console_dev,RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
172 }
173 #endif
174 }
175
176 #ifndef LCD_CONSOLE_FLUSH_NOW
lcd_console_task_entry(void * param)177 void lcd_console_task_entry(void *param)
178 {
179 fb_t *fb = (fb_t *)param;
180 while (1)
181 {
182 rt_memcpy((void *)fb->paddr, (void *)fb->vaddr, fb->size);
183 if(console_dev != RT_NULL)
184 {
185 rt_device_control(console_dev,RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
186 }
187 rt_thread_mdelay(LCD_CONSOLE_DELAY);
188 }
189
190 }
191 #endif
192
lcd_console_init(void)193 int lcd_console_init(void)
194 {
195 struct rt_device_graphic_info info;
196 console_dev = rt_device_find(CONSOLE_NAME);
197 if(console_dev == RT_NULL)
198 {
199 rt_kprintf("no console dev!\n");
200 return 0;
201 }
202
203 if(console_dev->ref_count >= 1)
204 {
205 rt_kprintf("lcd console has open!\n");
206 return 0;
207 }
208
209 rt_device_open(console_dev,RT_DEVICE_OFLAG_RDWR);
210
211 rt_device_control(console_dev, RTGRAPHIC_CTRL_GET_INFO, &info);
212
213 virt_buffer = (rt_uint8_t* )rt_malloc(info.width * info.height * (info.bits_per_pixel/8));
214 rt_memset(virt_buffer, 0 , info.width * info.height * (info.bits_per_pixel/8));
215 console_fb.width = info.width;
216 console_fb.height = info.height;
217 console_fb.pitch = info.width * (info.bits_per_pixel/8);
218 console_fb.vaddr = (rt_uint32_t)virt_buffer;
219 console_fb.paddr = (rt_uint32_t)info.framebuffer;
220 console_fb.size = info.width * info.height * (info.bits_per_pixel/8);
221 console_fb.depth = info.bits_per_pixel/8;
222 console_fb.x = 0;
223 console_fb.y = 0;
224 if(console_fb.depth >= 3)
225 {
226 console_fb.fore = CONSOLE_WHITE_32;
227 console_fb.back = CONSOLE_BLACK_32;
228 }
229 else
230 {
231 console_fb.fore = CONSOLE_WHITE_16;
232 console_fb.back = CONSOLE_BLACK_16;
233 }
234
235 #ifndef LCD_CONSOLE_FLUSH_NOW
236 console_flush_thread_tid = rt_thread_create("lcd_console", lcd_console_task_entry, (void *)&console_fb,
237 CONSOLE_FLUSH_THREAD_STACK_SIZE,
238 CONSOLE_FLUSH_THREAD_PRIORITY, CONSOLE_FLUSH_THREAD_TIMESLICE);
239 if (console_flush_thread_tid != RT_NULL)
240 rt_thread_startup(console_flush_thread_tid);
241 #endif
242 /*
243 * note:
244 * if serial console and lcd console together
245 * you can add /src/kservice.c:rt_kprintf
246 * #ifdef USING_LCD_CONSOLE
247 * fb_print((char*)rt_log_buf);
248 * #endif
249 *
250 * remove rt_console_set_device(CONSOLE_NAME);
251 */
252 rt_console_set_device(CONSOLE_NAME);
253
254 rt_show_version();//show rt-thread logo
255
256 return 0;
257 }
258 INIT_APP_EXPORT(lcd_console_init);
259