source: mainline/uspace/srv/fb/serial_console.c@ 17bf658

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 17bf658 was 50cfa6c, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Method for getting console color capabilities. Use to fix invisible tetris pieces.

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