* This patch add support for move cursor and reverse colors
   via ANSI espace codes in cfb_console driver
 * ANSI escape codes can be enabled/disabled via CONFIG_CFB_CONSOLE_ANSI

Signed-off-by: Pali Rohár <pali.ro...@gmail.com>
---
Changes since v1:
   - Added support ANSI code show/hide cursor
   - Added info to README

Changes since original version:
   - Fixed commit message

 README                      |    3 +
 drivers/video/cfb_console.c |  234 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 234 insertions(+), 3 deletions(-)

diff --git a/README b/README
index 60ad9c2..4a610f7 100644
--- a/README
+++ b/README
@@ -613,6 +613,9 @@ The following options need to be configured:
                                                additional board info beside
                                                the logo
 
+               When CONFIG_CFB_CONSOLE_ANSI is defined, console will have
+               ANSI terminal support. Needed for CONFIG_CMDLINE_EDITING.
+
                When CONFIG_CFB_CONSOLE is defined, video console is
                default i/o. Serial console can be forced with
                environment 'console=serial'.
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 43eb994..c9f9765 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -377,6 +377,11 @@ static int console_row;            /* cursor row */
 
 static u32 eorx, fgx, bgx;     /* color pats */
 
+static char ansi_buf[10] = { 0, };
+static int ansi_buf_size;
+static int ansi_colors_need_revert;
+static int ansi_cursor_hidden;
+
 static const int video_font_draw_table8[] = {
        0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
        0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
@@ -602,6 +607,14 @@ static void video_putchar(int xx, int yy, unsigned char c)
        video_drawchars(xx, yy + video_logo_height, &c, 1);
 }
 
+static void console_swap_colors(void)
+{
+       eorx = fgx;
+       fgx = bgx;
+       bgx = eorx;
+       eorx = fgx ^ bgx;
+}
+
 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR)
 static void video_set_cursor(void)
 {
@@ -843,11 +856,12 @@ static void console_cr(void)
        console_col = 0;
 }
 
-void video_putc(const char c)
+static void parse_putc(const char c)
 {
        static int nl = 1;
 
-       CURSOR_OFF;
+       if (!ansi_cursor_hidden)
+               CURSOR_OFF;
 
        switch (c) {
        case 13:                /* back to first column */
@@ -883,7 +897,221 @@ void video_putc(const char c)
                        nl = 0;
                }
        }
