diff options
author | Vic Yang <victoryang@google.com> | 2012-01-31 22:31:27 +0800 |
---|---|---|
committer | Vic Yang <victoryang@google.com> | 2012-02-01 10:35:36 +0800 |
commit | 1a10681369ffbf79dd1e66c3a540ccff8f845bfa (patch) | |
tree | abcd7a89cde909139c41536f1464706366bf496b /common | |
parent | df1d8933223817b4b5afe33101e939ff243aa9f6 (diff) | |
download | chrome-ec-1a10681369ffbf79dd1e66c3a540ccff8f845bfa.tar.gz |
Handle left and right arrow key in UART console.
Handle left and right arrow key to move cursor around.
Other escape sequences are still ignored.
BUG=chrome-os-partner:7865
TEST=type some text and use left and right arrow key. Cursor should
move.
type 'hellp', left key, and backspace. Should show 'help' and hitting
enter prints help.
type 'hexp', left key, backspace, 'l'. Should show 'help and hitting
enter prints help.
Change-Id: If9ac4504c56f023f824175de2daf565ce72d4560
Diffstat (limited to 'common')
-rw-r--r-- | common/uart_buffering.c | 122 |
1 files changed, 108 insertions, 14 deletions
diff --git a/common/uart_buffering.c b/common/uart_buffering.c index 030626f860..6b43041ce3 100644 --- a/common/uart_buffering.c +++ b/common/uart_buffering.c @@ -21,6 +21,9 @@ #define RX_BUF_NEXT(i) (((i) + 1) & (RX_BUF_SIZE - 1)) #define RX_BUF_PREV(i) (((i) - 1) & (RX_BUF_SIZE - 1)) +/* Macro to calculate difference of pointers in the circular receive buffers */ +#define RX_BUF_DIFF(i, j) (((i) - (j)) & (RX_BUF_SIZE - 1)) + /* Transmit and receive buffers */ static volatile char tx_buf[TX_BUF_SIZE]; static volatile int tx_buf_head; @@ -28,8 +31,10 @@ static volatile int tx_buf_tail; static volatile char rx_buf[RX_BUF_SIZE]; static volatile int rx_buf_head; static volatile int rx_buf_tail; +static volatile int rx_buf_ptr; static int last_rx_was_cr; static int in_escape; +static char esc_seq_char; static int console_mode = 1; @@ -57,6 +62,88 @@ static int __tx_char(int c) return 0; } +static void move_rx_ptr_fwd(void) +{ + if (rx_buf_ptr != rx_buf_head) { + rx_buf_ptr = RX_BUF_NEXT(rx_buf_ptr); + uart_write_char(0x1B); + uart_write_char('['); + uart_write_char('1'); + uart_write_char('C'); + } +} + +static void move_rx_ptr_bwd(void) +{ + if (rx_buf_ptr != rx_buf_tail) { + rx_buf_ptr = RX_BUF_PREV(rx_buf_ptr); + uart_write_char(0x1B); + uart_write_char('['); + uart_write_char('1'); + uart_write_char('D'); + } +} + +static void move_cursor_back(int dist) +{ + while (dist--) + uart_write_char('\b'); +} + +static void handle_backspace(void) +{ + if (rx_buf_ptr != rx_buf_tail) { + /* Move texts after cursor and also update rx buffer. */ + int ptr = rx_buf_ptr; + while (ptr != rx_buf_head) { + uart_write_char(rx_buf[ptr]); + rx_buf[RX_BUF_PREV(ptr)] = rx_buf[ptr]; + ptr = RX_BUF_NEXT(ptr); + } + /* Space over last character and move cursor back to correct + * position. + */ + uart_write_char(' '); + move_cursor_back(RX_BUF_DIFF(ptr, rx_buf_ptr) + 1); + + rx_buf_head = RX_BUF_PREV(rx_buf_head); + rx_buf_ptr = RX_BUF_PREV(rx_buf_ptr); + } + else + /* Cursor moves pass the first character. Move it back. */ + uart_write_char(' '); +} + +static void insert_char(char c) +{ + int ptr; + + /* Move buffer ptr to the end if 'c' is new line */ + if (c == '\n') + rx_buf_ptr = rx_buf_head; + + /* Move text after cursor. */ + ptr = rx_buf_ptr; + while (ptr != rx_buf_head) { + uart_write_char(rx_buf[ptr]); + ptr = RX_BUF_NEXT(ptr); + } + /* Insert character to rx buffer and move cursor to correct + * position. + */ + while (ptr != rx_buf_ptr) { + rx_buf[ptr] = rx_buf[RX_BUF_PREV(ptr)]; + uart_write_char('\b'); + ptr = RX_BUF_PREV(ptr); + } + rx_buf[rx_buf_ptr] = c; + rx_buf_head = RX_BUF_NEXT(rx_buf_head); + rx_buf_ptr = RX_BUF_NEXT(rx_buf_ptr); + /* On overflow, discard oldest output */ + if (rx_buf_head == rx_buf_tail) + rx_buf_tail = RX_BUF_NEXT(rx_buf_tail); +} + /* Helper for UART processing */ void uart_process(void) { @@ -77,16 +164,32 @@ void uart_process(void) last_rx_was_cr = 0; } - /* Eat common terminal escape sequences (ESC [ ...). + /* Handle left and right key, and eat other terminal + * escape sequences (ESC [ ...). * Would be really cool if we used arrow keys to edit * command history, but for now it's sufficient just to * keep them from causing problems. */ if (c == 0x1B) { in_escape = 1; + esc_seq_char = c; continue; } else if (in_escape) { - if (isalpha(c) || c == '~') + if (esc_seq_char == 0x1B && c == '[') + esc_seq_char = '['; + else if (esc_seq_char == '[') { + if (c == 'D') /* Left key */ + move_rx_ptr_bwd(); + else if (c == 'C') /* Right key */ + move_rx_ptr_fwd(); + esc_seq_char = 0; + } + else + esc_seq_char = 0; + + if (isalpha(c) || c == '~') { + esc_seq_char = 0; in_escape = 0; + } continue; } @@ -100,22 +203,12 @@ void uart_process(void) /* Handle backspace if we can */ if (c == '\b') { - if (rx_buf_head != rx_buf_tail) { - /* Delete the previous character (and - * space over it on the output) */ - uart_write_char(' '); - uart_write_char('\b'); - rx_buf_head = RX_BUF_PREV(rx_buf_head); - } + handle_backspace(); continue; } } - rx_buf[rx_buf_head] = c; - rx_buf_head = RX_BUF_NEXT(rx_buf_head); - /* On overflow, discard oldest output */ - if (rx_buf_head == rx_buf_tail) - rx_buf_tail = RX_BUF_NEXT(rx_buf_tail); + insert_char(c); /* Call console callback on newline, if in console mode */ if (console_mode && c == '\n') @@ -416,6 +509,7 @@ int uart_gets(char *dest, int size) if (c == '\n') break; /* Stop on newline */ } + rx_buf_ptr = rx_buf_tail; /* Re-enable interrupts */ uart_enable_interrupt(); |