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