Subversion Repositories HelenOS

Rev

Rev 4201 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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