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