source: mainline/uspace/srv/hid/fb/serial_console.c@ 63bdde6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 63bdde6 was 32e7411, checked in by Martin Decky <martin@…>, 15 years ago

more serial console fixes

  • better attributes in monochrome mode
  • better colors for styles in color mode
  • fix errors on redrawing areas
  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * Copyright (c) 2008 Martin Decky
4 * Copyright (c) 2008 Pavel Rimsky
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @defgroup serial Serial console
33 * @brief Serial console services (putc, puts, clear screen, cursor goto,...)
34 * @{
35 */
36
37/** @file
38 */
39
40#include <stdio.h>
41#include <ipc/ipc.h>
42#include <async.h>
43#include <ipc/fb.h>
44#include <bool.h>
45#include <errno.h>
46#include <io/color.h>
47#include <io/style.h>
48#include <str.h>
49#include <io/screenbuffer.h>
50
51#include "main.h"
52#include "serial_console.h"
53
54#define MAX_CONTROL 20
55
56static ipcarg_t scr_width;
57static ipcarg_t scr_height;
58static bool color = true; /**< True if producing color output. */
59static bool utf8 = false; /**< True if producing UTF8 output. */
60static putc_function_t putc_function;
61
62static ipcarg_t lastcol = 0;
63static ipcarg_t lastrow = 0;
64static attrs_t cur_attr = {
65 .t = at_style,
66 .a.s.style = STYLE_NORMAL
67};
68
69/* Allow only 1 connection */
70static int client_connected = 0;
71
72enum sgr_color_index {
73 CI_BLACK = 0,
74 CI_RED = 1,
75 CI_GREEN = 2,
76 CI_BROWN = 3,
77 CI_BLUE = 4,
78 CI_MAGENTA = 5,
79 CI_CYAN = 6,
80 CI_WHITE = 7
81};
82
83enum sgr_command {
84 SGR_RESET = 0,
85 SGR_BOLD = 1,
86 SGR_UNDERLINE = 4,
87 SGR_BLINK = 5,
88 SGR_REVERSE = 7,
89 SGR_FGCOLOR = 30,
90 SGR_BGCOLOR = 40
91};
92
93static int color_map[] = {
94 [COLOR_BLACK] = CI_BLACK,
95 [COLOR_BLUE] = CI_RED,
96 [COLOR_GREEN] = CI_GREEN,
97 [COLOR_CYAN] = CI_CYAN,
98 [COLOR_RED] = CI_RED,
99 [COLOR_MAGENTA] = CI_MAGENTA,
100 [COLOR_YELLOW] = CI_BROWN,
101 [COLOR_WHITE] = CI_WHITE
102};
103
104void serial_puts(const char *str)
105{
106 while (*str)
107 putc_function(*(str++));
108}
109
110static void serial_putchar(wchar_t ch)
111{
112 if (utf8 != true) {
113 if (ch >= 0 && ch < 128)
114 (*putc_function)((uint8_t) ch);
115 else
116 (*putc_function)('?');
117
118 return;
119 }
120
121 size_t offs = 0;
122 char buf[STR_BOUNDS(1)];
123 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
124 size_t i;
125 for (i = 0; i < offs; i++)
126 (*putc_function)(buf[i]);
127 } else
128 (*putc_function)('?');
129}
130
131void serial_goto(const ipcarg_t col, const ipcarg_t row)
132{
133 if ((col > scr_width) || (row > scr_height))
134 return;
135
136 char control[MAX_CONTROL];
137 snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
138 serial_puts(control);
139}
140
141/** ECMA-48 Set Graphics Rendition. */
142static void serial_sgr(const unsigned int mode)
143{
144 char control[MAX_CONTROL];
145 snprintf(control, MAX_CONTROL, "\033[%um", mode);
146 serial_puts(control);
147}
148
149static void serial_set_style(console_style_t style)
150{
151 switch (style) {
152 case STYLE_EMPHASIS:
153 serial_sgr(SGR_RESET);
154 if (color) {
155 serial_sgr(SGR_FGCOLOR + CI_RED);
156 serial_sgr(SGR_BGCOLOR + CI_WHITE);
157 }
158 serial_sgr(SGR_BOLD);
159 break;
160 case STYLE_INVERTED:
161 serial_sgr(SGR_RESET);
162 if (color) {
163 serial_sgr(SGR_FGCOLOR + CI_WHITE);
164 serial_sgr(SGR_BGCOLOR + CI_BLACK);
165 } else
166 serial_sgr(SGR_REVERSE);
167 break;
168 case STYLE_SELECTED:
169 serial_sgr(SGR_RESET);
170 if (color) {
171 serial_sgr(SGR_FGCOLOR + CI_WHITE);
172 serial_sgr(SGR_BGCOLOR + CI_RED);
173 } else
174 serial_sgr(SGR_UNDERLINE);
175 break;
176 default:
177 serial_sgr(SGR_RESET);
178 if (color) {
179 serial_sgr(SGR_FGCOLOR + CI_BLACK);
180 serial_sgr(SGR_BGCOLOR + CI_WHITE);
181 }
182 }
183}
184
185static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
186 uint8_t flags)
187{
188 serial_sgr(SGR_RESET);
189 if (color) {
190 serial_sgr(SGR_FGCOLOR + color_map[fgcolor & 7]);
191 serial_sgr(SGR_BGCOLOR + color_map[bgcolor & 7]);
192 if (flags & CATTR_BRIGHT)
193 serial_sgr(SGR_BOLD);
194 } else {
195 if (fgcolor >= bgcolor)
196 serial_sgr(SGR_REVERSE);
197 }
198}
199
200static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
201{
202 serial_sgr(SGR_RESET);
203
204 if (fgcolor >= bgcolor)
205 serial_sgr(SGR_REVERSE);
206}
207
208static void serial_set_attrs(attrs_t *a)
209{
210 switch (a->t) {
211 case at_style:
212 serial_set_style(a->a.s.style);
213 break;
214 case at_rgb:
215 serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color);
216 break;
217 case at_idx:
218 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
219 a->a.i.flags);
220 break;
221 }
222}
223
224void serial_clrscr(void)
225{
226 /* Initialize graphic rendition attributes. */
227 serial_sgr(SGR_RESET);
228 if (color) {
229 serial_sgr(SGR_FGCOLOR + CI_BLACK);
230 serial_sgr(SGR_BGCOLOR + CI_WHITE);
231 }
232
233 serial_puts("\033[2J");
234
235 serial_set_attrs(&cur_attr);
236}
237
238void serial_scroll(ssize_t i)
239{
240 if (i > 0) {
241 serial_goto(0, scr_height - 1);
242 while (i--)
243 serial_puts("\033D");
244 } else if (i < 0) {
245 serial_goto(0, 0);
246 while (i++)
247 serial_puts("\033M");
248 }
249}
250
251/** Set scrolling region. */
252void serial_set_scroll_region(ipcarg_t last_row)
253{
254 char control[MAX_CONTROL];
255 snprintf(control, MAX_CONTROL, "\033[0;%ur", last_row);
256 serial_puts(control);
257}
258
259void serial_cursor_disable(void)
260{
261 serial_puts("\033[?25l");
262}
263
264void serial_cursor_enable(void)
265{
266 serial_puts("\033[?25h");
267}
268
269void serial_console_init(putc_function_t putc_fn, ipcarg_t w, ipcarg_t h)
270{
271 scr_width = w;
272 scr_height = h;
273 putc_function = putc_fn;
274}
275
276/** Draw text data to viewport.
277 *
278 * @param vport Viewport id
279 * @param data Text data.
280 * @param x0 Leftmost column of the area.
281 * @param y0 Topmost row of the area.
282 * @param width Number of rows.
283 * @param height Number of columns.
284 *
285 */
286static void draw_text_data(keyfield_t *data, ipcarg_t x0, ipcarg_t y0,
287 ipcarg_t width, ipcarg_t height)
288{
289 attrs_t *a0 = &data[0].attrs;
290 serial_set_attrs(a0);
291
292 ipcarg_t y;
293 for (y = 0; y < height; y++) {
294 serial_goto(x0, y0 + y);
295
296 ipcarg_t x;
297 for (x = 0; x < width; x++) {
298 attrs_t *attr = &data[y * width + x].attrs;
299
300 if (!attrs_same(*a0, *attr)) {
301 serial_set_attrs(attr);
302 a0 = attr;
303 }
304
305 serial_putchar(data[y * width + x].character);
306 }
307 }
308}
309
310/**
311 * Main function of the thread serving client connections.
312 */
313void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
314{
315 keyfield_t *interbuf = NULL;
316 size_t intersize = 0;
317
318 if (client_connected) {
319 ipc_answer_0(iid, ELIMIT);
320 return;
321 }
322
323 client_connected = 1;
324 ipc_answer_0(iid, EOK);
325
326 /* Clear the terminal, set scrolling region
327 to 0 - height rows. */
328 serial_clrscr();
329 serial_goto(0, 0);
330 serial_set_scroll_region(scr_height);
331
332 while (true) {
333 ipc_call_t call;
334 ipc_callid_t callid = async_get_call(&call);
335
336 wchar_t c;
337 ipcarg_t col;
338 ipcarg_t row;
339 ipcarg_t w;
340 ipcarg_t h;
341 ssize_t rows;
342
343 int retval;
344
345 switch (IPC_GET_METHOD(call)) {
346 case IPC_M_PHONE_HUNGUP:
347 client_connected = 0;
348 ipc_answer_0(callid, EOK);
349
350 /* Exit thread */
351 return;
352 case IPC_M_SHARE_OUT:
353 /* We accept one area for data interchange */
354 intersize = IPC_GET_ARG2(call);
355 if (intersize >= scr_width * scr_height *
356 sizeof(*interbuf)) {
357 receive_comm_area(callid, &call,
358 (void *) &interbuf);
359 continue;
360 }
361
362 retval = EINVAL;
363 break;
364 case FB_DRAW_TEXT_DATA:
365 col = IPC_GET_ARG1(call);
366 row = IPC_GET_ARG2(call);
367 w = IPC_GET_ARG3(call);
368 h = IPC_GET_ARG4(call);
369
370 if (!interbuf) {
371 retval = EINVAL;
372 break;
373 }
374
375 if ((col + w > scr_width) || (row + h > scr_height)) {
376 retval = EINVAL;
377 break;
378 }
379
380 draw_text_data(interbuf, col, row, w, h);
381 lastcol = col + w;
382 lastrow = row + h - 1;
383 retval = 0;
384 break;
385 case FB_PUTCHAR:
386 c = IPC_GET_ARG1(call);
387 col = IPC_GET_ARG2(call);
388 row = IPC_GET_ARG3(call);
389
390 if ((lastcol != col) || (lastrow != row))
391 serial_goto(col, row);
392
393 lastcol = col + 1;
394 lastrow = row;
395 serial_putchar(c);
396 retval = 0;
397 break;
398 case FB_CURSOR_GOTO:
399 col = IPC_GET_ARG1(call);
400 row = IPC_GET_ARG2(call);
401 serial_goto(col, row);
402 lastcol = col;
403 lastrow = row;
404 retval = 0;
405 break;
406 case FB_GET_CSIZE:
407 ipc_answer_2(callid, EOK, scr_width, scr_height);
408 continue;
409 case FB_GET_COLOR_CAP:
410 ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
411 FB_CCAP_STYLE);
412 continue;
413 case FB_CLEAR:
414 serial_clrscr();
415 retval = 0;
416 break;
417 case FB_SET_STYLE:
418 cur_attr.t = at_style;
419 cur_attr.a.s.style = IPC_GET_ARG1(call);
420 serial_set_attrs(&cur_attr);
421 retval = 0;
422 break;
423 case FB_SET_COLOR:
424 cur_attr.t = at_idx;
425 cur_attr.a.i.fg_color = IPC_GET_ARG1(call);
426 cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
427 cur_attr.a.i.flags = IPC_GET_ARG3(call);
428 serial_set_attrs(&cur_attr);
429 retval = 0;
430 break;
431 case FB_SET_RGB_COLOR:
432 cur_attr.t = at_rgb;
433 cur_attr.a.r.fg_color = IPC_GET_ARG1(call);
434 cur_attr.a.r.bg_color = IPC_GET_ARG2(call);
435 serial_set_attrs(&cur_attr);
436 retval = 0;
437 break;
438 case FB_SCROLL:
439 rows = IPC_GET_ARG1(call);
440
441 if (rows >= 0) {
442 if ((ipcarg_t) rows > scr_height) {
443 retval = EINVAL;
444 break;
445 }
446 } else {
447 if ((ipcarg_t) (-rows) > scr_height) {
448 retval = EINVAL;
449 break;
450 }
451 }
452
453 serial_scroll(rows);
454 serial_goto(lastcol, lastrow);
455 retval = 0;
456 break;
457 case FB_CURSOR_VISIBILITY:
458 if(IPC_GET_ARG1(call))
459 serial_cursor_enable();
460 else
461 serial_cursor_disable();
462 retval = 0;
463 break;
464 case FB_SCREEN_YIELD:
465 serial_sgr(SGR_RESET);
466 serial_puts("\033[2J");
467 serial_goto(0, 0);
468 serial_cursor_enable();
469 retval = 0;
470 break;
471 case FB_SCREEN_RECLAIM:
472 serial_clrscr();
473 retval = 0;
474 break;
475 default:
476 retval = ENOENT;
477 }
478 ipc_answer_0(callid, retval);
479 }
480}
481
482/**
483 * @}
484 */
Note: See TracBrowser for help on using the repository browser.