-       CURSOR_SET;
+
+       if (!ansi_cursor_hidden)
+               CURSOR_SET;
+}
+
+void video_putc(const char c)
+{
+#ifdef CONFIG_CFB_CONSOLE_ANSI
+       int i;
+
+       if (c == 27) {
+               for (i = 0; i < ansi_buf_size; ++i)
+                       parse_putc(ansi_buf[i]);
+               ansi_buf[0] = 27;
+               ansi_buf_size = 1;
+               return;
+       }
+
+       if (ansi_buf_size > 0) {
+               /*
+               0 - ESC
+               1 - [
+               2 - num1
+               3 - ..
+               4 - ;
+               5 - num2
+               6 - ..
+               7 - cchar
+               */
+               int next = 0;
+
+               int flush = 0;
+               int fail = 0;
+
+               int num1 = 0;
+               int num2 = 0;
+               int cchar = 0;
+
+               ansi_buf[ansi_buf_size++] = c;
+
+               if (ansi_buf_size >= sizeof(ansi_buf))
+                       fail = 1;
+
+               for (i = 0; i < ansi_buf_size; ++i) {
+                       if (fail)
+                               break;
+
+                       switch (next) {
+                       case 0:
+                               if (ansi_buf[i] == 27)
+                                       next = 1;
+                               else
+                                       fail = 1;
+                               break;
+
+                       case 1:
+                               if (ansi_buf[i] == '[')
+                                       next = 2;
+                               else
+                                       fail = 1;
+                               break;
+
+                       case 2:
+                               if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+                                       num1 = ansi_buf[i]-'0';
+                                       next = 3;
+                               } else if (ansi_buf[i] != '?') {
+                                       --i;
+                                       num1 = 1;
+                                       next = 4;
+                               }
+                               break;
+
+                       case 3:
+                               if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+                                       num1 *= 10;
+                                       num1 += ansi_buf[i]-'0';
+                               } else {
+                                       --i;
+                                       next = 4;
+                               }
+                               break;
+
+                       case 4:
+                               if (ansi_buf[i] != ';') {
+                                       --i;
+                                       next = 7;
+                               } else
+                                       next = 5;
+                               break;
+
+                       case 5:
+                               if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+                                       num2 = ansi_buf[i]-'0';
+                                       next = 6;
+                               } else
+                                       fail = 1;
+                               break;
+
+                       case 6:
+                               if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+                                       num2 *= 10;
+                                       num2 += ansi_buf[i]-'0';
+                               } else {
+                                       --i;
+                                       next = 7;
+                               }
+                               break;
+
+                       case 7:
+                               if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
+                                       || ansi_buf[i] == 'J'
+                                       || ansi_buf[i] == 'K'
+                                       || ansi_buf[i] == 'h'
+                                       || ansi_buf[i] == 'l'
+                                       || ansi_buf[i] == 'm') {
+                                       cchar = ansi_buf[i];
+                                       flush = 1;
+                               } else
+                                       fail = 1;
+                               break;
+                       }
+               }
+
+               if (fail) {
+                       for (i = 0; i < ansi_buf_size; ++i)
+                               parse_putc(ansi_buf[i]);
+                       ansi_buf_size = 0;
+                       return;
+               }
+
+               if (flush) {
+                       if (!ansi_cursor_hidden)
+                               CURSOR_OFF;
+                       ansi_buf_size = 0;
+                       switch (cchar) {
+                       case 'A':
+                               /* move cursor num1 rows up */
+                               console_cursor_up(num1);
+                               break;
+                       case 'B':
+                               /* move cursor num1 rows down */
+                               console_cursor_down(num1);
+                               break;
+                       case 'C':
+                               /* move cursor num1 columns forward */
+                               console_cursor_right(num1);
+                               break;
+                       case 'D':
+                               /* move cursor num1 columns back */
+                               console_cursor_left(num1);
+                               break;
+                       case 'E':
+                               /* move cursor num1 rows up at begin of row */
+                               console_previewsline(num1);
+                               break;
+                       case 'F':
+                               /* move cursor num1 rows down at begin of row */
+                               console_newline(num1);
+                               break;
+                       case 'G':
+                               /* move cursor to column num1 */
+                               console_cursor_set_position(-1, num1-1);
+                               break;
+                       case 'H':
+                               /* move cursor to row num1, column num2 */
+                               console_cursor_set_position(num1-1, num2-1);
+                               break;
+                       case 'J':
+                               /* clear console and move cursor to 0, 0 */
+                               console_clear();
+                               console_cursor_set_position(0, 0);
+                               break;
+                       case 'K':
+                               /* clear line */
+                               if (num1 == 0)
+                                       console_clear_line(console_row,
+                                                       console_col,
+                                                       CONSOLE_COLS-1);
+                               else if (num1 == 1)
+                                       console_clear_line(console_row,
+                                                       0, console_col);
+                               else
+                                       console_clear_line(console_row,
+                                                       0, CONSOLE_COLS-1);
+                               break;
+                       case 'h':
+                               ansi_cursor_hidden = 0;
+                               break;
+                       case 'l':
+                               ansi_cursor_hidden = 1;
+                               break;
+                       case 'm':
+                               if (num1 == 0) { /* reset swapped colors */
+                                       if (ansi_colors_need_revert) {
+                                               console_swap_colors();
+                                               ansi_colors_need_revert = 0;
+                                       }
+                               } else if (num1 == 7) { /* once swap colors */
+                                       if (!ansi_colors_need_revert) {
+                                               console_swap_colors();
+                                               ansi_colors_need_revert = 1;
+                                       }
+                               }
+                               break;
+                       }
+                       if (!ansi_cursor_hidden)
+                               CURSOR_SET;
+               }
+       } else {
+               parse_putc(c);
+       }
+#else
+       parse_putc(c);
+#endif
 }
 
 void video_puts(const char *s)
-- 
1.7.9.5

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to