|
|
|
@ -1,30 +1,54 @@ |
|
|
|
|
#include <avr/io.h> |
|
|
|
|
#include <avr/pgmspace.h> |
|
|
|
|
#include <stdbool.h> |
|
|
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
|
|
#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(); |
|
|
|
|
} |
|
|
|
|