1 /*
2 * Copyright (c) 2018 PHYTEC Messtechnik GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr.h>
8 #include <string.h>
9 #include <display/cfb.h>
10
11 #define LOG_LEVEL CONFIG_CFB_LOG_LEVEL
12 #include <logging/log.h>
13 LOG_MODULE_REGISTER(cfb);
14
15 extern const struct cfb_font __font_entry_start[];
16 extern const struct cfb_font __font_entry_end[];
17
byte_reverse(uint8_t b)18 static inline uint8_t byte_reverse(uint8_t b)
19 {
20 b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
21 b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
22 b = (b & 0xaa) >> 1 | (b & 0x55) << 1;
23 return b;
24 }
25
26 struct char_framebuffer {
27 /** Pointer to a buffer in RAM */
28 uint8_t *buf;
29
30 /** Size of the framebuffer */
31 uint32_t size;
32
33 /** Pointer to the font entry array */
34 const struct cfb_font *fonts;
35
36 /** Display pixel format */
37 enum display_pixel_format pixel_format;
38
39 /** Display screen info */
40 enum display_screen_info screen_info;
41
42 /** Resolution of a framebuffer in pixels in X direction */
43 uint16_t x_res;
44
45 /** Resolution of a framebuffer in pixels in Y direction */
46 uint16_t y_res;
47
48 /** Number of pixels per tile, typically 8 */
49 uint8_t ppt;
50
51 /** Number of available fonts */
52 uint8_t numof_fonts;
53
54 /** Current font index */
55 uint8_t font_idx;
56
57 /** Font kerning */
58 int8_t kerning;
59
60 /** Invertedj*/
61 bool inverted;
62 };
63
64 static struct char_framebuffer char_fb;
65
get_glyph_ptr(const struct cfb_font * fptr,char c)66 static inline uint8_t *get_glyph_ptr(const struct cfb_font *fptr, char c)
67 {
68 if (fptr->caps & CFB_FONT_MONO_VPACKED) {
69 return (uint8_t *)fptr->data +
70 (c - fptr->first_char) *
71 (fptr->width * fptr->height / 8U);
72 }
73
74 return NULL;
75 }
76
77 /*
78 * Draw the monochrome character in the monochrome tiled framebuffer,
79 * a byte is interpreted as 8 pixels ordered vertically among each other.
80 */
draw_char_vtmono(const struct char_framebuffer * fb,char c,uint16_t x,uint16_t y)81 static uint8_t draw_char_vtmono(const struct char_framebuffer *fb,
82 char c, uint16_t x, uint16_t y)
83 {
84 const struct cfb_font *fptr = &(fb->fonts[fb->font_idx]);
85 uint8_t *glyph_ptr;
86 bool need_reverse = (((fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0)
87 != ((fptr->caps & CFB_FONT_MSB_FIRST) != 0));
88
89 if (c < fptr->first_char || c > fptr->last_char) {
90 c = ' ';
91 }
92
93 glyph_ptr = get_glyph_ptr(fptr, c);
94 if (!glyph_ptr) {
95 return 0;
96 }
97
98 for (size_t g_x = 0; g_x < fptr->width; g_x++) {
99 uint32_t y_segment = y / 8U;
100
101 for (size_t g_y = 0; g_y < fptr->height / 8U; g_y++) {
102 uint32_t fb_y = (y_segment + g_y) * fb->x_res;
103 uint8_t byte;
104
105 if ((fb_y + x + g_x) >= fb->size) {
106 return 0;
107 }
108
109 byte = glyph_ptr[g_x * (fptr->height / 8U) + g_y];
110 if (need_reverse) {
111 byte = byte_reverse(byte);
112 }
113
114 fb->buf[fb_y + x + g_x] = byte;
115 }
116
117 }
118
119 return fptr->width;
120 }
121
cfb_print(const struct device * dev,char * str,uint16_t x,uint16_t y)122 int cfb_print(const struct device *dev, char *str, uint16_t x, uint16_t y)
123 {
124 const struct char_framebuffer *fb = &char_fb;
125 const struct cfb_font *fptr;
126
127 if (!fb->fonts || !fb->buf) {
128 return -1;
129 }
130
131 fptr = &(fb->fonts[fb->font_idx]);
132
133 if (fptr->height % 8) {
134 LOG_ERR("Wrong font size");
135 return -1;
136 }
137
138 if ((fb->screen_info & SCREEN_INFO_MONO_VTILED) && !(y % 8)) {
139 for (size_t i = 0; i < strlen(str); i++) {
140 if (x + fptr->width > fb->x_res) {
141 x = 0U;
142 y += fptr->height;
143 }
144 x += fb->kerning + draw_char_vtmono(fb, str[i], x, y);
145 }
146 return 0;
147 }
148
149 LOG_ERR("Unsupported framebuffer configuration");
150 return -1;
151 }
152
cfb_invert(const struct char_framebuffer * fb)153 static int cfb_invert(const struct char_framebuffer *fb)
154 {
155 for (size_t i = 0; i < fb->x_res * fb->y_res / 8U; i++) {
156 fb->buf[i] = ~fb->buf[i];
157 }
158
159 return 0;
160 }
161
cfb_framebuffer_clear(const struct device * dev,bool clear_display)162 int cfb_framebuffer_clear(const struct device *dev, bool clear_display)
163 {
164 const struct char_framebuffer *fb = &char_fb;
165 struct display_buffer_descriptor desc;
166
167 if (!fb || !fb->buf) {
168 return -1;
169 }
170
171 desc.buf_size = fb->size;
172 desc.width = fb->x_res;
173 desc.height = fb->y_res;
174 desc.pitch = fb->x_res;
175 memset(fb->buf, 0, fb->size);
176
177 return 0;
178 }
179
180
cfb_framebuffer_invert(const struct device * dev)181 int cfb_framebuffer_invert(const struct device *dev)
182 {
183 struct char_framebuffer *fb = &char_fb;
184
185 if (!fb || !fb->buf) {
186 return -1;
187 }
188
189 fb->inverted = !fb->inverted;
190
191 return 0;
192 }
193
cfb_framebuffer_finalize(const struct device * dev)194 int cfb_framebuffer_finalize(const struct device *dev)
195 {
196 const struct display_driver_api *api = dev->api;
197 const struct char_framebuffer *fb = &char_fb;
198 struct display_buffer_descriptor desc;
199
200 if (!fb || !fb->buf) {
201 return -1;
202 }
203
204 desc.buf_size = fb->size;
205 desc.width = fb->x_res;
206 desc.height = fb->y_res;
207 desc.pitch = fb->x_res;
208
209 if (!(fb->pixel_format & PIXEL_FORMAT_MONO10) != !(fb->inverted)) {
210 cfb_invert(fb);
211 }
212
213 return api->write(dev, 0, 0, &desc, fb->buf);
214 }
215
cfb_get_display_parameter(const struct device * dev,enum cfb_display_param param)216 int cfb_get_display_parameter(const struct device *dev,
217 enum cfb_display_param param)
218 {
219 const struct char_framebuffer *fb = &char_fb;
220
221 switch (param) {
222 case CFB_DISPLAY_HEIGH:
223 return fb->y_res;
224 case CFB_DISPLAY_WIDTH:
225 return fb->x_res;
226 case CFB_DISPLAY_PPT:
227 return fb->ppt;
228 case CFB_DISPLAY_ROWS:
229 if (fb->screen_info & SCREEN_INFO_MONO_VTILED) {
230 return fb->y_res / fb->ppt;
231 }
232 return fb->y_res;
233 case CFB_DISPLAY_COLS:
234 if (fb->screen_info & SCREEN_INFO_MONO_VTILED) {
235 return fb->x_res;
236 }
237 return fb->x_res / fb->ppt;
238 }
239 return 0;
240 }
241
cfb_framebuffer_set_font(const struct device * dev,uint8_t idx)242 int cfb_framebuffer_set_font(const struct device *dev, uint8_t idx)
243 {
244 struct char_framebuffer *fb = &char_fb;
245
246 if (idx >= fb->numof_fonts) {
247 return -1;
248 }
249
250 fb->font_idx = idx;
251
252 return 0;
253 }
254
cfb_get_font_size(const struct device * dev,uint8_t idx,uint8_t * width,uint8_t * height)255 int cfb_get_font_size(const struct device *dev, uint8_t idx, uint8_t *width,
256 uint8_t *height)
257 {
258 const struct char_framebuffer *fb = &char_fb;
259
260 if (idx >= fb->numof_fonts) {
261 return -1;
262 }
263
264 if (width) {
265 *width = __font_entry_start[idx].width;
266 }
267
268 if (height) {
269 *height = __font_entry_start[idx].height;
270 }
271
272 return 0;
273 }
274
cfb_get_numof_fonts(const struct device * dev)275 int cfb_get_numof_fonts(const struct device *dev)
276 {
277 const struct char_framebuffer *fb = &char_fb;
278
279 return fb->numof_fonts;
280 }
281
cfb_framebuffer_init(const struct device * dev)282 int cfb_framebuffer_init(const struct device *dev)
283 {
284 const struct display_driver_api *api = dev->api;
285 struct char_framebuffer *fb = &char_fb;
286 struct display_capabilities cfg;
287
288 api->get_capabilities(dev, &cfg);
289
290 fb->numof_fonts = __font_entry_end - __font_entry_start;
291 LOG_DBG("number of fonts %d", fb->numof_fonts);
292 if (!fb->numof_fonts) {
293 return -1;
294 }
295
296 fb->x_res = cfg.x_resolution;
297 fb->y_res = cfg.y_resolution;
298 fb->ppt = 8U;
299 fb->pixel_format = cfg.current_pixel_format;
300 fb->screen_info = cfg.screen_info;
301 fb->buf = NULL;
302 fb->font_idx = 0U;
303 fb->kerning = 0;
304 fb->inverted = false;
305
306 fb->fonts = __font_entry_start;
307 fb->font_idx = 0U;
308
309 fb->size = fb->x_res * fb->y_res / fb->ppt;
310 fb->buf = k_malloc(fb->size);
311 if (!fb->buf) {
312 return -1;
313 }
314
315 memset(fb->buf, 0, fb->size);
316
317 return 0;
318 }
319