00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00040 #include <stdio.h>
00041 #include <async.h>
00042 #include <ipc/fb.h>
00043 #include <bool.h>
00044 #include <errno.h>
00045 #include <io/color.h>
00046 #include <io/style.h>
00047 #include <str.h>
00048 #include <inttypes.h>
00049 #include <io/screenbuffer.h>
00050
00051 #include "main.h"
00052 #include "serial_console.h"
00053
00054 #define MAX_CONTROL 20
00055
00056 static sysarg_t scr_width;
00057 static sysarg_t scr_height;
00058 static bool color = true;
00059 static bool utf8 = false;
00060 static putc_function_t putc_function;
00061
00062 static sysarg_t lastcol = 0;
00063 static sysarg_t lastrow = 0;
00064 static attrs_t cur_attr = {
00065 .t = at_style,
00066 .a.s.style = STYLE_NORMAL
00067 };
00068
00069
00070 static int client_connected = 0;
00071
00072 enum sgr_color_index {
00073 CI_BLACK = 0,
00074 CI_RED = 1,
00075 CI_GREEN = 2,
00076 CI_BROWN = 3,
00077 CI_BLUE = 4,
00078 CI_MAGENTA = 5,
00079 CI_CYAN = 6,
00080 CI_WHITE = 7
00081 };
00082
00083 enum sgr_command {
00084 SGR_RESET = 0,
00085 SGR_BOLD = 1,
00086 SGR_UNDERLINE = 4,
00087 SGR_BLINK = 5,
00088 SGR_REVERSE = 7,
00089 SGR_FGCOLOR = 30,
00090 SGR_BGCOLOR = 40
00091 };
00092
00093 static int color_map[] = {
00094 [COLOR_BLACK] = CI_BLACK,
00095 [COLOR_BLUE] = CI_RED,
00096 [COLOR_GREEN] = CI_GREEN,
00097 [COLOR_CYAN] = CI_CYAN,
00098 [COLOR_RED] = CI_RED,
00099 [COLOR_MAGENTA] = CI_MAGENTA,
00100 [COLOR_YELLOW] = CI_BROWN,
00101 [COLOR_WHITE] = CI_WHITE
00102 };
00103
00104 void serial_puts(const char *str)
00105 {
00106 while (*str)
00107 putc_function(*(str++));
00108 }
00109
00110 static void serial_putchar(wchar_t ch)
00111 {
00112 if (utf8 != true) {
00113 if (ch >= 0 && ch < 128)
00114 (*putc_function)((uint8_t) ch);
00115 else
00116 (*putc_function)('?');
00117
00118 return;
00119 }
00120
00121 size_t offs = 0;
00122 char buf[STR_BOUNDS(1)];
00123 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
00124 size_t i;
00125 for (i = 0; i < offs; i++)
00126 (*putc_function)(buf[i]);
00127 } else
00128 (*putc_function)('?');
00129 }
00130
00131 void serial_goto(const sysarg_t col, const sysarg_t row)
00132 {
00133 if ((col > scr_width) || (row > scr_height))
00134 return;
00135
00136 char control[MAX_CONTROL];
00137 snprintf(control, MAX_CONTROL, "\033[%" PRIun ";%" PRIun "f",
00138 row + 1, col + 1);
00139 serial_puts(control);
00140 }
00141
00143 static void serial_sgr(const unsigned int mode)
00144 {
00145 char control[MAX_CONTROL];
00146 snprintf(control, MAX_CONTROL, "\033[%um", mode);
00147 serial_puts(control);
00148 }
00149
00150 static void serial_set_style(console_style_t style)
00151 {
00152 switch (style) {
00153 case STYLE_EMPHASIS:
00154 serial_sgr(SGR_RESET);
00155 if (color) {
00156 serial_sgr(SGR_FGCOLOR + CI_RED);
00157 serial_sgr(SGR_BGCOLOR + CI_WHITE);
00158 }
00159 serial_sgr(SGR_BOLD);
00160 break;
00161 case STYLE_INVERTED:
00162 serial_sgr(SGR_RESET);
00163 if (color) {
00164 serial_sgr(SGR_FGCOLOR + CI_WHITE);
00165 serial_sgr(SGR_BGCOLOR + CI_BLACK);
00166 } else
00167 serial_sgr(SGR_REVERSE);
00168 break;
00169 case STYLE_SELECTED:
00170 serial_sgr(SGR_RESET);
00171 if (color) {
00172 serial_sgr(SGR_FGCOLOR + CI_WHITE);
00173 serial_sgr(SGR_BGCOLOR + CI_RED);
00174 } else
00175 serial_sgr(SGR_UNDERLINE);
00176 break;
00177 default:
00178 serial_sgr(SGR_RESET);
00179 if (color) {
00180 serial_sgr(SGR_FGCOLOR + CI_BLACK);
00181 serial_sgr(SGR_BGCOLOR + CI_WHITE);
00182 }
00183 }
00184 }
00185
00186 static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
00187 uint8_t flags)
00188 {
00189 serial_sgr(SGR_RESET);
00190 if (color) {
00191 serial_sgr(SGR_FGCOLOR + color_map[fgcolor & 7]);
00192 serial_sgr(SGR_BGCOLOR + color_map[bgcolor & 7]);
00193 if (flags & CATTR_BRIGHT)
00194 serial_sgr(SGR_BOLD);
00195 } else {
00196 if (fgcolor >= bgcolor)
00197 serial_sgr(SGR_REVERSE);
00198 }
00199 }
00200
00201 static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
00202 {
00203 serial_sgr(SGR_RESET);
00204
00205 if (fgcolor >= bgcolor)
00206 serial_sgr(SGR_REVERSE);
00207 }
00208
00209 static void serial_set_attrs(attrs_t *a)
00210 {
00211 switch (a->t) {
00212 case at_style:
00213 serial_set_style(a->a.s.style);
00214 break;
00215 case at_rgb:
00216 serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color);
00217 break;
00218 case at_idx:
00219 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
00220 a->a.i.flags);
00221 break;
00222 }
00223 }
00224
00225 void serial_clrscr(void)
00226 {
00227
00228 serial_sgr(SGR_RESET);
00229 if (color) {
00230 serial_sgr(SGR_FGCOLOR + CI_BLACK);
00231 serial_sgr(SGR_BGCOLOR + CI_WHITE);
00232 }
00233
00234 serial_puts("\033[2J");
00235
00236 serial_set_attrs(&cur_attr);
00237 }
00238
00239 void serial_scroll(ssize_t i)
00240 {
00241 if (i > 0) {
00242 serial_goto(0, scr_height - 1);
00243 while (i--)
00244 serial_puts("\033D");
00245 } else if (i < 0) {
00246 serial_goto(0, 0);
00247 while (i++)
00248 serial_puts("\033M");
00249 }
00250 }
00251
00253 void serial_set_scroll_region(sysarg_t last_row)
00254 {
00255 char control[MAX_CONTROL];
00256 snprintf(control, MAX_CONTROL, "\033[0;%" PRIun "r", last_row);
00257 serial_puts(control);
00258 }
00259
00260 void serial_cursor_disable(void)
00261 {
00262 serial_puts("\033[?25l");
00263 }
00264
00265 void serial_cursor_enable(void)
00266 {
00267 serial_puts("\033[?25h");
00268 }
00269
00270 void serial_console_init(putc_function_t putc_fn, sysarg_t w, sysarg_t h)
00271 {
00272 scr_width = w;
00273 scr_height = h;
00274 putc_function = putc_fn;
00275 }
00276
00287 static void draw_text_data(keyfield_t *data, sysarg_t x0, sysarg_t y0,
00288 sysarg_t width, sysarg_t height)
00289 {
00290 attrs_t *a0 = &data[0].attrs;
00291 serial_set_attrs(a0);
00292
00293 sysarg_t y;
00294 for (y = 0; y < height; y++) {
00295 serial_goto(x0, y0 + y);
00296
00297 sysarg_t x;
00298 for (x = 0; x < width; x++) {
00299 attrs_t *attr = &data[y * width + x].attrs;
00300
00301 if (!attrs_same(*a0, *attr)) {
00302 serial_set_attrs(attr);
00303 a0 = attr;
00304 }
00305
00306 serial_putchar(data[y * width + x].character);
00307 }
00308 }
00309 }
00310
00314 void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
00315 {
00316 keyfield_t *interbuf = NULL;
00317 size_t intersize = 0;
00318
00319 if (client_connected) {
00320 async_answer_0(iid, ELIMIT);
00321 return;
00322 }
00323
00324 client_connected = 1;
00325 async_answer_0(iid, EOK);
00326
00327
00328
00329 serial_clrscr();
00330 serial_goto(0, 0);
00331 serial_set_scroll_region(scr_height);
00332
00333 while (true) {
00334 ipc_call_t call;
00335 ipc_callid_t callid = async_get_call(&call);
00336
00337 wchar_t c;
00338 sysarg_t col;
00339 sysarg_t row;
00340 sysarg_t w;
00341 sysarg_t h;
00342 ssize_t rows;
00343
00344 int retval;
00345
00346 switch (IPC_GET_IMETHOD(call)) {
00347 case IPC_M_PHONE_HUNGUP:
00348 client_connected = 0;
00349 async_answer_0(callid, EOK);
00350
00351
00352 return;
00353 case IPC_M_SHARE_OUT:
00354
00355 intersize = IPC_GET_ARG2(call);
00356 if (intersize >= scr_width * scr_height *
00357 sizeof(*interbuf)) {
00358 receive_comm_area(callid, &call,
00359 (void *) &interbuf);
00360 continue;
00361 }
00362
00363 retval = EINVAL;
00364 break;
00365 case FB_DRAW_TEXT_DATA:
00366 col = IPC_GET_ARG1(call);
00367 row = IPC_GET_ARG2(call);
00368 w = IPC_GET_ARG3(call);
00369 h = IPC_GET_ARG4(call);
00370
00371 if (!interbuf) {
00372 retval = EINVAL;
00373 break;
00374 }
00375
00376 if ((col + w > scr_width) || (row + h > scr_height)) {
00377 retval = EINVAL;
00378 break;
00379 }
00380
00381 draw_text_data(interbuf, col, row, w, h);
00382 lastcol = col + w;
00383 lastrow = row + h - 1;
00384 retval = 0;
00385 break;
00386 case FB_PUTCHAR:
00387 c = IPC_GET_ARG1(call);
00388 col = IPC_GET_ARG2(call);
00389 row = IPC_GET_ARG3(call);
00390
00391 if ((lastcol != col) || (lastrow != row))
00392 serial_goto(col, row);
00393
00394 lastcol = col + 1;
00395 lastrow = row;
00396 serial_putchar(c);
00397 retval = 0;
00398 break;
00399 case FB_CURSOR_GOTO:
00400 col = IPC_GET_ARG1(call);
00401 row = IPC_GET_ARG2(call);
00402 serial_goto(col, row);
00403 lastcol = col;
00404 lastrow = row;
00405 retval = 0;
00406 break;
00407 case FB_GET_CSIZE:
00408 async_answer_2(callid, EOK, scr_width, scr_height);
00409 continue;
00410 case FB_GET_COLOR_CAP:
00411 async_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
00412 FB_CCAP_STYLE);
00413 continue;
00414 case FB_CLEAR:
00415 serial_clrscr();
00416 retval = 0;
00417 break;
00418 case FB_SET_STYLE:
00419 cur_attr.t = at_style;
00420 cur_attr.a.s.style = IPC_GET_ARG1(call);
00421 serial_set_attrs(&cur_attr);
00422 retval = 0;
00423 break;
00424 case FB_SET_COLOR:
00425 cur_attr.t = at_idx;
00426 cur_attr.a.i.fg_color = IPC_GET_ARG1(call);
00427 cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
00428 cur_attr.a.i.flags = IPC_GET_ARG3(call);
00429 serial_set_attrs(&cur_attr);
00430 retval = 0;
00431 break;
00432 case FB_SET_RGB_COLOR:
00433 cur_attr.t = at_rgb;
00434 cur_attr.a.r.fg_color = IPC_GET_ARG1(call);
00435 cur_attr.a.r.bg_color = IPC_GET_ARG2(call);
00436 serial_set_attrs(&cur_attr);
00437 retval = 0;
00438 break;
00439 case FB_SCROLL:
00440 rows = IPC_GET_ARG1(call);
00441
00442 if (rows >= 0) {
00443 if ((sysarg_t) rows > scr_height) {
00444 retval = EINVAL;
00445 break;
00446 }
00447 } else {
00448 if ((sysarg_t) (-rows) > scr_height) {
00449 retval = EINVAL;
00450 break;
00451 }
00452 }
00453
00454 serial_scroll(rows);
00455 serial_goto(lastcol, lastrow);
00456 retval = 0;
00457 break;
00458 case FB_CURSOR_VISIBILITY:
00459 if(IPC_GET_ARG1(call))
00460 serial_cursor_enable();
00461 else
00462 serial_cursor_disable();
00463 retval = 0;
00464 break;
00465 case FB_SCREEN_YIELD:
00466 serial_sgr(SGR_RESET);
00467 serial_puts("\033[2J");
00468 serial_goto(0, 0);
00469 serial_cursor_enable();
00470 retval = 0;
00471 break;
00472 case FB_SCREEN_RECLAIM:
00473 serial_clrscr();
00474 retval = 0;
00475 break;
00476 default:
00477 retval = ENOENT;
00478 }
00479 async_answer_0(callid, retval);
00480 }
00481 }
00482