serial_console.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006 Ondrej Palkovsky
00003  * Copyright (c) 2008 Martin Decky
00004  * Copyright (c) 2008 Pavel Rimsky
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright
00012  *   notice, this list of conditions and the following disclaimer.
00013  * - Redistributions in binary form must reproduce the above copyright
00014  *   notice, this list of conditions and the following disclaimer in the
00015  *   documentation and/or other materials provided with the distribution.
00016  * - The name of the author may not be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00020  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00024  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00028  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 /* Allow only 1 connection */
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         /* Initialize graphic rendition attributes. */
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         /* Clear the terminal, set scrolling region
00328            to 0 - height rows. */
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                         /* Exit thread */
00352                         return;
00353                 case IPC_M_SHARE_OUT:
00354                         /* We accept one area for data interchange */
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 

Generated on Thu Jun 2 07:45:49 2011 for HelenOS/USB by  doxygen 1.4.7