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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since db5f8d3 was 32e7411, checked in by Martin Decky <martin@…>, 16 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
RevLine 
[965dc18]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
[369a5f8]33 * @brief Serial console services (putc, puts, clear screen, cursor goto,...)
[965dc18]34 * @{
[369a5f8]35 */
[965dc18]36
37/** @file
38 */
39
40#include <stdio.h>
[8b97256]41#include <ipc/ipc.h>
42#include <async.h>
43#include <ipc/fb.h>
44#include <bool.h>
45#include <errno.h>
[8dc12ac]46#include <io/color.h>
47#include <io/style.h>
[19f857a]48#include <str.h>
[369a5f8]49#include <io/screenbuffer.h>
[965dc18]50
[16e9c476]51#include "main.h"
[965dc18]52#include "serial_console.h"
53
54#define MAX_CONTROL 20
55
[369a5f8]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. */
[965dc18]60static putc_function_t putc_function;
61
[369a5f8]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
[8b97256]69/* Allow only 1 connection */
70static int client_connected = 0;
71
[fb69f39]72enum sgr_color_index {
[369a5f8]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
[fb69f39]81};
82
83enum sgr_command {
[369a5f8]84 SGR_RESET = 0,
85 SGR_BOLD = 1,
[32e7411]86 SGR_UNDERLINE = 4,
[369a5f8]87 SGR_BLINK = 5,
88 SGR_REVERSE = 7,
89 SGR_FGCOLOR = 30,
90 SGR_BGCOLOR = 40
[fb69f39]91};
92
93static int color_map[] = {
[369a5f8]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,
[fb69f39]99 [COLOR_MAGENTA] = CI_MAGENTA,
[369a5f8]100 [COLOR_YELLOW] = CI_BROWN,
101 [COLOR_WHITE] = CI_WHITE
[fb69f39]102};
103
[a000878c]104void serial_puts(const char *str)
[965dc18]105{
106 while (*str)
107 putc_function(*(str++));
108}
109
[369a5f8]110static void serial_putchar(wchar_t ch)
[7ce3cb2]111{
[b27eb71]112 if (utf8 != true) {
113 if (ch >= 0 && ch < 128)
114 (*putc_function)((uint8_t) ch);
[369a5f8]115 else
[b27eb71]116 (*putc_function)('?');
[369a5f8]117
[b27eb71]118 return;
119 }
[369a5f8]120
121 size_t offs = 0;
122 char buf[STR_BOUNDS(1)];
[b27eb71]123 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
[369a5f8]124 size_t i;
[b27eb71]125 for (i = 0; i < offs; i++)
126 (*putc_function)(buf[i]);
[369a5f8]127 } else
[b27eb71]128 (*putc_function)('?');
[7ce3cb2]129}
130
[369a5f8]131void serial_goto(const ipcarg_t col, const ipcarg_t row)
[965dc18]132{
[8dc12ac]133 if ((col > scr_width) || (row > scr_height))
[965dc18]134 return;
135
[fb69f39]136 char control[MAX_CONTROL];
137 snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
[965dc18]138 serial_puts(control);
139}
140
[9805cde]141/** ECMA-48 Set Graphics Rendition. */
142static void serial_sgr(const unsigned int mode)
[965dc18]143{
144 char control[MAX_CONTROL];
145 snprintf(control, MAX_CONTROL, "\033[%um", mode);
146 serial_puts(control);
147}
148
[369a5f8]149static void serial_set_style(console_style_t style)
[965dc18]150{
[369a5f8]151 switch (style) {
152 case STYLE_EMPHASIS:
[32e7411]153 serial_sgr(SGR_RESET);
[16e9c476]154 if (color) {
155 serial_sgr(SGR_FGCOLOR + CI_RED);
156 serial_sgr(SGR_BGCOLOR + CI_WHITE);
157 }
158 serial_sgr(SGR_BOLD);
[369a5f8]159 break;
160 case STYLE_INVERTED:
[32e7411]161 serial_sgr(SGR_RESET);
[369a5f8]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:
[32e7411]169 serial_sgr(SGR_RESET);
[369a5f8]170 if (color) {
171 serial_sgr(SGR_FGCOLOR + CI_WHITE);
172 serial_sgr(SGR_BGCOLOR + CI_RED);
[32e7411]173 } else
174 serial_sgr(SGR_UNDERLINE);
[369a5f8]175 break;
176 default:
[32e7411]177 serial_sgr(SGR_RESET);
[16e9c476]178 if (color) {
179 serial_sgr(SGR_FGCOLOR + CI_BLACK);
180 serial_sgr(SGR_BGCOLOR + CI_WHITE);
181 }
182 }
183}
184
[369a5f8]185static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
186 uint8_t flags)
[16e9c476]187{
[32e7411]188 serial_sgr(SGR_RESET);
[16e9c476]189 if (color) {
[32e7411]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);
[16e9c476]194 } else {
[32e7411]195 if (fgcolor >= bgcolor)
[16e9c476]196 serial_sgr(SGR_REVERSE);
[32e7411]197 }
[16e9c476]198}
199
200static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
201{
[369a5f8]202 serial_sgr(SGR_RESET);
203
[32e7411]204 if (fgcolor >= bgcolor)
[8dc12ac]205 serial_sgr(SGR_REVERSE);
[16e9c476]206}
207
[369a5f8]208static void serial_set_attrs(attrs_t *a)
[16e9c476]209{
210 switch (a->t) {
[8dc12ac]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:
[369a5f8]218 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
219 a->a.i.flags);
[8dc12ac]220 break;
[16e9c476]221 }
222}
223
[369a5f8]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
[dc033a1]276/** Draw text data to viewport.
277 *
[32e7411]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.
[369a5f8]284 *
[dc033a1]285 */
[32e7411]286static void draw_text_data(keyfield_t *data, ipcarg_t x0, ipcarg_t y0,
287 ipcarg_t width, ipcarg_t height)
[16e9c476]288{
[369a5f8]289 attrs_t *a0 = &data[0].attrs;
[32e7411]290 serial_set_attrs(a0);
[369a5f8]291
[32e7411]292 ipcarg_t y;
293 for (y = 0; y < height; y++) {
294 serial_goto(x0, y0 + y);
[369a5f8]295
[32e7411]296 ipcarg_t x;
297 for (x = 0; x < width; x++) {
298 attrs_t *attr = &data[y * width + x].attrs;
[369a5f8]299
[32e7411]300 if (!attrs_same(*a0, *attr)) {
301 serial_set_attrs(attr);
302 a0 = attr;
[369a5f8]303 }
304
[32e7411]305 serial_putchar(data[y * width + x].character);
[16e9c476]306 }
307 }
308}
309
[8b97256]310/**
311 * Main function of the thread serving client connections.
312 */
313void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
314{
[16e9c476]315 keyfield_t *interbuf = NULL;
316 size_t intersize = 0;
[8b97256]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);
[16e9c476]330 serial_set_scroll_region(scr_height);
[8b97256]331
332 while (true) {
[369a5f8]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
[8b97256]345 switch (IPC_GET_METHOD(call)) {
346 case IPC_M_PHONE_HUNGUP:
347 client_connected = 0;
348 ipc_answer_0(callid, EOK);
[369a5f8]349
350 /* Exit thread */
[8b97256]351 return;
[16e9c476]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 }
[369a5f8]361
[16e9c476]362 retval = EINVAL;
363 break;
364 case FB_DRAW_TEXT_DATA:
[dc033a1]365 col = IPC_GET_ARG1(call);
366 row = IPC_GET_ARG2(call);
367 w = IPC_GET_ARG3(call);
368 h = IPC_GET_ARG4(call);
[369a5f8]369
[16e9c476]370 if (!interbuf) {
371 retval = EINVAL;
372 break;
373 }
[369a5f8]374
[36e9cd1]375 if ((col + w > scr_width) || (row + h > scr_height)) {
[dc033a1]376 retval = EINVAL;
377 break;
378 }
[369a5f8]379
[dc033a1]380 draw_text_data(interbuf, col, row, w, h);
381 lastcol = col + w;
[8dc12ac]382 lastrow = row + h - 1;
[16e9c476]383 retval = 0;
384 break;
[8b97256]385 case FB_PUTCHAR:
386 c = IPC_GET_ARG1(call);
[8dc12ac]387 col = IPC_GET_ARG2(call);
388 row = IPC_GET_ARG3(call);
[369a5f8]389
[dc033a1]390 if ((lastcol != col) || (lastrow != row))
[8dc12ac]391 serial_goto(col, row);
[369a5f8]392
[dc033a1]393 lastcol = col + 1;
394 lastrow = row;
[7ce3cb2]395 serial_putchar(c);
[8b97256]396 retval = 0;
397 break;
398 case FB_CURSOR_GOTO:
[8dc12ac]399 col = IPC_GET_ARG1(call);
400 row = IPC_GET_ARG2(call);
401 serial_goto(col, row);
[dc033a1]402 lastcol = col;
[8dc12ac]403 lastrow = row;
[8b97256]404 retval = 0;
405 break;
406 case FB_GET_CSIZE:
[8dc12ac]407 ipc_answer_2(callid, EOK, scr_width, scr_height);
[8b97256]408 continue;
[50cfa6c]409 case FB_GET_COLOR_CAP:
410 ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
411 FB_CCAP_STYLE);
412 continue;
[8b97256]413 case FB_CLEAR:
414 serial_clrscr();
415 retval = 0;
416 break;
417 case FB_SET_STYLE:
[53e197f]418 cur_attr.t = at_style;
419 cur_attr.a.s.style = IPC_GET_ARG1(call);
[10270a8]420 serial_set_attrs(&cur_attr);
[9805cde]421 retval = 0;
422 break;
423 case FB_SET_COLOR:
[53e197f]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);
[10270a8]428 serial_set_attrs(&cur_attr);
[9805cde]429 retval = 0;
430 break;
431 case FB_SET_RGB_COLOR:
[53e197f]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);
[10270a8]435 serial_set_attrs(&cur_attr);
[8b97256]436 retval = 0;
437 break;
438 case FB_SCROLL:
[369a5f8]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 }
[8b97256]451 }
[369a5f8]452
453 serial_scroll(rows);
[8dc12ac]454 serial_goto(lastcol, lastrow);
[8b97256]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;
[ebfabf6]464 case FB_SCREEN_YIELD:
[10270a8]465 serial_sgr(SGR_RESET);
466 serial_puts("\033[2J");
467 serial_goto(0, 0);
468 serial_cursor_enable();
469 retval = 0;
470 break;
[ebfabf6]471 case FB_SCREEN_RECLAIM:
472 serial_clrscr();
473 retval = 0;
474 break;
[8b97256]475 default:
476 retval = ENOENT;
477 }
478 ipc_answer_0(callid, retval);
479 }
480}
481
[8dc12ac]482/**
[965dc18]483 * @}
484 */
Note: See TracBrowser for help on using the repository browser.