1 /** @file
2  * @brief Monochrome Character Framebuffer shell module
3  *
4  * Provide some Character Framebuffer shell commands that can be useful for
5  * testing.
6  */
7 
8 /*
9  * Copyright (c) 2018 Diego Sueiro
10  *
11  * SPDX-License-Identifier: Apache-2.0
12  */
13 
14 #include <stdlib.h>
15 #include <zephyr/shell/shell.h>
16 #include <zephyr/display/cfb.h>
17 
18 #define HELP_NONE "[none]"
19 #define HELP_INIT "call \"cfb init\" first"
20 #define HELP_PRINT "<col: pos> <row: pos> \"<text>\""
21 #define HELP_DRAW_POINT "<x> <y0>"
22 #define HELP_DRAW_LINE "<x0> <y0> <x1> <y1>"
23 #define HELP_DRAW_RECT "<x0> <y0> <x1> <y1>"
24 #define HELP_INVERT "[<x> <y> <width> <height>]"
25 
26 static const struct device *const dev =
27 	DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
28 static const char * const param_name[] = {
29 	"height", "width", "ppt", "rows", "cols"};
30 
cmd_clear(const struct shell * sh,size_t argc,char * argv[])31 static int cmd_clear(const struct shell *sh, size_t argc, char *argv[])
32 {
33 	int err;
34 
35 	ARG_UNUSED(argc);
36 	ARG_UNUSED(argv);
37 
38 	err = cfb_framebuffer_clear(dev, true);
39 	if (err) {
40 		shell_error(sh, "Framebuffer clear error=%d", err);
41 		return err;
42 	}
43 
44 	err = cfb_framebuffer_finalize(dev);
45 	if (err) {
46 		shell_error(sh, "Framebuffer finalize error=%d", err);
47 		return err;
48 	}
49 
50 	shell_print(sh, "Display Cleared");
51 
52 	return err;
53 }
54 
cmd_cfb_print(const struct shell * sh,int col,int row,char * str)55 static int cmd_cfb_print(const struct shell *sh, int col, int row, char *str)
56 {
57 	int err;
58 	uint8_t ppt;
59 
60 	ppt = cfb_get_display_parameter(dev, CFB_DISPLAY_PPT);
61 
62 	err = cfb_framebuffer_clear(dev, false);
63 	if (err) {
64 		shell_error(sh, "Framebuffer clear failed error=%d", err);
65 		return err;
66 	}
67 
68 	err = cfb_print(dev, str, col, row * ppt);
69 	if (err) {
70 		shell_error(sh, "Failed to print the string %s error=%d",
71 		      str, err);
72 		return err;
73 	}
74 
75 	err = cfb_framebuffer_finalize(dev);
76 	if (err) {
77 		shell_error(sh,
78 			    "Failed to finalize the Framebuffer error=%d", err);
79 		return err;
80 	}
81 
82 	return err;
83 }
84 
cmd_print(const struct shell * sh,size_t argc,char * argv[])85 static int cmd_print(const struct shell *sh, size_t argc, char *argv[])
86 {
87 	int err;
88 	int col, row;
89 
90 	col = strtol(argv[1], NULL, 10);
91 	if (col > cfb_get_display_parameter(dev, CFB_DISPLAY_COLS)) {
92 		shell_error(sh, "Invalid col=%d position", col);
93 		return -EINVAL;
94 	}
95 
96 	row = strtol(argv[2], NULL, 10);
97 	if (row > cfb_get_display_parameter(dev, CFB_DISPLAY_ROWS)) {
98 		shell_error(sh, "Invalid row=%d position", row);
99 		return -EINVAL;
100 	}
101 
102 	err = cmd_cfb_print(sh, col, row, argv[3]);
103 	if (err) {
104 		shell_error(sh, "Failed printing to Framebuffer error=%d",
105 			    err);
106 	}
107 
108 	return err;
109 }
110 
cmd_draw_text(const struct shell * sh,size_t argc,char * argv[])111 static int cmd_draw_text(const struct shell *sh, size_t argc, char *argv[])
112 {
113 	int err;
114 	int x, y;
115 
116 	x = strtol(argv[1], NULL, 10);
117 	y = strtol(argv[2], NULL, 10);
118 	err = cfb_draw_text(dev, argv[3], x, y);
119 	if (err) {
120 		shell_error(sh, "Failed text drawing to Framebuffer error=%d", err);
121 		return err;
122 	}
123 
124 	err = cfb_framebuffer_finalize(dev);
125 
126 	return err;
127 }
128 
cmd_draw_point(const struct shell * sh,size_t argc,char * argv[])129 static int cmd_draw_point(const struct shell *sh, size_t argc, char *argv[])
130 {
131 	int err;
132 	struct cfb_position pos;
133 
134 	pos.x = strtol(argv[1], NULL, 10);
135 	pos.y = strtol(argv[2], NULL, 10);
136 
137 	err = cfb_draw_point(dev, &pos);
138 	if (err) {
139 		shell_error(sh, "Failed point drawing to Framebuffer error=%d", err);
140 		return err;
141 	}
142 
143 	err = cfb_framebuffer_finalize(dev);
144 
145 	return err;
146 }
147 
cmd_draw_line(const struct shell * sh,size_t argc,char * argv[])148 static int cmd_draw_line(const struct shell *sh, size_t argc, char *argv[])
149 {
150 	int err;
151 	struct cfb_position start, end;
152 
153 	start.x = strtol(argv[1], NULL, 10);
154 	start.y = strtol(argv[2], NULL, 10);
155 	end.x = strtol(argv[3], NULL, 10);
156 	end.y = strtol(argv[4], NULL, 10);
157 
158 	err = cfb_draw_line(dev, &start, &end);
159 	if (err) {
160 		shell_error(sh, "Failed text drawing to Framebuffer error=%d", err);
161 		return err;
162 	}
163 
164 	err = cfb_framebuffer_finalize(dev);
165 
166 	return err;
167 }
168 
cmd_draw_rect(const struct shell * sh,size_t argc,char * argv[])169 static int cmd_draw_rect(const struct shell *sh, size_t argc, char *argv[])
170 {
171 	int err;
172 	struct cfb_position start, end;
173 
174 	start.x = strtol(argv[1], NULL, 10);
175 	start.y = strtol(argv[2], NULL, 10);
176 	end.x = strtol(argv[3], NULL, 10);
177 	end.y = strtol(argv[4], NULL, 10);
178 
179 	err = cfb_draw_rect(dev, &start, &end);
180 	if (err) {
181 		shell_error(sh, "Failed rectanble drawing to Framebuffer error=%d", err);
182 		return err;
183 	}
184 
185 	err = cfb_framebuffer_finalize(dev);
186 
187 	return err;
188 }
189 
cmd_scroll_vert(const struct shell * sh,size_t argc,char * argv[])190 static int cmd_scroll_vert(const struct shell *sh, size_t argc, char *argv[])
191 {
192 	int err = 0;
193 	int col, row;
194 	int boundary;
195 
196 	col = strtol(argv[1], NULL, 10);
197 	if (col > cfb_get_display_parameter(dev, CFB_DISPLAY_COLS)) {
198 		shell_error(sh, "Invalid col=%d position", col);
199 		return -EINVAL;
200 	}
201 
202 	row = strtol(argv[2], NULL, 10);
203 	if (row > cfb_get_display_parameter(dev, CFB_DISPLAY_ROWS)) {
204 		shell_error(sh, "Invalid row=%d position", row);
205 		return -EINVAL;
206 	}
207 
208 	boundary = cfb_get_display_parameter(dev, CFB_DISPLAY_ROWS) - row;
209 
210 	for (int i = 0; i < boundary; i++) {
211 		err = cmd_cfb_print(sh, col, row, argv[3]);
212 		if (err) {
213 			shell_error(sh,
214 				    "Failed printing to Framebuffer error=%d",
215 				    err);
216 			break;
217 		}
218 		row++;
219 	}
220 
221 	cmd_cfb_print(sh, 0, 0, "");
222 
223 	return err;
224 }
225 
cmd_scroll_horz(const struct shell * sh,size_t argc,char * argv[])226 static int cmd_scroll_horz(const struct shell *sh, size_t argc, char *argv[])
227 {
228 	int err = 0;
229 	int col, row;
230 	int boundary;
231 
232 	col = strtol(argv[1], NULL, 10);
233 	if (col > cfb_get_display_parameter(dev, CFB_DISPLAY_COLS)) {
234 		shell_error(sh, "Invalid col=%d position", col);
235 		return -EINVAL;
236 	}
237 
238 	row = strtol(argv[2], NULL, 10);
239 	if (row > cfb_get_display_parameter(dev, CFB_DISPLAY_ROWS)) {
240 		shell_error(sh, "Invalid row=%d position", row);
241 		return -EINVAL;
242 	}
243 
244 	col++;
245 	boundary = cfb_get_display_parameter(dev, CFB_DISPLAY_COLS) - col;
246 
247 	for (int i = 0; i < boundary; i++) {
248 		err = cmd_cfb_print(sh, col, row, argv[3]);
249 		if (err) {
250 			shell_error(sh,
251 				    "Failed printing to Framebuffer error=%d",
252 				    err);
253 			break;
254 		}
255 		col++;
256 	}
257 
258 	cmd_cfb_print(sh, 0, 0, "");
259 
260 	return err;
261 }
262 
cmd_set_font(const struct shell * sh,size_t argc,char * argv[])263 static int cmd_set_font(const struct shell *sh, size_t argc, char *argv[])
264 {
265 	int err;
266 	int idx;
267 	uint8_t height;
268 	uint8_t width;
269 
270 	idx = strtol(argv[1], NULL, 10);
271 
272 	err = cfb_get_font_size(dev, idx, &width, &height);
273 	if (err) {
274 		shell_error(sh, "Invalid font idx=%d err=%d\n", idx, err);
275 		return err;
276 	}
277 
278 	err = cfb_framebuffer_set_font(dev, idx);
279 	if (err) {
280 		shell_error(sh, "Failed setting font idx=%d err=%d", idx,
281 			    err);
282 		return err;
283 	}
284 
285 	shell_print(sh, "Font idx=%d height=%d widht=%d set", idx, height,
286 		    width);
287 
288 	return err;
289 }
290 
cmd_set_kerning(const struct shell * sh,size_t argc,char * argv[])291 static int cmd_set_kerning(const struct shell *sh, size_t argc, char *argv[])
292 {
293 	int err = 0;
294 	long kerning;
295 
296 	kerning = shell_strtol(argv[1], 10, &err);
297 	if (err) {
298 		shell_error(sh, HELP_INIT);
299 		return -EINVAL;
300 	}
301 
302 	err = cfb_set_kerning(dev, kerning);
303 	if (err) {
304 		shell_error(sh, "Failed to set kerning err=%d", err);
305 		return err;
306 	}
307 
308 	return err;
309 }
310 
cmd_invert(const struct shell * sh,size_t argc,char * argv[])311 static int cmd_invert(const struct shell *sh, size_t argc, char *argv[])
312 {
313 	int err;
314 
315 	if (argc == 1) {
316 		err = cfb_framebuffer_invert(dev);
317 		if (err) {
318 			shell_error(sh, "Error inverting Framebuffer");
319 			return err;
320 		}
321 	} else if (argc == 5) {
322 		int x, y, w, h;
323 
324 		x = strtol(argv[1], NULL, 10);
325 		y = strtol(argv[2], NULL, 10);
326 		w = strtol(argv[3], NULL, 10);
327 		h = strtol(argv[4], NULL, 10);
328 
329 		err = cfb_invert_area(dev, x, y, w, h);
330 		if (err) {
331 			shell_error(sh, "Error invert area");
332 			return err;
333 		}
334 	} else {
335 		shell_help(sh);
336 		return 0;
337 	}
338 
339 	cfb_framebuffer_finalize(dev);
340 
341 	shell_print(sh, "Framebuffer Inverted");
342 
343 	return err;
344 }
345 
cmd_get_fonts(const struct shell * sh,size_t argc,char * argv[])346 static int cmd_get_fonts(const struct shell *sh, size_t argc, char *argv[])
347 {
348 	int err = 0;
349 	uint8_t font_height;
350 	uint8_t font_width;
351 
352 	ARG_UNUSED(argc);
353 	ARG_UNUSED(argv);
354 
355 	for (int idx = 0; idx < cfb_get_numof_fonts(dev); idx++) {
356 		if (cfb_get_font_size(dev, idx, &font_width, &font_height)) {
357 			break;
358 		}
359 		shell_print(sh, "idx=%d height=%d width=%d", idx,
360 			    font_height, font_width);
361 	}
362 
363 	return err;
364 }
365 
cmd_get_device(const struct shell * sh,size_t argc,char * argv[])366 static int cmd_get_device(const struct shell *sh, size_t argc, char *argv[])
367 {
368 	int err = 0;
369 
370 	ARG_UNUSED(argc);
371 	ARG_UNUSED(argv);
372 
373 	shell_print(sh, "Framebuffer Device: %s", dev->name);
374 
375 	return err;
376 }
377 
cmd_get_param_all(const struct shell * sh,size_t argc,char * argv[])378 static int cmd_get_param_all(const struct shell *sh, size_t argc,
379 			     char *argv[])
380 {
381 	ARG_UNUSED(argc);
382 	ARG_UNUSED(argv);
383 
384 	for (unsigned int i = 0; i <= CFB_DISPLAY_COLS; i++) {
385 		shell_print(sh, "param: %s=%d", param_name[i],
386 				cfb_get_display_parameter(dev, i));
387 
388 	}
389 
390 	return 0;
391 }
392 
cmd_get_param_height(const struct shell * sh,size_t argc,char * argv[])393 static int cmd_get_param_height(const struct shell *sh, size_t argc,
394 			     char *argv[])
395 {
396 	ARG_UNUSED(argc);
397 	ARG_UNUSED(argv);
398 
399 	shell_print(sh, "param: %s=%d", param_name[CFB_DISPLAY_HEIGH],
400 		    cfb_get_display_parameter(dev, CFB_DISPLAY_HEIGH));
401 
402 	return 0;
403 }
404 
cmd_get_param_width(const struct shell * sh,size_t argc,char * argv[])405 static int cmd_get_param_width(const struct shell *sh, size_t argc,
406 			     char *argv[])
407 {
408 	ARG_UNUSED(argc);
409 	ARG_UNUSED(argv);
410 
411 	shell_print(sh, "param: %s=%d", param_name[CFB_DISPLAY_WIDTH],
412 		    cfb_get_display_parameter(dev, CFB_DISPLAY_WIDTH));
413 
414 	return 0;
415 }
416 
cmd_get_param_ppt(const struct shell * sh,size_t argc,char * argv[])417 static int cmd_get_param_ppt(const struct shell *sh, size_t argc,
418 			     char *argv[])
419 {
420 	ARG_UNUSED(argc);
421 	ARG_UNUSED(argv);
422 
423 	shell_print(sh, "param: %s=%d", param_name[CFB_DISPLAY_PPT],
424 		    cfb_get_display_parameter(dev, CFB_DISPLAY_PPT));
425 
426 	return 0;
427 }
428 
cmd_get_param_rows(const struct shell * sh,size_t argc,char * argv[])429 static int cmd_get_param_rows(const struct shell *sh, size_t argc,
430 			     char *argv[])
431 {
432 	ARG_UNUSED(argc);
433 	ARG_UNUSED(argv);
434 
435 	shell_print(sh, "param: %s=%d", param_name[CFB_DISPLAY_ROWS],
436 		    cfb_get_display_parameter(dev, CFB_DISPLAY_ROWS));
437 
438 	return 0;
439 }
440 
cmd_get_param_cols(const struct shell * sh,size_t argc,char * argv[])441 static int cmd_get_param_cols(const struct shell *sh, size_t argc,
442 			     char *argv[])
443 {
444 	ARG_UNUSED(argc);
445 	ARG_UNUSED(argv);
446 
447 	shell_print(sh, "param: %s=%d", param_name[CFB_DISPLAY_COLS],
448 		    cfb_get_display_parameter(dev, CFB_DISPLAY_COLS));
449 
450 	return 0;
451 }
452 
cmd_init(const struct shell * sh,size_t argc,char * argv[])453 static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
454 {
455 	int err;
456 
457 	if (!device_is_ready(dev)) {
458 		shell_error(sh, "Display device not ready");
459 		return -ENODEV;
460 	}
461 
462 	err = display_set_pixel_format(dev, PIXEL_FORMAT_MONO10);
463 	if (err) {
464 		err = display_set_pixel_format(dev, PIXEL_FORMAT_MONO01);
465 		if (err) {
466 			shell_error(sh, "Failed to set required pixel format: %d", err);
467 			return err;
468 		}
469 	}
470 
471 	err = display_blanking_off(dev);
472 	if (err) {
473 		shell_error(sh, "Failed to turn off display blanking: %d", err);
474 		return err;
475 	}
476 
477 	err = cfb_framebuffer_init(dev);
478 	if (err) {
479 		shell_error(sh, "Framebuffer initialization failed!");
480 		return err;
481 	}
482 
483 	shell_print(sh, "Framebuffer initialized: %s", dev->name);
484 	cmd_clear(sh, argc, argv);
485 
486 	return err;
487 }
488 
489 SHELL_STATIC_SUBCMD_SET_CREATE(sub_cmd_get_param,
490 
491 	SHELL_CMD_ARG(all, NULL, NULL, cmd_get_param_all, 1, 0),
492 	SHELL_CMD_ARG(height, NULL, NULL, cmd_get_param_height, 1, 0),
493 	SHELL_CMD_ARG(width, NULL, NULL, cmd_get_param_width, 1, 0),
494 	SHELL_CMD_ARG(ppt, NULL, NULL, cmd_get_param_ppt, 1, 0),
495 	SHELL_CMD_ARG(rows, NULL, NULL, cmd_get_param_rows, 1, 0),
496 	SHELL_CMD_ARG(cols, NULL, NULL, cmd_get_param_cols, 1, 0),
497 	SHELL_SUBCMD_SET_END
498 );
499 
500 SHELL_STATIC_SUBCMD_SET_CREATE(sub_cmd_scroll,
501 
502 	SHELL_CMD_ARG(vertical, NULL, HELP_PRINT, cmd_scroll_vert, 4, 0),
503 	SHELL_CMD_ARG(horizontal, NULL, HELP_PRINT, cmd_scroll_horz, 4, 0),
504 	SHELL_SUBCMD_SET_END
505 );
506 
507 SHELL_STATIC_SUBCMD_SET_CREATE(sub_cmd_draw,
508 	SHELL_CMD_ARG(text, NULL, HELP_PRINT, cmd_draw_text, 4, 0),
509 	SHELL_CMD_ARG(point, NULL, HELP_DRAW_POINT, cmd_draw_point, 3, 0),
510 	SHELL_CMD_ARG(line, NULL, HELP_DRAW_LINE, cmd_draw_line, 5, 0),
511 	SHELL_CMD_ARG(rect, NULL, HELP_DRAW_RECT, cmd_draw_rect, 5, 0),
512 	SHELL_SUBCMD_SET_END
513 );
514 
515 SHELL_STATIC_SUBCMD_SET_CREATE(cfb_cmds,
516 	SHELL_CMD_ARG(init, NULL, HELP_NONE, cmd_init, 1, 0),
517 	SHELL_CMD_ARG(get_device, NULL, HELP_NONE, cmd_get_device, 1, 0),
518 	SHELL_CMD(get_param, &sub_cmd_get_param,
519 		  "<all, height, width, ppt, rows, cols>", NULL),
520 	SHELL_CMD_ARG(get_fonts, NULL, HELP_NONE, cmd_get_fonts, 1, 0),
521 	SHELL_CMD_ARG(set_font, NULL, "<idx>", cmd_set_font, 2, 0),
522 	SHELL_CMD_ARG(set_kerning, NULL, "<kerning>", cmd_set_kerning, 2, 0),
523 	SHELL_CMD_ARG(invert, NULL, HELP_INVERT, cmd_invert, 1, 5),
524 	SHELL_CMD_ARG(print, NULL, HELP_PRINT, cmd_print, 4, 0),
525 	SHELL_CMD(scroll, &sub_cmd_scroll, "scroll a text in vertical or "
526 		  "horizontal direction", NULL),
527 	SHELL_CMD(draw, &sub_cmd_draw, "drawing text", NULL),
528 	SHELL_CMD_ARG(clear, NULL, HELP_NONE, cmd_clear, 1, 0),
529 	SHELL_SUBCMD_SET_END
530 );
531 
532 SHELL_CMD_REGISTER(cfb, &cfb_cmds, "Character Framebuffer shell commands",
533 		   NULL);
534