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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7e752b2 was 7e752b2, checked in by Martin Decky <martin@…>, 15 years ago
  • correct printf() formatting strings and corresponding arguments
  • minor cstyle changes and other small fixes
  • Property mode set to 100644
File size: 10.5 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>
[7e752b2]49#include <inttypes.h>
[369a5f8]50#include <io/screenbuffer.h>
[965dc18]51
[16e9c476]52#include "main.h"
[965dc18]53#include "serial_console.h"
54
55#define MAX_CONTROL 20
56
[369a5f8]57static ipcarg_t scr_width;
58static ipcarg_t scr_height;
59static bool color = true; /**< True if producing color output. */
60static bool utf8 = false; /**< True if producing UTF8 output. */
[965dc18]61static putc_function_t putc_function;
62
[369a5f8]63static ipcarg_t lastcol = 0;
64static ipcarg_t lastrow = 0;
65static attrs_t cur_attr = {
66 .t = at_style,
67 .a.s.style = STYLE_NORMAL
68};
69
[8b97256]70/* Allow only 1 connection */
71static int client_connected = 0;
72
[fb69f39]73enum sgr_color_index {
[369a5f8]74 CI_BLACK = 0,
75 CI_RED = 1,
76 CI_GREEN = 2,
77 CI_BROWN = 3,
78 CI_BLUE = 4,
79 CI_MAGENTA = 5,
80 CI_CYAN = 6,
81 CI_WHITE = 7
[fb69f39]82};
83
84enum sgr_command {
[369a5f8]85 SGR_RESET = 0,
86 SGR_BOLD = 1,
[32e7411]87 SGR_UNDERLINE = 4,
[369a5f8]88 SGR_BLINK = 5,
89 SGR_REVERSE = 7,
90 SGR_FGCOLOR = 30,
91 SGR_BGCOLOR = 40
[fb69f39]92};
93
94static int color_map[] = {
[369a5f8]95 [COLOR_BLACK] = CI_BLACK,
96 [COLOR_BLUE] = CI_RED,
97 [COLOR_GREEN] = CI_GREEN,
98 [COLOR_CYAN] = CI_CYAN,
99 [COLOR_RED] = CI_RED,
[fb69f39]100 [COLOR_MAGENTA] = CI_MAGENTA,
[369a5f8]101 [COLOR_YELLOW] = CI_BROWN,
102 [COLOR_WHITE] = CI_WHITE
[fb69f39]103};
104
[a000878c]105void serial_puts(const char *str)
[965dc18]106{
107 while (*str)
108 putc_function(*(str++));
109}
110
[369a5f8]111static void serial_putchar(wchar_t ch)
[7ce3cb2]112{
[b27eb71]113 if (utf8 != true) {
114 if (ch >= 0 && ch < 128)
115 (*putc_function)((uint8_t) ch);
[369a5f8]116 else
[b27eb71]117 (*putc_function)('?');
[369a5f8]118
[b27eb71]119 return;
120 }
[369a5f8]121
122 size_t offs = 0;
123 char buf[STR_BOUNDS(1)];
[b27eb71]124 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
[369a5f8]125 size_t i;
[b27eb71]126 for (i = 0; i < offs; i++)
127 (*putc_function)(buf[i]);
[369a5f8]128 } else
[b27eb71]129 (*putc_function)('?');
[7ce3cb2]130}
131
[369a5f8]132void serial_goto(const ipcarg_t col, const ipcarg_t row)
[965dc18]133{
[8dc12ac]134 if ((col > scr_width) || (row > scr_height))
[965dc18]135 return;
136
[fb69f39]137 char control[MAX_CONTROL];
[7e752b2]138 snprintf(control, MAX_CONTROL, "\033[%" PRIun ";%" PRIun "f",
139 row + 1, col + 1);
[965dc18]140 serial_puts(control);
141}
142
[9805cde]143/** ECMA-48 Set Graphics Rendition. */
144static void serial_sgr(const unsigned int mode)
[965dc18]145{
146 char control[MAX_CONTROL];
147 snprintf(control, MAX_CONTROL, "\033[%um", mode);
148 serial_puts(control);
149}
150
[369a5f8]151static void serial_set_style(console_style_t style)
[965dc18]152{
[369a5f8]153 switch (style) {
154 case STYLE_EMPHASIS:
[32e7411]155 serial_sgr(SGR_RESET);
[16e9c476]156 if (color) {
157 serial_sgr(SGR_FGCOLOR + CI_RED);
158 serial_sgr(SGR_BGCOLOR + CI_WHITE);
159 }
160 serial_sgr(SGR_BOLD);
[369a5f8]161 break;
162 case STYLE_INVERTED:
[32e7411]163 serial_sgr(SGR_RESET);
[369a5f8]164 if (color) {
165 serial_sgr(SGR_FGCOLOR + CI_WHITE);
166 serial_sgr(SGR_BGCOLOR + CI_BLACK);
167 } else
168 serial_sgr(SGR_REVERSE);
169 break;
170 case STYLE_SELECTED:
[32e7411]171 serial_sgr(SGR_RESET);
[369a5f8]172 if (color) {
173 serial_sgr(SGR_FGCOLOR + CI_WHITE);
174 serial_sgr(SGR_BGCOLOR + CI_RED);
[32e7411]175 } else
176 serial_sgr(SGR_UNDERLINE);
[369a5f8]177 break;
178 default:
[32e7411]179 serial_sgr(SGR_RESET);
[16e9c476]180 if (color) {
181 serial_sgr(SGR_FGCOLOR + CI_BLACK);
182 serial_sgr(SGR_BGCOLOR + CI_WHITE);
183 }
184 }
185}
186
[369a5f8]187static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
188 uint8_t flags)
[16e9c476]189{
[32e7411]190 serial_sgr(SGR_RESET);
[16e9c476]191 if (color) {
[32e7411]192 serial_sgr(SGR_FGCOLOR + color_map[fgcolor & 7]);
193 serial_sgr(SGR_BGCOLOR + color_map[bgcolor & 7]);
194 if (flags & CATTR_BRIGHT)
195 serial_sgr(SGR_BOLD);
[16e9c476]196 } else {
[32e7411]197 if (fgcolor >= bgcolor)
[16e9c476]198 serial_sgr(SGR_REVERSE);
[32e7411]199 }
[16e9c476]200}
201
202static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
203{
[369a5f8]204 serial_sgr(SGR_RESET);
205
[32e7411]206 if (fgcolor >= bgcolor)
[8dc12ac]207 serial_sgr(SGR_REVERSE);
[16e9c476]208}
209
[369a5f8]210static void serial_set_attrs(attrs_t *a)
[16e9c476]211{
212 switch (a->t) {
[8dc12ac]213 case at_style:
214 serial_set_style(a->a.s.style);
215 break;
216 case at_rgb:
217 serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color);
218 break;
219 case at_idx:
[369a5f8]220 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
221 a->a.i.flags);
[8dc12ac]222 break;
[16e9c476]223 }
224}
225
[369a5f8]226void serial_clrscr(void)
227{
228 /* Initialize graphic rendition attributes. */
229 serial_sgr(SGR_RESET);
230 if (color) {
231 serial_sgr(SGR_FGCOLOR + CI_BLACK);
232 serial_sgr(SGR_BGCOLOR + CI_WHITE);
233 }
234
235 serial_puts("\033[2J");
236
237 serial_set_attrs(&cur_attr);
238}
239
240void serial_scroll(ssize_t i)
241{
242 if (i > 0) {
243 serial_goto(0, scr_height - 1);
244 while (i--)
245 serial_puts("\033D");
246 } else if (i < 0) {
247 serial_goto(0, 0);
248 while (i++)
249 serial_puts("\033M");
250 }
251}
252
253/** Set scrolling region. */
254void serial_set_scroll_region(ipcarg_t last_row)
255{
256 char control[MAX_CONTROL];
[7e752b2]257 snprintf(control, MAX_CONTROL, "\033[0;%" PRIun "r", last_row);
[369a5f8]258 serial_puts(control);
259}
260
261void serial_cursor_disable(void)
262{
263 serial_puts("\033[?25l");
264}
265
266void serial_cursor_enable(void)
267{
268 serial_puts("\033[?25h");
269}
270
271void serial_console_init(putc_function_t putc_fn, ipcarg_t w, ipcarg_t h)
272{
273 scr_width = w;
274 scr_height = h;
275 putc_function = putc_fn;
276}
277
[dc033a1]278/** Draw text data to viewport.
279 *
[32e7411]280 * @param vport Viewport id
281 * @param data Text data.
282 * @param x0 Leftmost column of the area.
283 * @param y0 Topmost row of the area.
284 * @param width Number of rows.
285 * @param height Number of columns.
[369a5f8]286 *
[dc033a1]287 */
[32e7411]288static void draw_text_data(keyfield_t *data, ipcarg_t x0, ipcarg_t y0,
289 ipcarg_t width, ipcarg_t height)
[16e9c476]290{
[369a5f8]291 attrs_t *a0 = &data[0].attrs;
[32e7411]292 serial_set_attrs(a0);
[369a5f8]293
[32e7411]294 ipcarg_t y;
295 for (y = 0; y < height; y++) {
296 serial_goto(x0, y0 + y);
[369a5f8]297
[32e7411]298 ipcarg_t x;
299 for (x = 0; x < width; x++) {
300 attrs_t *attr = &data[y * width + x].attrs;
[369a5f8]301
[32e7411]302 if (!attrs_same(*a0, *attr)) {
303 serial_set_attrs(attr);
304 a0 = attr;
[369a5f8]305 }
306
[32e7411]307 serial_putchar(data[y * width + x].character);
[16e9c476]308 }
309 }
310}
311
[8b97256]312/**
313 * Main function of the thread serving client connections.
314 */
315void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
316{
[16e9c476]317 keyfield_t *interbuf = NULL;
318 size_t intersize = 0;
[8b97256]319
320 if (client_connected) {
321 ipc_answer_0(iid, ELIMIT);
322 return;
323 }
324
325 client_connected = 1;
326 ipc_answer_0(iid, EOK);
327
328 /* Clear the terminal, set scrolling region
329 to 0 - height rows. */
330 serial_clrscr();
331 serial_goto(0, 0);
[16e9c476]332 serial_set_scroll_region(scr_height);
[8b97256]333
334 while (true) {
[369a5f8]335 ipc_call_t call;
336 ipc_callid_t callid = async_get_call(&call);
337
338 wchar_t c;
339 ipcarg_t col;
340 ipcarg_t row;
341 ipcarg_t w;
342 ipcarg_t h;
343 ssize_t rows;
344
345 int retval;
346
[8b97256]347 switch (IPC_GET_METHOD(call)) {
348 case IPC_M_PHONE_HUNGUP:
349 client_connected = 0;
350 ipc_answer_0(callid, EOK);
[369a5f8]351
352 /* Exit thread */
[8b97256]353 return;
[16e9c476]354 case IPC_M_SHARE_OUT:
355 /* We accept one area for data interchange */
356 intersize = IPC_GET_ARG2(call);
357 if (intersize >= scr_width * scr_height *
358 sizeof(*interbuf)) {
359 receive_comm_area(callid, &call,
360 (void *) &interbuf);
361 continue;
362 }
[369a5f8]363
[16e9c476]364 retval = EINVAL;
365 break;
366 case FB_DRAW_TEXT_DATA:
[dc033a1]367 col = IPC_GET_ARG1(call);
368 row = IPC_GET_ARG2(call);
369 w = IPC_GET_ARG3(call);
370 h = IPC_GET_ARG4(call);
[369a5f8]371
[16e9c476]372 if (!interbuf) {
373 retval = EINVAL;
374 break;
375 }
[369a5f8]376
[36e9cd1]377 if ((col + w > scr_width) || (row + h > scr_height)) {
[dc033a1]378 retval = EINVAL;
379 break;
380 }
[369a5f8]381
[dc033a1]382 draw_text_data(interbuf, col, row, w, h);
383 lastcol = col + w;
[8dc12ac]384 lastrow = row + h - 1;
[16e9c476]385 retval = 0;
386 break;
[8b97256]387 case FB_PUTCHAR:
388 c = IPC_GET_ARG1(call);
[8dc12ac]389 col = IPC_GET_ARG2(call);
390 row = IPC_GET_ARG3(call);
[369a5f8]391
[dc033a1]392 if ((lastcol != col) || (lastrow != row))
[8dc12ac]393 serial_goto(col, row);
[369a5f8]394
[dc033a1]395 lastcol = col + 1;
396 lastrow = row;
[7ce3cb2]397 serial_putchar(c);
[8b97256]398 retval = 0;
399 break;
400 case FB_CURSOR_GOTO:
[8dc12ac]401 col = IPC_GET_ARG1(call);
402 row = IPC_GET_ARG2(call);
403 serial_goto(col, row);
[dc033a1]404 lastcol = col;
[8dc12ac]405 lastrow = row;
[8b97256]406 retval = 0;
407 break;
408 case FB_GET_CSIZE:
[8dc12ac]409 ipc_answer_2(callid, EOK, scr_width, scr_height);
[8b97256]410 continue;
[50cfa6c]411 case FB_GET_COLOR_CAP:
412 ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
413 FB_CCAP_STYLE);
414 continue;
[8b97256]415 case FB_CLEAR:
416 serial_clrscr();
417 retval = 0;
418 break;
419 case FB_SET_STYLE:
[53e197f]420 cur_attr.t = at_style;
421 cur_attr.a.s.style = IPC_GET_ARG1(call);
[10270a8]422 serial_set_attrs(&cur_attr);
[9805cde]423 retval = 0;
424 break;
425 case FB_SET_COLOR:
[53e197f]426 cur_attr.t = at_idx;
427 cur_attr.a.i.fg_color = IPC_GET_ARG1(call);
428 cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
429 cur_attr.a.i.flags = IPC_GET_ARG3(call);
[10270a8]430 serial_set_attrs(&cur_attr);
[9805cde]431 retval = 0;
432 break;
433 case FB_SET_RGB_COLOR:
[53e197f]434 cur_attr.t = at_rgb;
435 cur_attr.a.r.fg_color = IPC_GET_ARG1(call);
436 cur_attr.a.r.bg_color = IPC_GET_ARG2(call);
[10270a8]437 serial_set_attrs(&cur_attr);
[8b97256]438 retval = 0;
439 break;
440 case FB_SCROLL:
[369a5f8]441 rows = IPC_GET_ARG1(call);
442
443 if (rows >= 0) {
444 if ((ipcarg_t) rows > scr_height) {
445 retval = EINVAL;
446 break;
447 }
448 } else {
449 if ((ipcarg_t) (-rows) > scr_height) {
450 retval = EINVAL;
451 break;
452 }
[8b97256]453 }
[369a5f8]454
455 serial_scroll(rows);
[8dc12ac]456 serial_goto(lastcol, lastrow);
[8b97256]457 retval = 0;
458 break;
459 case FB_CURSOR_VISIBILITY:
460 if(IPC_GET_ARG1(call))
461 serial_cursor_enable();
462 else
463 serial_cursor_disable();
464 retval = 0;
465 break;
[ebfabf6]466 case FB_SCREEN_YIELD:
[10270a8]467 serial_sgr(SGR_RESET);
468 serial_puts("\033[2J");
469 serial_goto(0, 0);
470 serial_cursor_enable();
471 retval = 0;
472 break;
[ebfabf6]473 case FB_SCREEN_RECLAIM:
474 serial_clrscr();
475 retval = 0;
476 break;
[8b97256]477 default:
478 retval = ENOENT;
479 }
480 ipc_answer_0(callid, retval);
481 }
482}
483
[8dc12ac]484/**
[965dc18]485 * @}
486 */
Note: See TracBrowser for help on using the repository browser.