refactoring and cleaning
This commit is contained in:
+2
-2
@@ -11,14 +11,14 @@ EFUSE = 0x05
|
|||||||
|
|
||||||
## === Source files ===
|
## === Source files ===
|
||||||
# Main C file
|
# Main C file
|
||||||
MAIN = uart_isr.c
|
MAIN = sonar_to_lcd.c
|
||||||
# Extra C files in this folder
|
# Extra C files in this folder
|
||||||
LOCAL_SOURCE =
|
LOCAL_SOURCE =
|
||||||
|
|
||||||
# Library directory (with C files)
|
# Library directory (with C files)
|
||||||
EXTRA_SOURCE_DIR = lib/
|
EXTRA_SOURCE_DIR = lib/
|
||||||
# C files in the library directory
|
# C files in the library directory
|
||||||
EXTRA_SOURCE_FILES = uart.c lcd.c sonar.c uart_ansi.c stream.c
|
EXTRA_SOURCE_FILES = uart.c lcd.c sonar.c stream.c
|
||||||
|
|
||||||
|
|
||||||
## === Programmer ===
|
## === Programmer ===
|
||||||
|
|||||||
@@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
// Pin config file for LCD.
|
// Pin config file for LCD.
|
||||||
|
|
||||||
#include "lib/arduino_pins.h"
|
#define LCD_RS 2
|
||||||
|
#define LCD_RW 3
|
||||||
#define LCD_RS D2
|
#define LCD_E 4
|
||||||
#define LCD_RW D3
|
#define LCD_D4 5
|
||||||
#define LCD_E D4
|
#define LCD_D5 6
|
||||||
#define LCD_D4 D5
|
#define LCD_D6 7
|
||||||
#define LCD_D5 D6
|
#define LCD_D7 8
|
||||||
#define LCD_D6 D7
|
|
||||||
#define LCD_D7 D8
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "lib/arduino_pins.h"
|
#include "lib/iopins.h"
|
||||||
#include "lib/sonar.h"
|
#include "lib/sonar.h"
|
||||||
#include "lib/stream.h"
|
#include "lib/stream.h"
|
||||||
#include "lib/lcd.h"
|
#include "lib/lcd.h"
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "lib/uart.h"
|
#include "lib/uart.h"
|
||||||
#include "lib/uart_ansi.h"
|
|
||||||
#include "lib/stream.h"
|
#include "lib/stream.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
+10
-4
@@ -1,7 +1,13 @@
|
|||||||
#include <stdlib.h>
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "colors.h"
|
|
||||||
#include "hsl.h"
|
#include "iopins.h"
|
||||||
|
#include "nsdelay.h"
|
||||||
|
#include "color.h"
|
||||||
|
|
||||||
|
|
||||||
|
// --- HSL ---
|
||||||
|
|
||||||
#ifdef HSL_LINEAR
|
#ifdef HSL_LINEAR
|
||||||
const uint8_t FADE_128[] = {
|
const uint8_t FADE_128[] = {
|
||||||
@@ -17,7 +23,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// based on: https://github.com/lewisd32/avr-hsl2rgb
|
// based on: https://github.com/lewisd32/avr-hsl2rgb
|
||||||
xrgb_t hsl2xrgb(const hsl_t cc)
|
xrgb_t hsl_xrgb(const hsl_t cc)
|
||||||
{
|
{
|
||||||
// 0 .. 256*3
|
// 0 .. 256*3
|
||||||
const uint16_t hh = (uint16_t) cc.h * 3;
|
const uint16_t hh = (uint16_t) cc.h * 3;
|
||||||
+15
-44
@@ -1,15 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//
|
// --- color types ---
|
||||||
// Some useful utilities for RGB color manipulation
|
|
||||||
//
|
//
|
||||||
// The XXXc macros don't use cast, so they can be used in array initializers.
|
// The XXXc macros don't use cast, so they can be used in array initializers.
|
||||||
//
|
//
|
||||||
// xrgb ... 3-byte true-color RGB (8 bits per component)
|
// xrgb ... 3-byte true-color RGB (8 bits per component)
|
||||||
// rgbXX ... XX-bit color value, with equal nr of bits per component
|
// rgb24 ... 24-bit color value, with equal nr of bits per component
|
||||||
//
|
//
|
||||||
// XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
|
// XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
|
||||||
//
|
|
||||||
|
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -18,11 +18,8 @@ typedef struct {
|
|||||||
uint8_t b;
|
uint8_t b;
|
||||||
} xrgb_t;
|
} xrgb_t;
|
||||||
|
|
||||||
typedef uint32_t rgb24_t;
|
|
||||||
typedef uint16_t rgb15_t;
|
|
||||||
typedef uint16_t rgb12_t;
|
|
||||||
typedef uint8_t rgb6_t;
|
|
||||||
|
|
||||||
|
typedef uint32_t rgb24_t;
|
||||||
|
|
||||||
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
|
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
|
||||||
// xrgb for constant array declarations
|
// xrgb for constant array declarations
|
||||||
@@ -35,7 +32,6 @@ typedef uint8_t rgb6_t;
|
|||||||
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
|
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
|
||||||
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
|
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
|
||||||
|
|
||||||
|
|
||||||
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
|
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
|
||||||
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
|
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
|
||||||
|
|
||||||
@@ -45,40 +41,15 @@ typedef uint8_t rgb6_t;
|
|||||||
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
|
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
|
||||||
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
|
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
|
||||||
|
|
||||||
|
|
||||||
#define rgb15(r,g,b) ((rgb15_t) rgb15c(r,g,b))
|
|
||||||
#define rgb15c(r,g,b) (((r & 0x1F) << 10) | ((g & 0x1F) << 5) | (b & 0x1F))
|
|
||||||
|
|
||||||
#define rgb15_r(c) ((((rgb15_t) (c)) & 0x7C00) >> 7)
|
|
||||||
#define rgb15_g(c) ((((rgb15_t) (c)) & 0x3E0) >> 2)
|
|
||||||
#define rgb15_b(c) ((((rgb15_t) (c)) & 0x1F) << 3)
|
|
||||||
#define rgb15_xrgb(c) xrgb(rgb15_r(c), rgb15_g(c), rgb15_b(c))
|
|
||||||
#define rgb15_rgb24(c) rgb24(rgb15_r(c), rgb15_g(c), rgb15_b(c))
|
|
||||||
#define rgb15_rgb24c(c) rgb24c(rgb15_r(c), rgb15_g(c), rgb15_b(c))
|
|
||||||
|
|
||||||
|
|
||||||
#define rgb12(r,g,b) ((rgb12_t) rgb12c(r,g,b))
|
|
||||||
#define rgb12c(r,g,b) (((r & 0xF) << 8) | ((g & 0xF) << 4) | (b & 0xF))
|
|
||||||
|
|
||||||
#define rgb12_r(c) ((((rgb12_t) (c)) & 0xF00) >> 4)
|
|
||||||
#define rgb12_g(c) (((rgb12_t) (c)) & 0xF0)
|
|
||||||
#define rgb12_b(c) (((r(rgb12_t) (c)gb) & 0x0F) << 4)
|
|
||||||
#define rgb12_xrgb(c) xrgb(rgb12_r(c), rgb12_g(c), rgb12_b(c))
|
|
||||||
#define rgb12_xrgbc(c) xrgbc(rgb12_r(c), rgb12_g(c), rgb12_b(c))
|
|
||||||
#define rgb12_rgb24(c) rgb24(rgb12_r(c), rgb12_g(c), rgb12_b(c))
|
|
||||||
#define rgb12_rgb24c(c) rgb24c(rgb12_r(c), rgb12_g(c), rgb12_b(c))
|
|
||||||
|
|
||||||
|
|
||||||
#define rgb6(r,g,b) ((rgb6_t) rgb6c(r,g,b))
|
|
||||||
#define rgb6c(r,g,b) (((r & 3) << 4) | ((g & 3) << 2) | (b & 3))
|
|
||||||
|
|
||||||
#define rgb6_r(c) ((((rgb6_t) (c)) & 0x30) << 2)
|
|
||||||
#define rgb6_g(c) ((((rgb6_t) (c)) & 0xC) << 4)
|
|
||||||
#define rgb6_b(c) ((((rgb6_t) (c)) & 0x3) << 6)
|
|
||||||
#define rgb6_xrgb(c) xrgb(rgb6_r(c), rgb6_g(c), rgb6_b(c))
|
|
||||||
#define rgb6_xrgbc(c) xrgbc(rgb6_r(c), rgb6_g(c), rgb6_b(c))
|
|
||||||
#define rgb6_rgb24(c) rgb24(rgb6_r(c), rgb6_g(c), rgb6_b(c))
|
|
||||||
#define rgb6_rgb24c(c) rgb24c(rgb6_r(c), rgb6_g(c), rgb6_b(c))
|
|
||||||
|
|
||||||
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
|
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
|
||||||
|
|
||||||
|
|
||||||
|
// HSL data structure
|
||||||
|
typedef struct {
|
||||||
|
uint8_t h;
|
||||||
|
uint8_t s;
|
||||||
|
uint8_t l;
|
||||||
|
} hsl_t;
|
||||||
|
|
||||||
|
/* Convert HSL to XRGB */
|
||||||
|
xrgb_t hsl_xrgb(const hsl_t color);
|
||||||
+7
-7
@@ -7,13 +7,6 @@
|
|||||||
//
|
//
|
||||||
// You must provide a config file debo_config.h (next to your main.c)
|
// You must provide a config file debo_config.h (next to your main.c)
|
||||||
//
|
//
|
||||||
// Example:
|
|
||||||
// #pragma once
|
|
||||||
// #define DEBO_CHANNELS 2
|
|
||||||
// #define DDEBO_TICKS 5
|
|
||||||
//
|
|
||||||
// ----
|
|
||||||
//
|
|
||||||
// A pin is registered like this:
|
// A pin is registered like this:
|
||||||
//
|
//
|
||||||
// #define BTN1 12 // pin D12
|
// #define BTN1 12 // pin D12
|
||||||
@@ -39,7 +32,14 @@
|
|||||||
|
|
||||||
#include "calc.h"
|
#include "calc.h"
|
||||||
#include "pins.h"
|
#include "pins.h"
|
||||||
|
|
||||||
|
// Your config file
|
||||||
#include "debo_config.h"
|
#include "debo_config.h"
|
||||||
|
/*
|
||||||
|
#define DEBO_CHANNELS 2
|
||||||
|
#define DDEBO_TICKS 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Internal deboucer entry */
|
/* Internal deboucer entry */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
|
||||||
#include "calc.h"
|
#include "calc.h"
|
||||||
#include "pins.h"
|
#include "iopins.h"
|
||||||
#include "nsdelay.h"
|
#include "nsdelay.h"
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
#include "lcd_config.h"
|
#include "lcd_config.h"
|
||||||
|
|||||||
@@ -7,15 +7,6 @@
|
|||||||
//
|
//
|
||||||
// Content can be something like this:
|
// Content can be something like this:
|
||||||
//
|
//
|
||||||
// #pragma once
|
|
||||||
// #include "lib/arduino_pins.h"
|
|
||||||
// #define LCD_RS D10
|
|
||||||
// #define LCD_RW D11
|
|
||||||
// #define LCD_E D12
|
|
||||||
// #define LCD_D4 D13
|
|
||||||
// #define LCD_D5 D14
|
|
||||||
// #define LCD_D6 D15
|
|
||||||
// #define LCD_D7 D16
|
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -23,8 +14,17 @@
|
|||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
// File with configs
|
// Your file with configs
|
||||||
#include "lcd_config.h"
|
#include "lcd_config.h"
|
||||||
|
/*
|
||||||
|
#define LCD_RS 10
|
||||||
|
#define LCD_RW 11
|
||||||
|
#define LCD_E 12
|
||||||
|
#define LCD_D4 13
|
||||||
|
#define LCD_D5 14
|
||||||
|
#define LCD_D6 15
|
||||||
|
#define LCD_D7 16
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+576
@@ -100,3 +100,579 @@ void uart_flush()
|
|||||||
dummy = UDR0;
|
dummy = UDR0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------- VT100 extension --------------
|
||||||
|
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+185
@@ -66,3 +66,188 @@ void uart_puts(const char* str);
|
|||||||
/** Send progmem string over UART */
|
/** Send progmem string over UART */
|
||||||
void uart_puts_P(const char* str);
|
void uart_puts_P(const char* str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|||||||
-581
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-192
@@ -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));
|
|
||||||
-126
@@ -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)
|
|
||||||
+132
@@ -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]); \
|
||||||
|
// } \
|
||||||
|
// } \
|
||||||
|
// }
|
||||||
+51
@@ -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);
|
||||||
Reference in New Issue
Block a user