From patchwork Fri Mar 13 22:49:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrey Danin X-Patchwork-Id: 450117 X-Patchwork-Delegate: agust@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 9DB001400DE for ; Sat, 14 Mar 2015 09:58:00 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=mail.ru header.i=@mail.ru header.b=LlxmHLrW; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DF0CBA7424; Fri, 13 Mar 2015 23:57:56 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0GTMvhgVEMsG; Fri, 13 Mar 2015 23:57:56 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 83548A741F; Fri, 13 Mar 2015 23:57:56 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 70C96A741F for ; Fri, 13 Mar 2015 23:57:53 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id NMq1MeVSD4q7 for ; Fri, 13 Mar 2015 23:57:53 +0100 (CET) X-Greylist: delayed 437 seconds by postgrey-1.34 at theia; Fri, 13 Mar 2015 23:57:49 CET X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from fallback4.mail.ru (fallback4.mail.ru [94.100.181.169]) by theia.denx.de (Postfix) with ESMTP id 20235A741D for ; Fri, 13 Mar 2015 23:57:49 +0100 (CET) Received: from smtp36.i.mail.ru (smtp36.i.mail.ru [94.100.177.96]) by fallback4.mail.ru (mPOP.Fallback_MX) with ESMTP id 98C30337620 for ; Sat, 14 Mar 2015 01:50:31 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=LAmTskZufMxLIGvzaJc5HReDUFXeGt4kXTztj0XCMkQ=; b=LlxmHLrW/G3oQlmSDxlyA4WjFrSbbsqQWQRdymGtLc55RWy6ZPNQIeuDcwBD9HQY+MxG6/+o0hZPzKsBRug9mAgGWxbSl/XQDLOAtHzdppLUUxNrA5Ujhqspm6Jml3kycWMShYu2uxmEyDmo66rS1NIF1t5KmBi3FBFXXTNKUiM=; Received: from [87.255.2.44] (port=2044 helo=localhost.localdomain) by smtp36.i.mail.ru with esmtpa (envelope-from ) id 1YWYP4-0003bP-Qf; Sat, 14 Mar 2015 01:50:08 +0300 From: Andrey Danin To: u-boot@lists.denx.de Date: Sat, 14 Mar 2015 01:49:22 +0300 Message-Id: <1426286965-18117-2-git-send-email-danindrey@mail.ru> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1426286965-18117-1-git-send-email-danindrey@mail.ru> References: <1426286965-18117-1-git-send-email-danindrey@mail.ru> MIME-Version: 1.0 X-Spam: Not detected X-Mras: Ok Cc: Stephen Warren , ac100@lists.launchpad.net Subject: [U-Boot] [RFC 1/4] common: add ansi console base implementation X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This code is based on ansi implementation in cfb_console. It is adopted to be used in lcd and cfb_console drivers. Signed-off-by: Andrey Danin --- common/ansi_console.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++ include/ansi_console.h | 39 ++++++ 2 files changed, 394 insertions(+) create mode 100644 common/ansi_console.c create mode 100644 include/ansi_console.h diff --git a/common/ansi_console.c b/common/ansi_console.c new file mode 100644 index 0000000..08adc1b --- /dev/null +++ b/common/ansi_console.c @@ -0,0 +1,355 @@ +#include + +#define COL (*(console->console_col)) +#define ROW (*(console->console_row)) + +#ifdef CONFIG_CONSOLE_ANSI_EXTENSION_ENABLED +static void cursor_fix(struct ansi_console_t *console) +{ + if (ROW < 0) + ROW = 0; + if (ROW >= console->rows) + ROW = console->rows - 1; + if (COL < 0) + COL = 0; + if (COL >= console->cols) + COL = console->cols - 1; +} + +static void cursor_set_position(struct ansi_console_t *console, + int row, int col) +{ + if (ROW != -1) + ROW = row; + if (COL != -1) + COL = col; + cursor_fix(console); +} +#endif /* CONFIG_CONSOLE_ANSI_EXTENSION_ENABLED */ + +static inline void cursor_up(struct ansi_console_t *console, int n) +{ + ROW -= n; + if (ROW < 0) + ROW = 0; +} + +static inline void cursor_down(struct ansi_console_t *console, int n) +{ + ROW += n; + if (ROW >= console->rows) + ROW = console->rows - 1; +} + +static inline void cursor_left(struct ansi_console_t *console, int n) +{ + COL -= n; + if (COL < 0) + COL = 0; +} + +static inline void cursor_right(struct ansi_console_t *console, int n) +{ + COL += n; + if (COL >= console->cols) + COL = console->cols - 1; +} + +static inline void console_previous_line(struct ansi_console_t *console, int n) +{ + COL = 0; + ROW -= n; + + /* Check if we need to scroll the terminal */ + if (ROW < 0) { + if (console->scroll) + console->scroll(1 - ROW); + } else if (console->sync) { + console->sync(); + } +} + +static void console_new_line(struct ansi_console_t *console, int n) +{ + COL = 0; + ROW += n; + + /* Check if we need to scroll the terminal */ + if (ROW >= console->rows) { + if (console->scroll) + console->scroll(console->rows - ROW + 1); + ROW = console->rows - 1; + } else if (console->sync) { + console->sync(); + } +} + +static void console_caret_return(struct ansi_console_t *console) +{ + COL = 0; +} + +static inline void console_back(struct ansi_console_t *console) +{ + if (--COL < 0) { + COL = console->cols - 1; + if (--ROW < 0) + ROW = 0; + } + + console->putc_cr(COL, ROW, ' '); +} + + +static void console_putc(struct ansi_console_t *console, const char c) +{ + switch (c) { + case '\r': /* back to first column */ + console_caret_return(console); + break; + + case '\n': /* next line */ + console_new_line(console, 1); + break; + + case '\t': /* tab 8 */ + COL |= 0x0008; + COL &= ~0x0007; + + if (COL >= console->cols) + console_new_line(console, 1); + break; + + case '\b': /* backspace */ + console_back(console); + break; + + case 7: /* bell */ + break; /* ignored */ + + default: /* draw the char */ + console->putc_cr(COL, ROW, c); + COL++; + + /* check for new line */ + if (COL >= console->cols) + console_new_line(console, 1); + } +} + + +void ansi_putc(struct ansi_console_t *console, const char c) +{ +#ifdef CONFIG_CONSOLE_ANSI_EXTENSION_ENABLED + int i; + + if (c == 27) { + for (i = 0; i < console->ansi_buf_size; ++i) + console_putc(console, console->ansi_buf[i]); + console->ansi_buf[0] = 27; + console->ansi_buf_size = 1; + return; + } + + if (console->ansi_buf_size > 0) { + /* + * 0 - ESC + * 1 - [ + * 2 - num1 + * 3 - .. + * 4 - ; + * 5 - num2 + * 6 - .. + * - cchar + */ + int next = 0; + + int flush = 0; + int fail = 0; + + int num1 = 0; + int num2 = 0; + int cchar = 0; + + console->ansi_buf[console->ansi_buf_size++] = c; + + if (console->ansi_buf_size >= sizeof(console->ansi_buf)) + fail = 1; + + for (i = 0; i < console->ansi_buf_size; ++i) { + if (fail) + break; + + switch (next) { + case 0: + if (console->ansi_buf[i] == 27) + next = 1; + else + fail = 1; + break; + + case 1: + if (console->ansi_buf[i] == '[') + next = 2; + else + fail = 1; + break; + + case 2: + if (console->ansi_buf[i] >= '0' && + console->ansi_buf[i] <= '9') { + num1 = console->ansi_buf[i]-'0'; + next = 3; + } else if (console->ansi_buf[i] != '?') { + --i; + num1 = 1; + next = 4; + } + break; + + case 3: + if (console->ansi_buf[i] >= '0' && + console->ansi_buf[i] <= '9') { + num1 *= 10; + num1 += console->ansi_buf[i]-'0'; + } else { + --i; + next = 4; + } + break; + + case 4: + if (console->ansi_buf[i] != ';') { + --i; + next = 7; + } else { + next = 5; + } + break; + + case 5: + if (console->ansi_buf[i] >= '0' && + console->ansi_buf[i] <= '9') { + num2 = console->ansi_buf[i]-'0'; + next = 6; + } else { + fail = 1; + } + break; + + case 6: + if (console->ansi_buf[i] >= '0' && + console->ansi_buf[i] <= '9') { + num2 *= 10; + num2 += console->ansi_buf[i]-'0'; + } else { + --i; + next = 7; + } + break; + + case 7: + if ((console->ansi_buf[i] >= 'A' && + console->ansi_buf[i] <= 'H') || + console->ansi_buf[i] == 'J' || + console->ansi_buf[i] == 'K' || + console->ansi_buf[i] == 'h' || + console->ansi_buf[i] == 'l' || + console->ansi_buf[i] == 'm') { + cchar = console->ansi_buf[i]; + flush = 1; + } else { + fail = 1; + } + break; + } + } + + if (fail) { + for (i = 0; i < console->ansi_buf_size; ++i) + console_putc(console, console->ansi_buf[i]); + console->ansi_buf_size = 0; + return; + } + + if (flush) { + if (!console->ansi_cursor_hidden && + console->cursor_enable) + console->cursor_enable(0); + console->ansi_buf_size = 0; + switch (cchar) { + case 'A': + /* move cursor num1 rows up */ + cursor_up(console, num1); + break; + case 'B': + /* move cursor num1 rows down */ + cursor_down(console, num1); + break; + case 'C': + /* move cursor num1 columns forward */ + cursor_right(console, num1); + break; + case 'D': + /* move cursor num1 columns back */ + cursor_left(console, num1); + break; + case 'E': + /* move cursor num1 rows up at begin of row */ + console_previous_line(console, num1); + break; + case 'F': + /* move cursor num1 rows down at begin of row */ + console_new_line(console, num1); + break; + case 'G': + /* move cursor to column num1 */ + cursor_set_position(console, -1, num1-1); + break; + case 'H': + /* move cursor to row num1, column num2 */ + cursor_set_position(console, num1-1, num2-1); + break; + case 'J': + /* clear console and move cursor to 0, 0 */ + console->clear(); + cursor_set_position(console, 0, 0); + break; + case 'K': + /* clear line */ + if (num1 == 0) + console->clear_line(ROW, COL, -1); + else if (num1 == 1) + console->clear_line(ROW, 0, COL); + else + console->clear_line(ROW, 0, -1); + break; + case 'h': + console->ansi_cursor_hidden = 0; + break; + case 'l': + console->ansi_cursor_hidden = 1; + break; + case 'm': + if (num1 == 0) { /* reset swapped colors */ + if (console->ansi_colors_need_revert && + console->swap_colors) { + console->swap_colors(); + console->ansi_colors_need_revert = 0; + } + } else if (num1 == 7) { /* once swap colors */ + if (!console->ansi_colors_need_revert && + console->swap_colors) { + console->swap_colors(); + console->ansi_colors_need_revert = 1; + } + } + break; + } + if (!console->ansi_cursor_hidden && console->cursor_set) + console->cursor_set(); + } + } else +#endif /* CONFIG_ANSI_CONSOLE_EXTENSION_ENABLED */ + console_putc(console, c); +} diff --git a/include/ansi_console.h b/include/ansi_console.h new file mode 100644 index 0000000..b7ec094 --- /dev/null +++ b/include/ansi_console.h @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2012 + * Pali Rohár + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * ANSI terminal + */ + +#include + +struct ansi_console_t { + void (*putc_cr)(int col, int row, const char c); + + void (*clear_line)(int line, int begin, int end); + + void (*clear)(void); + void (*swap_colors)(void); + + /* Optional */ + void (*cursor_set)(void); + void (*cursor_enable)(int state); + void (*sync)(void); + void (*scroll)(int n); + + int cols; + int rows; + int *console_col; + int *console_row; + + char ansi_buf[10]; + int ansi_buf_size; + int ansi_colors_need_revert; + int ansi_cursor_hidden; +}; + +void ansi_putc(struct ansi_console_t *console, const char c);