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