parent
							
								
									32c1be7e54
								
							
						
					
					
						commit
						72964684e4
					
				| @ -1,19 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| //
 | ||||
| // HSL support (addition to colors.h)
 | ||||
| //
 | ||||
| 
 | ||||
| #include "colors.h" | ||||
| 
 | ||||
| // Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
 | ||||
| 
 | ||||
| // HSL data structure
 | ||||
| typedef struct { | ||||
| 	uint8_t h; | ||||
| 	uint8_t s; | ||||
| 	uint8_t l; | ||||
| } hsl_t; | ||||
| 
 | ||||
| /* Convert HSL to XRGB */ | ||||
| xrgb_t hsl2xrgb(const hsl_t color); | ||||
| @ -1,581 +0,0 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/pgmspace.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "uart.h" | ||||
| #include "uart_ansi.h" | ||||
| #include "stream.h" | ||||
| 
 | ||||
| void _vt_apply_style(); | ||||
| void _vt_reset_attribs_do(); | ||||
| void _vt_style_do(); | ||||
| void _vt_color_do(); | ||||
| 
 | ||||
| 
 | ||||
| void vt_goto(uint8_t x, uint8_t y) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, y+1); // one-based !
 | ||||
| 	uart_tx(';'); | ||||
| 	put_u8(uart, x+1); | ||||
| 	uart_tx('H'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_goto_x(uint8_t x) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, x+1); | ||||
| 	uart_tx('`'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_goto_y(uint8_t y) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, y+1); | ||||
| 	uart_tx('d'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_move(int8_t x, int8_t y) | ||||
| { | ||||
| 	vt_move_x(x); | ||||
| 	vt_move_y(y); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_move_x(int8_t x) | ||||
| { | ||||
| 	if (x < 0) { | ||||
| 		vt_left(-x); | ||||
| 	} else { | ||||
| 		vt_right(x); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_move_y(int8_t y) | ||||
| { | ||||
| 	if (y < 0) { | ||||
| 		vt_up(-y); | ||||
| 	} else { | ||||
| 		vt_down(y); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_up(uint8_t y) | ||||
| { | ||||
| 	if (y == 0) return; | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, y); | ||||
| 	uart_tx('A'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_down(uint8_t y) | ||||
| { | ||||
| 	if (y == 0) return; | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, y); | ||||
| 	uart_tx('B'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_left(uint8_t x) | ||||
| { | ||||
| 	if (x == 0) return; | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, x); | ||||
| 	uart_tx('D'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_right(uint8_t x) | ||||
| { | ||||
| 	if (x == 0) return; | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, x); | ||||
| 	uart_tx('C'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_scroll(int8_t y) | ||||
| { | ||||
| 	while (y < 0) { | ||||
| 		uart_tx(27); | ||||
| 		uart_tx('D'); // up
 | ||||
| 		y++; | ||||
| 	} | ||||
| 
 | ||||
| 	while (y > 0) { | ||||
| 		uart_tx(27); | ||||
| 		uart_tx('M'); // down
 | ||||
| 		y--; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_scroll_set(uint8_t from, uint8_t to) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, from); | ||||
| 	uart_tx(';'); | ||||
| 	put_u8(uart, to); | ||||
| 	uart_tx('r'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_scroll_reset() | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	uart_tx('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_P(PSTR("\x1B[s")); | ||||
| 
 | ||||
| 	saved_style = current_style; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_restore() | ||||
| { | ||||
| 	uart_puts_P(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; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	_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_P(PSTR("\x1B[m")); // reset
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Send commands for text attribs */ | ||||
| void _vt_style_do() | ||||
| { | ||||
| 	if (current_style.flags & VT_BOLD) { | ||||
| 		uart_puts_P(PSTR("\x1B[1m")); | ||||
| 	} | ||||
| 
 | ||||
| 	if (current_style.flags & VT_FAINT) { | ||||
| 		uart_puts_P(PSTR("\x1B[2m")); | ||||
| 	} | ||||
| 
 | ||||
| 	if (current_style.flags & VT_ITALIC) { | ||||
| 		uart_puts_P(PSTR("\x1B[3m")); | ||||
| 	} | ||||
| 
 | ||||
| 	if (current_style.flags & VT_UNDERLINE) { | ||||
| 		uart_puts_P(PSTR("\x1B[4m")); | ||||
| 	} | ||||
| 
 | ||||
| 	if (current_style.flags & VT_BLINK) { | ||||
| 		uart_puts_P(PSTR("\x1B[5m")); | ||||
| 	} | ||||
| 
 | ||||
| 	if (current_style.flags & VT_REVERSE) { | ||||
| 		uart_puts_P(PSTR("\x1B[7m")); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Send commands for xolor */ | ||||
| void _vt_color_do() | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, 30 + current_style.fg); | ||||
| 	uart_tx(';'); | ||||
| 	put_u8(uart, 40 + current_style.bg); | ||||
| 	uart_tx('m'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Insert blank lines febore the current line */ | ||||
| void vt_insert_lines(uint8_t count) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, count); | ||||
| 	uart_tx('L'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Delete lines from the current line down */ | ||||
| void vt_delete_lines(uint8_t count) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, count); | ||||
| 	uart_tx('M'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Insert empty characters at cursor */ | ||||
| void vt_insert_chars(uint8_t count) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, count); | ||||
| 	uart_tx('@'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Delete characters at cursor */ | ||||
| void vt_delete_chars(uint8_t count) | ||||
| { | ||||
| 	uart_tx(27); | ||||
| 	uart_tx('['); | ||||
| 	put_u8(uart, count); | ||||
| 	uart_tx('P'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_clear() | ||||
| { | ||||
| 	uart_puts_P(PSTR("\x1B[2J")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_erase_forth() | ||||
| { | ||||
| 	uart_puts_P(PSTR("\x1B[K")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_erase_back() | ||||
| { | ||||
| 	uart_puts_P(PSTR("\x1B[1K")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_erase_line() | ||||
| { | ||||
| 	uart_puts_P(PSTR("\x1B[2K")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_erase_above() | ||||
| { | ||||
| 	uart_puts_P(PSTR("\x1B[1J")); | ||||
| } | ||||
| 
 | ||||
| void vt_erase_below() | ||||
| { | ||||
| 	uart_puts_P(PSTR("\x1B[J")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void vt_home() | ||||
| { | ||||
| 	uart_puts_P(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(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Assigned keyhandler
 | ||||
| void (*_vt_kh)(uint8_t, bool) = NULL; | ||||
| 
 | ||||
| /** Assign a key handler (later used with vt_handle_key) */ | ||||
| void vt_set_key_handler(void (*handler)(uint8_t, bool)) | ||||
| { | ||||
| 	_vt_kh = handler; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // state machine states
 | ||||
| typedef enum { | ||||
| 	GROUND = 0, | ||||
| 	ESC = 1, | ||||
| 	BR = 2, | ||||
| 	O = 3, | ||||
| 	WAITING_TILDE = 4 | ||||
| } KSTATE; | ||||
| 
 | ||||
| // code received before started to wait for a tilde
 | ||||
| uint8_t _before_wtilde; | ||||
| // current state
 | ||||
| KSTATE _kstate = GROUND; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void _vt_kh_abort() | ||||
| { | ||||
| 	switch (_kstate) { | ||||
| 		case ESC: | ||||
| 			_vt_kh(VK_ESC, true); | ||||
| 			break; | ||||
| 
 | ||||
| 		case BR: | ||||
| 			_vt_kh(VK_ESC, true); | ||||
| 			_vt_kh('[', false); | ||||
| 			break; | ||||
| 
 | ||||
| 		case O: | ||||
| 			_vt_kh(VK_ESC, true); | ||||
| 			_vt_kh('O', false); | ||||
| 			break; | ||||
| 
 | ||||
| 		case WAITING_TILDE: | ||||
| 			_vt_kh(VK_ESC, true); | ||||
| 			_vt_kh('[', false); | ||||
| 			vt_handle_key(_before_wtilde); | ||||
| 			break; | ||||
| 
 | ||||
| 		case GROUND: | ||||
| 			// nop
 | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	_kstate = GROUND; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Handle a key received over UART | ||||
|  * Takes care of multi-byte keys and translates them to special | ||||
|  * constants. | ||||
|  */ | ||||
| void vt_handle_key(uint8_t c) | ||||
| { | ||||
| 	if (_vt_kh == NULL) return; | ||||
| 
 | ||||
| 	switch (_kstate) { | ||||
| 		case GROUND: | ||||
| 			switch (c) { | ||||
| 				case 27: | ||||
| 					_kstate = ESC; | ||||
| 					break; | ||||
| 
 | ||||
| 				case VK_ENTER: | ||||
| 				case VK_TAB: | ||||
| 				case VK_BACKSPACE: | ||||
| 					_vt_kh(c, true); | ||||
| 					return; | ||||
| 
 | ||||
| 				default: | ||||
| 					_vt_kh(c, false); | ||||
| 					return; | ||||
| 			} | ||||
| 
 | ||||
| 			break;  // continue to next char
 | ||||
| 
 | ||||
| 		case ESC: | ||||
| 			switch (c) { | ||||
| 				case '[': | ||||
| 					_kstate = BR; | ||||
| 					break; // continue to next char
 | ||||
| 
 | ||||
| 				case 'O': | ||||
| 					_kstate = O; | ||||
| 					break; // continue to next char
 | ||||
| 
 | ||||
| 				default: | ||||
| 					// bad code
 | ||||
| 					_vt_kh_abort(); | ||||
| 					vt_handle_key(c); | ||||
| 					return; | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case BR: | ||||
| 			switch (c) { | ||||
| 				// arrows
 | ||||
| 				case 65: | ||||
| 				case 66: | ||||
| 				case 67: | ||||
| 				case 68: | ||||
| 					_vt_kh(c, true); | ||||
| 					_kstate = GROUND; | ||||
| 					return; | ||||
| 
 | ||||
| 				// ins del pgup pgdn
 | ||||
| 				case 50: | ||||
| 				case 51: | ||||
| 				case 53: | ||||
| 				case 54: | ||||
| 					// wait for terminating tilde
 | ||||
| 					_before_wtilde = c; | ||||
| 					_kstate = WAITING_TILDE; | ||||
| 					break; // continue to next char
 | ||||
| 
 | ||||
| 				// bad key
 | ||||
| 				default: | ||||
| 					_vt_kh_abort(); | ||||
| 					vt_handle_key(c); | ||||
| 					return; | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case O: | ||||
| 			switch (c) { | ||||
| 				// F keys
 | ||||
| 				case 80: | ||||
| 				case 81: | ||||
| 				case 82: | ||||
| 				case 83: | ||||
| 				// home, end
 | ||||
| 				case 72: | ||||
| 				case 70: | ||||
| 					_vt_kh(c, true); | ||||
| 					_kstate = GROUND; | ||||
| 					return; | ||||
| 
 | ||||
| 				// bad key
 | ||||
| 				default: | ||||
| 					_vt_kh_abort(); | ||||
| 					vt_handle_key(c); | ||||
| 					return; | ||||
| 			} | ||||
| 
 | ||||
| 		case WAITING_TILDE: | ||||
| 			if (c != '~') { | ||||
| 				_vt_kh_abort(); | ||||
| 				vt_handle_key(c); | ||||
| 				return; | ||||
| 			} else { | ||||
| 				_vt_kh(_before_wtilde, true); | ||||
| 				_kstate = GROUND; | ||||
| 				return; | ||||
| 			} | ||||
| 	} | ||||
| 
 | ||||
| 	// wait for next key
 | ||||
| 	if (_kstate != GROUND) { | ||||
| 		_delay_ms(2); | ||||
| 		if (!uart_rx_ready()) { | ||||
| 			// abort receiving
 | ||||
| 			_vt_kh_abort(); | ||||
| 
 | ||||
| 		} else { | ||||
| 			vt_handle_key(uart_rx()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -1,192 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| //
 | ||||
| // 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 <avr/io.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include "uart.h" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // 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(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(int8_t x, int8_t y); | ||||
| 
 | ||||
| /** Move cursor horizontally */ | ||||
| void vt_move_x(int8_t x); | ||||
| 
 | ||||
| /** Move cursor vertically */ | ||||
| void vt_move_y(int8_t y); | ||||
| 
 | ||||
| /** Move cursor up y cells */ | ||||
| void vt_up(uint8_t y); | ||||
| 
 | ||||
| /** Move cursor down y cells */ | ||||
| void vt_down(uint8_t y); | ||||
| 
 | ||||
| /** Move cursor left x cells */ | ||||
| void vt_left(uint8_t x); | ||||
| 
 | ||||
| /** Move cursor right x cells */ | ||||
| void vt_right(uint8_t x); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // SCROLLING
 | ||||
| 
 | ||||
| /** Scroll y lines down (like up/down, but moves window if needed) */ | ||||
| void vt_scroll(int8_t down); | ||||
| 
 | ||||
| /** Set scrolling region (lines) */ | ||||
| void vt_scroll_set(uint8_t from, uint8_t to); | ||||
| 
 | ||||
| 
 | ||||
| /** Sets scrolling region to the entire screen. */ | ||||
| void vt_scroll_reset(); | ||||
| 
 | ||||
| 
 | ||||
| // 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(); | ||||
| 
 | ||||
| /** 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(); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // KEY HANDLER
 | ||||
| 
 | ||||
| // Special keys from key handler
 | ||||
| #define VK_LEFT   68 | ||||
| #define VK_RIGHT  67 | ||||
| #define VK_UP     65 | ||||
| #define VK_DOWN   66 | ||||
| #define VK_DELETE 51 | ||||
| #define VK_INSERT 50 | ||||
| #define VK_PGUP   53 | ||||
| #define VK_PGDN   54 | ||||
| #define VK_HOME   72 | ||||
| #define VK_END    70 | ||||
| #define VK_F1 80 | ||||
| #define VK_F2 81 | ||||
| #define VK_F3 82 | ||||
| #define VK_F4 83 | ||||
| #define VK_BACKSPACE  8 | ||||
| #define VK_TAB        9 | ||||
| #define VK_ENTER     13 | ||||
| #define VK_ESC       27 | ||||
| 
 | ||||
| void vt_handle_key(uint8_t c); | ||||
| void vt_set_key_handler(void (*handler)(uint8_t, bool)); | ||||
| @ -1,126 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| //
 | ||||
| //  Utils for driving a WS28xx (tested on WS2812B) RGB LED strips.
 | ||||
| //
 | ||||
| //  It's implemented as macros to avoid overhead when passing values, and to
 | ||||
| //  enable driving multiple strips at once.
 | ||||
| //
 | ||||
| //  To avoid bloating your code, try to reduce the number of invocations -
 | ||||
| //  compute color and then send it.
 | ||||
| //
 | ||||
| //  [IMPORTANT]
 | ||||
| //
 | ||||
| //  Some seemingly random influences can ruin the communication.
 | ||||
| //  If you have enough memory, consider preparing the colors in array,
 | ||||
| //  and sending this array using one of the "ws_send_XXX_array" macros.
 | ||||
| //
 | ||||
| 
 | ||||
| #include <avr/io.h> | ||||
| 
 | ||||
| #include "iopins.h" | ||||
| #include "nsdelay.h" | ||||
| #include "colors.h" | ||||
| 
 | ||||
| /* Driver code for WS2812B */ | ||||
| 
 | ||||
| // --- timing constraints (NS) ---
 | ||||
| 
 | ||||
| #ifndef WS_T_1H | ||||
| # define WS_T_1H  700 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WS_T_1L | ||||
| # define WS_T_1L  150 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WS_T_0H | ||||
| # define WS_T_0H  150 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WS_T_0L | ||||
| # define WS_T_0L  700 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WS_T_LATCH | ||||
| # define WS_T_LATCH 7000 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| /** Wait long enough for the colors to show */ | ||||
| #define ws_show() do {delay_ns_c(WS_T_LATCH, 0); } while(0) | ||||
| 
 | ||||
| 
 | ||||
| /** Send one byte to the RGB strip */ | ||||
| #define ws_send_byte(io, bb) do {										\ | ||||
| 	for (volatile int8_t __ws_tmp = 7; __ws_tmp >= 0; --__ws_tmp) {		\
 | ||||
| 		if ((bb) & (1 << __ws_tmp)) {									\
 | ||||
| 			set_high(io); delay_ns_c(WS_T_1H, -2);				\
 | ||||
| 			set_low(io); delay_ns_c(WS_T_1L, -10);				\
 | ||||
| 		} else {														\
 | ||||
| 			set_high(io); delay_ns_c(WS_T_0H, -2);				\
 | ||||
| 			set_low(io); delay_ns_c(WS_T_0L, -10);				\
 | ||||
| 		}																\
 | ||||
| 	}																	\
 | ||||
| } while(0) | ||||
| 
 | ||||
| 
 | ||||
| /** Send R,G,B color to the strip */ | ||||
| #define ws_send_rgb(io, r, g, b) do {			\ | ||||
| 	ws_send_byte(io, g);				\
 | ||||
| 	ws_send_byte(io, r);				\
 | ||||
| 	ws_send_byte(io, b);				\
 | ||||
| } while(0) | ||||
| 
 | ||||
| /** Send a RGB struct */ | ||||
| #define ws_send_xrgb(io, xrgb) ws_send_rgb(io, (xrgb).r, (xrgb).g, (xrgb).b) | ||||
| 
 | ||||
| /** Send color hex */ | ||||
| #define ws_send_rgb24(io, rgb) ws_send_rgb(io, rgb24_r(rgb), rgb24_g(rgb), rgb24_b(rgb)) | ||||
| #define ws_send_rgb15(io, rgb) ws_send_rgb(io, rgb15_r(rgb), rgb15_g(rgb), rgb15_b(rgb)) | ||||
| #define ws_send_rgb12(io, rgb) ws_send_rgb(io, rgb12_r(rgb), rgb12_g(rgb), rgb12_b(rgb)) | ||||
| #define ws_send_rgb6(io, rgb)  ws_send_rgb(io, rgb6_r(rgb),  rgb6_g(rgb),  rgb6_b(rgb)) | ||||
| 
 | ||||
| /** Send array of colors */ | ||||
| #define ws_send_xrgb_array(io, rgbs, length) __ws_send_array_proto(io, (rgbs), (length), xrgb) | ||||
| #define ws_send_rgb24_array(io, rgbs, length) __ws_send_array_proto(io, (rgbs), (length), rgb24) | ||||
| #define ws_send_rgb15_array(io, rgbs, length) __ws_send_array_proto(io, (rgbs), (length), rgb15) | ||||
| #define ws_send_rgb12_array(io, rgbs, length) __ws_send_array_proto(io, (rgbs), (length), rgb12) | ||||
| #define ws_send_rgb6_array(io, rgbs, length) __ws_send_array_proto(io, (rgbs), (length), rgb6) | ||||
| 
 | ||||
| // prototype for sending array. it's ugly, sorry.
 | ||||
| #define __ws_send_array_proto(io, rgbs, length, style) do {						\ | ||||
| 	for (uint8_t __ws_sap_i = 0; __ws_sap_i < length; __ws_sap_i++) {			\
 | ||||
| 		style ## _t __ws_sap2 = (rgbs)[__ws_sap_i];								\
 | ||||
| 		ws_send_ ## style(io, __ws_sap2);								\
 | ||||
| 	}																			\
 | ||||
| } while(0) | ||||
| 
 | ||||
| /** Send a 2D array to a zig-zag display */ | ||||
| #define ws_send_xrgb_array_zigzag(io, rgbs, width, height) do {				\ | ||||
| 	int8_t __ws_sxaz_y, __ws_sxaz_x;										\
 | ||||
| 	for(__ws_sxaz_y = 0; __ws_sxaz_y < (height); __ws_sxaz_y ++) {			\
 | ||||
| 		for(__ws_sxaz_x = 0; __ws_sxaz_x < (width); __ws_sxaz_x++) {		\
 | ||||
| 			ws_send_xrgb(io, (rgbs)[__ws_sxaz_y][__ws_sxaz_x]);	\
 | ||||
| 		}																	\
 | ||||
| 		__ws_sxaz_y++;														\
 | ||||
| 		for(__ws_sxaz_x = (width) - 1; __ws_sxaz_x >= 0; __ws_sxaz_x--) {	\
 | ||||
| 			ws_send_xrgb(io, (rgbs)[__ws_sxaz_y][__ws_sxaz_x]);	\
 | ||||
| 		}																	\
 | ||||
| 	}																		\
 | ||||
| } while(0) | ||||
| 
 | ||||
| 
 | ||||
| /** Send a linear array to a zig-zag display as a n*m board (row-by-row) */ | ||||
| #define ws_send_xrgb_array_zigzag_linear(io, rgbs, width, height) do {					\ | ||||
| 	int8_t __ws_sxazl_x, __ws_sxazl_y;													\
 | ||||
| 	for(__ws_sxazl_y = 0; __ws_sxazl_y < (height); __ws_sxazl_y++) {					\
 | ||||
| 		for(__ws_sxazl_x = 0; __ws_sxazl_x < (width); __ws_sxazl_x++) {					\
 | ||||
| 			ws_send_xrgb(io, (rgbs)[__ws_sxazl_y * (width) + __ws_sxazl_x]);	\
 | ||||
| 		}																				\
 | ||||
| 		__ws_sxazl_y++;																	\
 | ||||
| 		for(__ws_sxazl_x = width-1; __ws_sxazl_x >=0; __ws_sxazl_x--) {					\
 | ||||
| 			ws_send_xrgb(io, (rgbs)[__ws_sxazl_y * (width) + __ws_sxazl_x]);	\
 | ||||
| 		}																				\
 | ||||
| 	}																					\
 | ||||
| } while(0) | ||||
| @ -0,0 +1,132 @@ | ||||
| #include <avr/io.h> | ||||
| #include <util/delay.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "iopins.h" | ||||
| #include "nsdelay.h" | ||||
| 
 | ||||
| #include "wsrgb.h" | ||||
| #include "color.h" | ||||
| #include "ws_config.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Driver code for WS2812B */ | ||||
| 
 | ||||
| void ws_init() | ||||
| { | ||||
| 	as_output(WS_PIN); | ||||
| } | ||||
| 
 | ||||
| /** Wait long enough for the colors to show */ | ||||
| void ws_show() { | ||||
| 	delay_ns_c(WS_T_LATCH, 0); | ||||
| } | ||||
| 
 | ||||
| /** Send one byte to the RGB strip */ | ||||
| void ws_send_byte(const uint8_t bb) | ||||
| { | ||||
| 	for (volatile int8_t i = 7; i >= 0; --i) { | ||||
| 		if ((bb) & (1 << i)) { | ||||
| 			set_high(WS_PIN); | ||||
| 			delay_ns_c(WS_T_1H, -2); | ||||
| 
 | ||||
| 			set_low(WS_PIN); | ||||
| 			delay_ns_c(WS_T_1L, -10); | ||||
| 		} else { | ||||
| 			set_high(WS_PIN); | ||||
| 			delay_ns_c(WS_T_0H, -2); | ||||
| 
 | ||||
| 			set_low(WS_PIN); | ||||
| 			delay_ns_c(WS_T_0L, -10); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Send R,G,B color to the strip */ | ||||
| void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b) | ||||
| { | ||||
| 	ws_send_byte(g); | ||||
| 	ws_send_byte(r); | ||||
| 	ws_send_byte(b); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Send a RGB struct */ | ||||
| void ws_send_xrgb(xrgb_t xrgb) | ||||
| { | ||||
| 	ws_send_byte(xrgb.g); | ||||
| 	ws_send_byte(xrgb.r); | ||||
| 	ws_send_byte(xrgb.b); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Send color hex */ | ||||
| void ws_send_rgb24(rgb24_t rgb) | ||||
| { | ||||
| 	ws_send_byte(rgb24_g(rgb)); | ||||
| 	ws_send_byte(rgb24_r(rgb)); | ||||
| 	ws_send_byte(rgb24_b(rgb)); | ||||
| } | ||||
| 
 | ||||
| /** Send array of colors */ | ||||
| void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length) | ||||
| { | ||||
| 	for (uint8_t i = 0; i < length; i++) { | ||||
| 		const xrgb_t c = rgbs[i]; | ||||
| 		ws_send_byte(c.g); | ||||
| 		ws_send_byte(c.r); | ||||
| 		ws_send_byte(c.b); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** Send array of colors */ | ||||
| void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length) | ||||
| { | ||||
| 	for (uint8_t i = 0; i < length; i++) { | ||||
| 		const rgb24_t c = rgbs[i]; | ||||
| 		ws_send_byte(rgb24_g(c)); | ||||
| 		ws_send_byte(rgb24_r(c)); | ||||
| 		ws_send_byte(rgb24_b(c)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| //#define ws_send_rgb24_array(rgbs, length) __ws_send_array_proto((rgbs), (length), rgb24)
 | ||||
| 
 | ||||
| // prototype for sending array. it's ugly, sorry.
 | ||||
| /*#define __ws_send_array_proto(rgbs, length, style) {						\
 | ||||
| 	for (uint8_t __rgb_sap_i = 0; __rgb_sap_i < length; __rgb_sap_i++) {			\
 | ||||
| 		style ## _t __rgb_sap2 = (rgbs)[__rgb_sap_i];								\
 | ||||
| 		ws_send_ ## style(__rgb_sap2);								\
 | ||||
| 	}																			\
 | ||||
| }*/ | ||||
| 
 | ||||
| 
 | ||||
| // /** Send a 2D array to a zig-zag display */
 | ||||
| // #define ws_send_xrgb_array_zigzag(rgbs, width, height) {				\
 | ||||
| // 	int8_t __rgb_sxaz_y, __rgb_sxaz_x;										\
 | ||||
| // 	for(__rgb_sxaz_y = 0; __rgb_sxaz_y < (height); __rgb_sxaz_y ++) {			\
 | ||||
| // 		for(__rgb_sxaz_x = 0; __rgb_sxaz_x < (width); __rgb_sxaz_x++) {		\
 | ||||
| // 			ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]);	\
 | ||||
| // 		}																	\
 | ||||
| // 		__rgb_sxaz_y++;														\
 | ||||
| // 		for(__rgb_sxaz_x = (width) - 1; __rgb_sxaz_x >= 0; __rgb_sxaz_x--) {	\
 | ||||
| // 			ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]);	\
 | ||||
| // 		}																	\
 | ||||
| // 	}																		\
 | ||||
| // }
 | ||||
| 
 | ||||
| 
 | ||||
| // /* Send a linear array to a zig-zag display as a n*m board (row-by-row)
 | ||||
| // #define ws_send_xrgb_array_zigzag_linear(rgbs, width, height) {					\
 | ||||
| // 	int8_t __rgb_sxazl_x, __rgb_sxazl_y;													\
 | ||||
| // 	for(__rgb_sxazl_y = 0; __rgb_sxazl_y < (height); __rgb_sxazl_y++) {					\
 | ||||
| // 		for(__rgb_sxazl_x = 0; __rgb_sxazl_x < (width); __rgb_sxazl_x++) {					\
 | ||||
| // 			ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]);	\
 | ||||
| // 		}																				\
 | ||||
| // 		__rgb_sxazl_y++;																	\
 | ||||
| // 		for(__rgb_sxazl_x = width-1; __rgb_sxazl_x >=0; __rgb_sxazl_x--) {					\
 | ||||
| // 			ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]);	\
 | ||||
| // 		}																				\
 | ||||
| // 	}																					\
 | ||||
| // }
 | ||||
| @ -0,0 +1,51 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| //
 | ||||
| // Utils for driving a WS2812 RGB LED strips, and color manipulation in general.
 | ||||
| //
 | ||||
| // Timing is critical!
 | ||||
| //
 | ||||
| // Create a config file rgb_config.h next to your main.c
 | ||||
| //
 | ||||
| 
 | ||||
| #include "iopins.h" | ||||
| #include "color.h" | ||||
| 
 | ||||
| // Your config file
 | ||||
| #include "ws_config.h" | ||||
| 
 | ||||
| /*
 | ||||
| 	#define WS_T_1H  700 | ||||
| 	#define WS_T_1L  150 | ||||
| 	#define WS_T_0H  150 | ||||
| 	#define WS_T_0L  700 | ||||
| 	#define WS_T_LATCH 7000 | ||||
| 	#define WS_PIN 2 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| // --- functions for RGB strips ---
 | ||||
| 
 | ||||
| /** Initialize OI */ | ||||
| void ws_init(); | ||||
| 
 | ||||
| /** Wait long enough for the colors to show */ | ||||
| void ws_show(); | ||||
| 
 | ||||
| /** Send one byte to the RGB strip */ | ||||
| void ws_send_byte(const uint8_t bb); | ||||
| 
 | ||||
| /** Send R,G,B color to the strip */ | ||||
| void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b); | ||||
| 
 | ||||
| /** Send a RGB struct */ | ||||
| void ws_send_xrgb(xrgb_t xrgb); | ||||
| 
 | ||||
| /** Send color hex */ | ||||
| void ws_send_rgb24(rgb24_t rgb); | ||||
| 
 | ||||
| /** Send array of colors */ | ||||
| void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length); | ||||
| 
 | ||||
| /** Send array of colors */ | ||||
| void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length); | ||||
					Loading…
					
					
				
		Reference in new issue