From 7caeceb05cf11fbfa79adb7fcd09c28a3222e99b Mon Sep 17 00:00:00 2001 From: MightyPork Date: Sat, 25 Apr 2015 00:27:07 +0200 Subject: [PATCH] fixed and improved VT100 support --- lib/uart.c | 39 ++++-- lib/uart.h | 35 +++--- lib/uart_ansi.c | 307 ++++++++++++++++++++++++++++++++++++++++++------ lib/uart_ansi.h | 142 ++++++++++++++++++---- 4 files changed, 438 insertions(+), 85 deletions(-) diff --git a/lib/uart.c b/lib/uart.c index b26b499..7782627 100644 --- a/lib/uart.c +++ b/lib/uart.c @@ -102,9 +102,6 @@ void uart_flush() } - - - /** Send CRLF */ void uart_nl() { @@ -118,24 +115,40 @@ char tmpstr[12]; // buffer for number rendering void _uart_putn(const uint8_t places); +/** Send unsigned int8 */ +void uart_put8i(const int8_t num) +{ + itoa(num, tmpstr, 10); + uart_puts(tmpstr); +} + + +/** Send signed int8 */ +void uart_put8u(const uint8_t num) +{ + itoa(num, tmpstr, 10); + uart_puts(tmpstr); +} + + /** Send unsigned int */ -void uart_puti(const int16_t num) +void uart_put16i(const int16_t num) { - ltoa(num, tmpstr, 10); + itoa(num, tmpstr, 10); uart_puts(tmpstr); } /** Send signed int */ -void uart_putu(const uint16_t num) +void uart_put16u(const uint16_t num) { - ltoa(num, tmpstr, 10); + itoa(num, tmpstr, 10); uart_puts(tmpstr); } /** Send unsigned long */ -void uart_putlu(const uint32_t num) +void uart_put32u(const uint32_t num) { ltoa(num, tmpstr, 10); uart_puts(tmpstr); @@ -143,7 +156,7 @@ void uart_putlu(const uint32_t num) /** Send signed long */ -void uart_putl(const int32_t num) +void uart_put32i(const int32_t num) { ltoa(num, tmpstr, 10); uart_puts(tmpstr); @@ -151,7 +164,7 @@ void uart_putl(const int32_t num) /** Send signed long as float */ -void uart_putlf(const int32_t num, const uint8_t places) +void uart_put32if(const int32_t num, const uint8_t places) { if (num < 0) { uart_tx('-'); @@ -165,7 +178,7 @@ void uart_putlf(const int32_t num, const uint8_t places) /** Send unsigned long as float */ -void uart_putluf(const uint32_t num, const uint8_t places) +void uart_put32uf(const uint32_t num, const uint8_t places) { ltoa(num, tmpstr, 10); _uart_putn(places); @@ -173,7 +186,7 @@ void uart_putluf(const uint32_t num, const uint8_t places) /** Send signed int as float */ -void uart_putif(const int16_t num, const uint8_t places) +void uart_put16if(const int16_t num, const uint8_t places) { if (num < 0) { uart_tx('-'); @@ -187,7 +200,7 @@ void uart_putif(const int16_t num, const uint8_t places) /** Send unsigned int as float */ -void uart_putuf(const uint16_t num, const uint8_t places) +void uart_put16uf(const uint16_t num, const uint8_t places) { ltoa(num, tmpstr, 10); _uart_putn(places); diff --git a/lib/uart.h b/lib/uart.h index 0f9fd20..bec3f71 100644 --- a/lib/uart.h +++ b/lib/uart.h @@ -3,8 +3,8 @@ // // Utilities for UART communication. // -// First, init uart with desired baud rate using uart_init(). -// Then, enable interrupts you want, and that's it. +// First, init uart with desired baud rate using uart_init(baud). +// Then enable interrupts you want with uart_isr_XXX(). // #include @@ -13,6 +13,7 @@ #include #include + /** Init UART for given baudrate */ void _uart_init_do(uint16_t ubrr); // internal, needed for the macro. #define uart_init(baud) _uart_init_do(F_CPU / 16 / (baud) - 1) @@ -64,28 +65,34 @@ void uart_puts_pgm(const char* str); // Numbers /** Send unsigned int */ -void uart_puti(const int16_t num); +void uart_put8i(const int8_t num); /** Send signed int */ -void uart_putu(const uint16_t num); +void uart_put8u(const uint8_t num); -/** Send unsigned long */ -void uart_putlu(const uint32_t num); +/** Send unsigned int */ +void uart_put16i(const int16_t num); -/** Send signed long */ -void uart_putl(const int32_t num); +/** Send signed int */ +void uart_put16u(const uint16_t num); -/** Send signed long as float */ -void uart_putlf(const int32_t num, const uint8_t places); +/** Send unsigned long */ +void uart_put32u(const uint32_t num); -/** Send unsigned long as float */ -void uart_putluf(const uint32_t num, const uint8_t places); +/** Send signed long */ +void uart_put32i(const int32_t num); /** Send signed int as float */ -void uart_putif(const int16_t num, const uint8_t places); +void uart_put16if(const int16_t num, const uint8_t places); /** Send unsigned int as float */ -void uart_putuf(const uint16_t num, const uint8_t places); +void uart_put16uf(const uint16_t num, const uint8_t places); + +/** Send signed long as float */ +void uart_put32if(const int32_t num, const uint8_t places); + +/** Send unsigned long as float */ +void uart_put32uf(const uint32_t num, const uint8_t places); // Extras diff --git a/lib/uart_ansi.c b/lib/uart_ansi.c index 57662d2..930d572 100644 --- a/lib/uart_ansi.c +++ b/lib/uart_ansi.c @@ -1,30 +1,54 @@ #include +#include #include #include #include "uart.h" #include "uart_ansi.h" +void _vt_apply_style(); +void _vt_reset_attribs_do(); +void _vt_style_do(); +void _vt_color_do(); -void vt_goto(uint16_t x, uint16_t y) + +void vt_goto(uint8_t x, uint8_t y) { uart_putc(27); uart_putc('['); - uart_putu(x); + uart_put8u(x); uart_putc(';'); - uart_putu(y); + uart_put8u(y); uart_putc('H'); } -void vt_move(int16_t x, int16_t y) +void vt_goto_x(uint8_t x) +{ + uart_putc(27); + uart_putc('['); + uart_put8u(x); + uart_putc('`'); +} + + +void vt_goto_y(uint8_t y) +{ + uart_putc(27); + uart_putc('['); + uart_put8u(y); + uart_putc('d'); +} + + +void vt_move(int8_t x, int8_t y) { vt_move_x(x); vt_move_y(y); } -void vt_move_x(int16_t x) +void vt_move_x(int8_t x) { if (x < 0) { vt_left(-x); @@ -34,7 +58,7 @@ void vt_move_x(int16_t x) } -void vt_move_y(int16_t y) +void vt_move_y(int8_t y) { if (y < 0) { vt_up(-y); @@ -44,47 +68,47 @@ void vt_move_y(int16_t y) } -void vt_up(uint16_t y) +void vt_up(uint8_t y) { if (y == 0) return; uart_putc(27); uart_putc('['); - uart_putu(y); + uart_put8u(y); uart_putc('A'); } -void vt_down(uint16_t y) +void vt_down(uint8_t y) { if (y == 0) return; uart_putc(27); uart_putc('['); - uart_putu(y); + uart_put8u(y); uart_putc('B'); } -void vt_left(uint16_t x) +void vt_left(uint8_t x) { if (x == 0) return; uart_putc(27); uart_putc('['); - uart_putu(x); + uart_put8u(x); uart_putc('D'); } -void vt_right(uint16_t x) +void vt_right(uint8_t x) { if (x == 0) return; uart_putc(27); uart_putc('['); - uart_putu(x); + uart_put8u(x); uart_putc('C'); } -void vt_scroll(int16_t y) +void vt_scroll(int8_t y) { while (y < 0) { uart_putc(27); @@ -100,67 +124,274 @@ void vt_scroll(int16_t y) } -void vt_save() +void vt_scroll_set(uint8_t from, uint8_t to) { uart_putc(27); - uart_putc(7); + uart_putc('['); + uart_put8u(from); + uart_putc(';'); + uart_put8u(to); + uart_putc('r'); } -void vt_restore() +void vt_scroll_reset() { uart_putc(27); - uart_putc(8); + uart_putc('['); + uart_putc('r'); +} + + + +typedef struct { + uint8_t flags; + uint8_t fg; + uint8_t bg; +} vt_style_t; + +vt_style_t saved_style; +vt_style_t current_style; + +void vt_save() +{ + uart_puts_pgm(PSTR("\x1B[s")); + + saved_style = current_style; } -void vt_style(uint8_t flags) +void vt_restore() { - if (flags == VT_NORMAL) { - uart_puts("\x1B[m"); // reset - return; + uart_puts_pgm(PSTR("\x1B[u")); + + current_style = saved_style; +} + + +/** Disable all text attributes (excluding color) */ +void vt_attr_reset() +{ + current_style.flags = 0; + + _vt_reset_attribs_do(); + _vt_apply_style(); +} + + +/** Set color to white on black */ +void vt_color_reset() +{ + current_style.fg = VT_WHITE; + current_style.bg = VT_BLACK; + + _vt_color_do(); +} + + +/** Enable or disable a text attribute */ +void vt_attr(uint8_t attribute, bool on) +{ + // flags are powers of two + // so this can handle multiple OR'd flags + for(uint8_t c = 1; c <= VT_FAINT; c *= 2) { + if (attribute & c) { + if (on) { + current_style.flags |= c; + } else { + current_style.flags &= ~c; + } + } } - if (flags & VT_BOLD) { - uart_puts("\x1B[1m"); + _vt_apply_style(); +} + + +/** Send style and color commands */ +void _vt_apply_style() +{ + _vt_reset_attribs_do(); + _vt_style_do(); + _vt_color_do(); +} + + +/** Set color 0..7 */ +void vt_color(uint8_t fg, uint8_t bg) +{ + current_style.fg = fg; + current_style.bg = bg; + _vt_color_do(); +} + + +/** Set FG color 0..7 */ +void vt_color_fg(uint8_t fg) +{ + current_style.fg = fg; + _vt_color_do(); +} + + +/** Set BG color 0..7 */ +void vt_color_bg(uint8_t bg) +{ + current_style.bg = bg; + _vt_color_do(); +} + + +/** Send reset command */ +inline void _vt_reset_attribs_do() +{ + uart_puts_pgm(PSTR("\x1B[m")); // reset +} + + +/** Send commands for text attribs */ +void _vt_style_do() +{ + if (current_style.flags & VT_BOLD) { + uart_puts_pgm(PSTR("\x1B[1m")); + } + + if (current_style.flags & VT_FAINT) { + uart_puts_pgm(PSTR("\x1B[2m")); } - if (flags & VT_UNDERLINE) { - uart_puts("\x1B[4m"); + if (current_style.flags & VT_ITALIC) { + uart_puts_pgm(PSTR("\x1B[3m")); } - if (flags & VT_BLINK) { - uart_puts("\x1B[5m"); + if (current_style.flags & VT_UNDERLINE) { + uart_puts_pgm(PSTR("\x1B[4m")); } - if (flags & VT_REVERSE) { - uart_puts("\x1B[7m"); + if (current_style.flags & VT_BLINK) { + uart_puts_pgm(PSTR("\x1B[5m")); } - if (flags & VT_HIDDEN) { - uart_puts("\x1B[8m"); + if (current_style.flags & VT_REVERSE) { + uart_puts_pgm(PSTR("\x1B[7m")); } } -void vt_color(uint8_t fg, uint8_t bg) +/** Send commands for xolor */ +void _vt_color_do() { uart_putc(27); uart_putc('['); - uart_putu(fg); + uart_put8u(30 + current_style.fg); uart_putc(';'); - uart_putu(bg); + uart_put8u(40 + current_style.bg); uart_putc('m'); } +/** Insert blank lines febore the current line */ +void vt_insert_lines(uint8_t count) +{ + uart_putc(27); + uart_putc('['); + uart_put8u(count); + uart_putc('L'); +} + + +/** Delete lines from the current line down */ +void vt_delete_lines(uint8_t count) +{ + uart_putc(27); + uart_putc('['); + uart_put8u(count); + uart_putc('M'); +} + + +/** Insert empty characters at cursor */ +void vt_insert_chars(uint8_t count) +{ + uart_putc(27); + uart_putc('['); + uart_put8u(count); + uart_putc('@'); +} + + +/** Delete characters at cursor */ +void vt_delete_chars(uint8_t count) +{ + uart_putc(27); + uart_putc('['); + uart_put8u(count); + uart_putc('P'); +} + + void vt_clear() { - uart_puts("\x1B[2J"); + uart_puts_pgm(PSTR("\x1B[2J")); +} + + +void vt_erase_forth() +{ + uart_puts_pgm(PSTR("\x1B[K")); +} + + +void vt_erase_back() +{ + uart_puts_pgm(PSTR("\x1B[1K")); +} + + +void vt_erase_line() +{ + uart_puts_pgm(PSTR("\x1B[2K")); +} + + +void vt_erase_above() +{ + uart_puts_pgm(PSTR("\x1B[1J")); +} + +void vt_erase_below() +{ + uart_puts_pgm(PSTR("\x1B[J")); } void vt_home() { - uart_puts("\x1B[H"); + uart_puts_pgm(PSTR("\x1B[H")); +} + + +/** Initialize helper variables */ +void vt_init() +{ + vt_reset(); +} + + +/** Reset state and clear screen */ +void vt_reset() +{ + // reset color and attributes + vt_color_reset(); + vt_attr_reset(); + vt_scroll_reset(); + + // clear screen + vt_clear(); + + // go to top left + vt_home(); + + // overwrite saved state + vt_save(); } diff --git a/lib/uart_ansi.h b/lib/uart_ansi.h index bab86e0..9042420 100644 --- a/lib/uart_ansi.h +++ b/lib/uart_ansi.h @@ -3,60 +3,162 @@ // // ANSI / VT100 utilities for UART // +// To use this, first call uart_init(baud) and vt_init() +// To print stuff on the screen, use uart_puts() etc from uart.h +// #include #include #include #include "uart.h" -#define VT_NORMAL 0 -#define VT_BOLD 1 -#define VT_UNDERLINE 2 -#define VT_BLINK 4 -#define VT_REVERSE 8 -#define VT_HIDDEN 16 + + +// INIT + +/** Initialize helper variables */ +void vt_init(); + +/** Reset state and clear screen */ +void vt_reset(); + + + +// CURSOR MOVE + +/** Move cursor to top left corner */ +void vt_home(); /** Jump to a location on the screen */ -void vt_goto(uint16_t x, uint16_t y); +void vt_goto(uint8_t x, uint8_t y); + +/** Jump to given X, keep Y */ +void vt_goto_x(uint8_t x); + +/** Jump to given Y, keep X */ +void vt_goto_y(uint8_t y); /** Move cursor relative to current location */ -void vt_move(int16_t x, int16_t y); +void vt_move(int8_t x, int8_t y); /** Move cursor horizontally */ -void vt_move_x(int16_t x); +void vt_move_x(int8_t x); /** Move cursor vertically */ -void vt_move_y(int16_t y); +void vt_move_y(int8_t y); /** Move cursor up y cells */ -void vt_up(uint16_t y); +void vt_up(uint8_t y); /** Move cursor down y cells */ -void vt_down(uint16_t y); +void vt_down(uint8_t y); /** Move cursor left x cells */ -void vt_left(uint16_t x); +void vt_left(uint8_t x); /** Move cursor right x cells */ -void vt_right(uint16_t x); +void vt_right(uint8_t x); + + + +// SCROLLING /** Scroll y lines down (like up/down, but moves window if needed) */ -void vt_scroll(int16_t down); +void vt_scroll(int8_t down); + +/** Set scrolling region (lines) */ +void vt_scroll_set(uint8_t from, uint8_t to); + -/** Set font style */ -void vt_style(uint8_t flags); +/** Sets scrolling region to the entire screen. */ +void vt_scroll_reset(); -/** Set color */ + +// COLOR + +#define VT_BLACK 0 +#define VT_RED 1 +#define VT_GREEN 2 +#define VT_YELLOW 3 +#define VT_BLUE 4 +#define VT_MAGENTA 5 +#define VT_CYAN 6 +#define VT_WHITE 7 + +/** Set color 0..7 */ void vt_color(uint8_t fg, uint8_t bg); +/** Set FG color 0..7 */ +void vt_color_fg(uint8_t fg); + +/** Set BG color 0..7 */ +void vt_color_bg(uint8_t bg); + +/** Set color to white on black */ +void vt_color_reset(); + + + +// STYLES + +#define VT_BOLD 1 +#define VT_UNDERLINE 2 +#define VT_BLINK 4 +#define VT_REVERSE 8 +#define VT_ITALIC 16 +#define VT_FAINT 32 + +/** Enable or disable a text attribute */ +void vt_attr(uint8_t attribute, bool on); + +/** Disable all text attributes (excluding color) */ +void vt_attr_reset(); + + + +// SAVE & RESTORE + /** Save cursor position & text attributes */ void vt_save(); /** Restore cursor to saved values */ void vt_restore(); + + +// MODIFY + + +/** Insert blank lines febore the current line */ +void vt_insert_lines(uint8_t count); + +/** Delete lines from the current line down */ +void vt_delete_lines(uint8_t count); + +/** Insert empty characters at cursor */ +void vt_insert_chars(uint8_t count); + +/** Delete characters at cursor */ +void vt_delete_chars(uint8_t count); + + + +// ERASING + /** Clear the screen */ void vt_clear(); -/** Move cursor to top left corner */ -void vt_home(); +/** Erase to the end of line */ +void vt_erase_forth(); + +/** Erase line to cursor */ +void vt_erase_back(); + +/** Erase entire line */ +void vt_erase_line(); + +/** Erase screen below the line */ +void vt_erase_above(); + +/** Erase screen above the line */ +void vt_erase_below();