mirror of
https://github.com/laanwj/k210-sdk-stuff.git
synced 2024-11-22 01:16:20 +04:00
rust: Add weather
Add `weather` demo, also extend console as necessary to handle wttr.in's escape codes.
This commit is contained in:
parent
bfe58fe72b
commit
71b427b188
15
README.md
15
README.md
@ -139,6 +139,21 @@ Control the color of the RGB LED from the touch screen.
|
||||
|
||||
[README](rust/rgbcontrol/README.md)
|
||||
|
||||
rust/esp8266at
|
||||
--------------
|
||||
|
||||
A crate for communicating with WiFi using the ESP8266 using AT commands. TODO: move this to its own repository.
|
||||
|
||||
[README](rust/esp8266at/README.md)
|
||||
|
||||
rust/weather
|
||||
------------
|
||||
|
||||
Uses the ESP8285 WiFi chip of the Maix Go to fetch weather data from
|
||||
[wttr.in](https://wttr.in) and print it to the display using `k210-console`.
|
||||
|
||||
[README](rust/weather/README.md)
|
||||
|
||||
ROM re'ing
|
||||
===========
|
||||
|
||||
|
@ -6,6 +6,7 @@ members = [
|
||||
"accelerometer",
|
||||
"uart-passthrough",
|
||||
"rgbcontrol",
|
||||
"weather",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
3
rust/k210-console/data/README.md
Normal file
3
rust/k210-console/data/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
Based on https://github.com/nabijaczleweli/codepage-437/blob/master/dialect-specs/cp437_wingdings/values.tsv by nabijaczleweli.
|
||||
|
||||
- Changed 0xFF to WHITE SQUARE
|
161
rust/k210-console/data/values.tsv
Normal file
161
rust/k210-console/data/values.tsv
Normal file
@ -0,0 +1,161 @@
|
||||
cp437_wingdings Unicode Comment
|
||||
0x01 0x263A WHITE SMILING FACE
|
||||
0x02 0x263B BLACK SMILING FACE
|
||||
0x03 0x2665 BLACK HEART SUIT
|
||||
0x04 0x2666 BLACK DIAMOND SUIT
|
||||
0x05 0x2663 BLACK CLUB SUIT
|
||||
0x06 0x2660 BLACK SPADE SUIT
|
||||
0x07 0x2022 BULLET
|
||||
0x08 0x25D8 INVERSE BULLET
|
||||
0x09 0x25CB WHITE CIRCLE
|
||||
0x0A 0x25D9 INVERSE WHITE CIRCLE
|
||||
0x0B 0x2642 MALE SIGN
|
||||
0x0C 0x2640 FEMALE SIGN
|
||||
0x0D 0x266A EIGHTH NOTE
|
||||
0x0E 0x266B BEAMED EIGHTH NOTES
|
||||
0x0F 0x263C WHITE SUN WITH RAYS
|
||||
0x10 0x25BA BLACK RIGHT-POINTING POINTER
|
||||
0x11 0x25C4 BLACK LEFT-POINTING POINTER
|
||||
0x12 0x2195 UP DOWN ARROW
|
||||
0x13 0x203C DOUBLE EXCLAMATION MARK
|
||||
0x14 0x00B6 PILCROW SIGN
|
||||
0x15 0x00A7 SECTION SIGN
|
||||
0x16 0x25AC BLACK RECTANGLE
|
||||
0x17 0x21A8 UP DOWN ARROW WITH BASE
|
||||
0x18 0x2191 UPWARDS ARROW
|
||||
0x19 0x2193 DOWNWARDS ARROW
|
||||
0x1A 0x2192 RIGHTWARDS ARROW
|
||||
0x1B 0x2190 LEFTWARDS ARROW
|
||||
0x1C 0x221F RIGHT ANGLE
|
||||
0x1D 0x2194 LEFT RIGHT ARROW
|
||||
0x1E 0x25B2 BLACK UP-POINTING TRIANGLE
|
||||
0x1F 0x25BC BLACK DOWN-POINTING TRIANGLE
|
||||
0x7F 0x2302 HOUSE
|
||||
0x80 0x00C7 LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x81 0x00FC LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x82 0x00E9 LATIN SMALL LETTER E WITH ACUTE
|
||||
0x83 0x00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x84 0x00E4 LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x85 0x00E0 LATIN SMALL LETTER A WITH GRAVE
|
||||
0x86 0x00E5 LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x87 0x00E7 LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x88 0x00EA LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x89 0x00EB LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x8A 0x00E8 LATIN SMALL LETTER E WITH GRAVE
|
||||
0x8B 0x00EF LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x8C 0x00EE LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x8D 0x00EC LATIN SMALL LETTER I WITH GRAVE
|
||||
0x8E 0x00C4 LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x8F 0x00C5 LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x90 0x00C9 LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x91 0x00E6 LATIN SMALL LETTER AE
|
||||
0x92 0x00C6 LATIN CAPITAL LETTER AE
|
||||
0x93 0x00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x94 0x00F6 LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x95 0x00F2 LATIN SMALL LETTER O WITH GRAVE
|
||||
0x96 0x00FB LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x97 0x00F9 LATIN SMALL LETTER U WITH GRAVE
|
||||
0x98 0x00FF LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
0x99 0x00D6 LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x9A 0x00DC LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x9B 0x00A2 CENT SIGN
|
||||
0x9C 0x00A3 POUND SIGN
|
||||
0x9D 0x00A5 YEN SIGN
|
||||
0x9E 0x20A7 PESETA SIGN
|
||||
0x9F 0x0192 LATIN SMALL LETTER F WITH HOOK
|
||||
0xA0 0x00E1 LATIN SMALL LETTER A WITH ACUTE
|
||||
0xA1 0x00ED LATIN SMALL LETTER I WITH ACUTE
|
||||
0xA2 0x00F3 LATIN SMALL LETTER O WITH ACUTE
|
||||
0xA3 0x00FA LATIN SMALL LETTER U WITH ACUTE
|
||||
0xA4 0x00F1 LATIN SMALL LETTER N WITH TILDE
|
||||
0xA5 0x00D1 LATIN CAPITAL LETTER N WITH TILDE
|
||||
0xA6 0x00AA FEMININE ORDINAL INDICATOR
|
||||
0xA7 0x00BA MASCULINE ORDINAL INDICATOR
|
||||
0xA8 0x00BF INVERTED QUESTION MARK
|
||||
0xA9 0x2310 REVERSED NOT SIGN
|
||||
0xAA 0x00AC NOT SIGN
|
||||
0xAB 0x00BD VULGAR FRACTION ONE HALF
|
||||
0xAC 0x00BC VULGAR FRACTION ONE QUARTER
|
||||
0xAD 0x00A1 INVERTED EXCLAMATION MARK
|
||||
0xAE 0x00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0xAF 0x00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0xB0 0x2591 LIGHT SHADE
|
||||
0xB1 0x2592 MEDIUM SHADE
|
||||
0xB2 0x2593 DARK SHADE
|
||||
0xB3 0x2502 BOX DRAWINGS LIGHT VERTICAL
|
||||
0xB4 0x2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
0xB5 0x2561 BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
|
||||
0xB6 0x2562 BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
|
||||
0xB7 0x2556 BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
|
||||
0xB8 0x2555 BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
|
||||
0xB9 0x2563 BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
0xBA 0x2551 BOX DRAWINGS DOUBLE VERTICAL
|
||||
0xBB 0x2557 BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
0xBC 0x255D BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
0xBD 0x255C BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
|
||||
0xBE 0x255B BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
|
||||
0xBF 0x2510 BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
0xC0 0x2514 BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
0xC1 0x2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
0xC2 0x252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
0xC3 0x251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
0xC4 0x2500 BOX DRAWINGS LIGHT HORIZONTAL
|
||||
0xC5 0x253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
0xC6 0x255E BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
|
||||
0xC7 0x255F BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
|
||||
0xC8 0x255A BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
0xC9 0x2554 BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
0xCA 0x2569 BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
0xCB 0x2566 BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
0xCC 0x2560 BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
0xCD 0x2550 BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
0xCE 0x256C BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
0xCF 0x2567 BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
|
||||
0xD0 0x2568 BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
|
||||
0xD1 0x2564 BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
|
||||
0xD2 0x2565 BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
|
||||
0xD3 0x2559 BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
|
||||
0xD4 0x2558 BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
|
||||
0xD5 0x2552 BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
|
||||
0xD6 0x2553 BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
|
||||
0xD7 0x256B BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
|
||||
0xD8 0x256A BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
|
||||
0xD9 0x2518 BOX DRAWINGS LIGHT UP AND LEFT
|
||||
0xDA 0x250C BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
0xDB 0x2588 FULL BLOCK
|
||||
0xDC 0x2584 LOWER HALF BLOCK
|
||||
0xDD 0x258C LEFT HALF BLOCK
|
||||
0xDE 0x2590 RIGHT HALF BLOCK
|
||||
0xDF 0x2580 UPPER HALF BLOCK
|
||||
0xE0 0x03B1 GREEK SMALL LETTER ALPHA
|
||||
0xE1 0x00DF LATIN SMALL LETTER SHARP S
|
||||
0xE2 0x0393 GREEK CAPITAL LETTER GAMMA
|
||||
0xE3 0x03C0 GREEK SMALL LETTER PI
|
||||
0xE4 0x03A3 GREEK CAPITAL LETTER SIGMA
|
||||
0xE5 0x03C3 GREEK SMALL LETTER SIGMA
|
||||
0xE6 0x00B5 MICRO SIGN
|
||||
0xE7 0x03C4 GREEK SMALL LETTER TAU
|
||||
0xE8 0x03A6 GREEK CAPITAL LETTER PHI
|
||||
0xE9 0x0398 GREEK CAPITAL LETTER THETA
|
||||
0xEA 0x03A9 GREEK CAPITAL LETTER OMEGA
|
||||
0xEB 0x03B4 GREEK SMALL LETTER DELTA
|
||||
0xEC 0x221E INFINITY
|
||||
0xED 0x03C6 GREEK SMALL LETTER PHI
|
||||
0xEE 0x03B5 GREEK SMALL LETTER EPSILON
|
||||
0xEF 0x2229 INTERSECTION
|
||||
0xF0 0x2261 IDENTICAL TO
|
||||
0xF1 0x00B1 PLUS-MINUS SIGN
|
||||
0xF2 0x2265 GREATER-THAN OR EQUAL TO
|
||||
0xF3 0x2264 LESS-THAN OR EQUAL TO
|
||||
0xF4 0x2320 TOP HALF INTEGRAL
|
||||
0xF5 0x2321 BOTTOM HALF INTEGRAL
|
||||
0xF6 0x00F7 DIVISION SIGN
|
||||
0xF7 0x2248 ALMOST EQUAL TO
|
||||
0xF8 0x00B0 DEGREE SIGN
|
||||
0xF9 0x2219 BULLET OPERATOR
|
||||
0xFA 0x00B7 MIDDLE DOT
|
||||
0xFB 0x221A SQUARE ROOT
|
||||
0xFC 0x207F SUPERSCRIPT LATIN SMALL LETTER N
|
||||
0xFD 0x00B2 SUPERSCRIPT TWO
|
||||
0xFE 0x25A0 BLACK SQUARE
|
||||
0xFF 0x25A1 WHITE SQUARE
|
|
45
rust/k210-console/scripts/create_tables.py
Executable file
45
rust/k210-console/scripts/create_tables.py
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
import unicodedata
|
||||
|
||||
mapping = []
|
||||
with open('../data/values.tsv', 'r') as f:
|
||||
lines = iter(f)
|
||||
next(lines)
|
||||
for line in lines:
|
||||
(byte, unich, name) = line.rstrip().split('\t')
|
||||
byte = int(byte, 0)
|
||||
unich = int(unich, 0)
|
||||
mapping.append((byte, unich, name))
|
||||
|
||||
# add in ASCII
|
||||
mapping.append((0x00, 0x0000, 'NUL'))
|
||||
for ch in range(0x20, 0x7f):
|
||||
mapping.append((ch, ch, unicodedata.name(chr(ch))))
|
||||
mapping.sort()
|
||||
|
||||
fw_mapping = [None] * 256
|
||||
for byte, unich, name in mapping:
|
||||
#print('%02x %05x %s' % (byte, unich, name))
|
||||
fw_mapping[byte] = unich
|
||||
|
||||
def qchar(ch):
|
||||
return "'\\u{%04x}'" % ch
|
||||
|
||||
print('static FROM: [char; 256] = [')
|
||||
for i in range(0x100):
|
||||
if (i % 8)==0:
|
||||
print(" ", end='')
|
||||
print("%s," % qchar(fw_mapping[i]), end='')
|
||||
if ((i+1) % 8)==0:
|
||||
print()
|
||||
else:
|
||||
print(" ", end='')
|
||||
print(']')
|
||||
|
||||
print('pub fn to(ch: char) -> u8 {')
|
||||
print(' match ch {')
|
||||
for byte, unich, name in mapping:
|
||||
print(' %s => 0x%02x, // %s' % (qchar(unich), byte, name))
|
||||
print(' }')
|
||||
print('}')
|
||||
|
@ -1,11 +1,16 @@
|
||||
use core::fmt;
|
||||
|
||||
use k210_shared::board::lcd_colors::rgb565;
|
||||
use crate::cp437;
|
||||
use crate::cp437_8x8;
|
||||
use crate::palette_xterm256::PALETTE;
|
||||
|
||||
pub const DISP_WIDTH: usize = 320;
|
||||
pub const DISP_HEIGHT: usize = 240;
|
||||
const GRID_WIDTH: usize = DISP_WIDTH / 8;
|
||||
const GRID_HEIGHT: usize = DISP_HEIGHT / 8;
|
||||
const DEF_FG: u16 = rgb565(192, 192, 192);
|
||||
const DEF_BG: u16 = rgb565(0, 0, 0);
|
||||
|
||||
pub type ScreenImage = [u32; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
|
||||
@ -18,15 +23,15 @@ pub struct Color {
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(r: u8, g: u8, b: u8) -> Color {
|
||||
pub const fn new(r: u8, g: u8, b: u8) -> Color {
|
||||
Color { r, g, b, a: 255 }
|
||||
}
|
||||
|
||||
pub fn new_rgba(r: u8, g: u8, b: u8, a: u8) -> Color {
|
||||
pub const fn new_rgba(r: u8, g: u8, b: u8, a: u8) -> Color {
|
||||
Color { r, g, b, a: a }
|
||||
}
|
||||
|
||||
pub fn from_rgba32(val: u32) -> Color {
|
||||
pub const fn from_rgba32(val: u32) -> Color {
|
||||
Color {
|
||||
r: ((val >> 24) & 0xff) as u8,
|
||||
g: ((val >> 16) & 0xff) as u8,
|
||||
@ -34,6 +39,10 @@ impl Color {
|
||||
a: ((val >> 0) & 0xff) as u8,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn to_rgb565(&self) -> u16 {
|
||||
rgb565(self.r, self.g, self.b)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -71,27 +80,71 @@ pub struct Cell {
|
||||
ch: char,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Initial,
|
||||
Escape,
|
||||
CSI,
|
||||
}
|
||||
|
||||
enum Sgr {
|
||||
Initial,
|
||||
SpecialFg,
|
||||
SpecialBg,
|
||||
Fg256,
|
||||
Bg256,
|
||||
FgR,
|
||||
BgR,
|
||||
FgG,
|
||||
BgG,
|
||||
FgB,
|
||||
BgB,
|
||||
}
|
||||
|
||||
/** Visual attributes of console */
|
||||
pub struct Console {
|
||||
/** Dirty flag */
|
||||
pub dirty: bool,
|
||||
/** Array of character cells representing console */
|
||||
cells: [Cell; GRID_WIDTH * GRID_HEIGHT],
|
||||
/** Cursor position */
|
||||
cursor_pos: Coord,
|
||||
/** Cursor visible flag */
|
||||
cursor_visible: bool,
|
||||
/** Default foreground */
|
||||
def_fg: u16,
|
||||
/** Default background */
|
||||
def_bg: u16,
|
||||
/** Current foreground */
|
||||
cur_fg: u16,
|
||||
/** Current background */
|
||||
cur_bg: u16,
|
||||
/** Current escape state */
|
||||
state: State,
|
||||
/** Current CSI parameter */
|
||||
idx: usize,
|
||||
/** CSI parameters */
|
||||
num: [u16; 16],
|
||||
}
|
||||
|
||||
impl Console {
|
||||
/** Create new, empty console */
|
||||
pub fn new() -> Console {
|
||||
Console {
|
||||
dirty: false,
|
||||
cells: [Cell {
|
||||
fg: 0,
|
||||
bg: 0,
|
||||
fg: DEF_FG,
|
||||
bg: DEF_BG,
|
||||
ch: '\x00',
|
||||
}; GRID_WIDTH * GRID_HEIGHT],
|
||||
cursor_pos: Coord::new(0, 0),
|
||||
cursor_visible: true,
|
||||
def_fg: DEF_FG,
|
||||
def_bg: DEF_BG,
|
||||
cur_fg: DEF_FG,
|
||||
cur_bg: DEF_BG,
|
||||
state: State::Initial,
|
||||
idx: 0,
|
||||
num: [0; 16],
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,11 +193,139 @@ impl Console {
|
||||
GRID_HEIGHT as u16
|
||||
}
|
||||
|
||||
/** Put a char at an arbitrary position with arbitrary fg/bg color. Does not move the cursor.
|
||||
* Use this to regard the console as a simple grid of cells a la libtcod. Useful for drawing
|
||||
* frames and such.
|
||||
*/
|
||||
pub fn put(&mut self, x: u16, y: u16, fg: Color, bg: Color, ch: char) {
|
||||
self.dirty = true;
|
||||
self.cells[(y as usize) * GRID_WIDTH + (x as usize)] = Cell {
|
||||
fg: rgb565(fg.r, fg.g, fg.b),
|
||||
bg: rgb565(bg.r, bg.g, bg.b),
|
||||
ch,
|
||||
};
|
||||
}
|
||||
|
||||
/** Handle SGR escape sequence parameters */
|
||||
pub fn handle_sgr(&mut self) {
|
||||
let mut state = Sgr::Initial;
|
||||
let mut color = Color::new(0, 0, 0);
|
||||
for param in &self.num[0..self.idx+1] {
|
||||
match state {
|
||||
Sgr::Initial => {
|
||||
match param {
|
||||
0 => { self.cur_fg = self.def_fg; self.cur_bg = self.def_bg; }
|
||||
30..=37 => { self.cur_fg = Color::from_rgba32(PALETTE[(param - 30) as usize]).to_rgb565(); }
|
||||
38 => { state = Sgr::SpecialFg; }
|
||||
40..=47 => { self.cur_bg = Color::from_rgba32(PALETTE[(param - 40) as usize]).to_rgb565(); }
|
||||
48 => { state = Sgr::SpecialBg; }
|
||||
90..=97 => { self.cur_fg = Color::from_rgba32(PALETTE[8 + (param - 90) as usize]).to_rgb565(); }
|
||||
100..=107 => { self.cur_bg = Color::from_rgba32(PALETTE[8 + (param - 100) as usize]).to_rgb565(); }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Sgr::SpecialFg => {
|
||||
match param {
|
||||
2 => { state = Sgr::FgR; }
|
||||
5 => { state = Sgr::Fg256; }
|
||||
_ => { state = Sgr::Initial; }
|
||||
}
|
||||
}
|
||||
Sgr::SpecialBg => {
|
||||
match param {
|
||||
2 => { state = Sgr::BgR; }
|
||||
5 => { state = Sgr::Bg256; }
|
||||
_ => { state = Sgr::Initial; }
|
||||
}
|
||||
}
|
||||
Sgr::Fg256 => {
|
||||
self.cur_fg = Color::from_rgba32(PALETTE[(param & 0xff) as usize]).to_rgb565();
|
||||
state = Sgr::Initial;
|
||||
}
|
||||
Sgr::Bg256 => {
|
||||
self.cur_bg = Color::from_rgba32(PALETTE[(param & 0xff) as usize]).to_rgb565();
|
||||
state = Sgr::Initial;
|
||||
}
|
||||
Sgr::FgR => { color.r = (param & 0xff) as u8; state = Sgr::FgG; }
|
||||
Sgr::FgG => { color.g = (param & 0xff) as u8; state = Sgr::FgB; }
|
||||
Sgr::FgB => { color.b = (param & 0xff) as u8; state = Sgr::Initial; self.cur_fg = color.to_rgb565(); }
|
||||
Sgr::BgR => { color.r = (param & 0xff) as u8; state = Sgr::BgG; }
|
||||
Sgr::BgG => { color.g = (param & 0xff) as u8; state = Sgr::BgB; }
|
||||
Sgr::BgB => { color.b = (param & 0xff) as u8; state = Sgr::Initial; self.cur_bg = color.to_rgb565(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Put a char at current cursor position, interpreting control and escape codes. */
|
||||
pub fn putch(&mut self, ch: char) {
|
||||
match self.state {
|
||||
State::Initial => {
|
||||
match ch {
|
||||
'\r' => { self.cursor_pos.x = 0; }
|
||||
'\n' => { self.cursor_pos.y += 1; self.cursor_pos.x = 0; }
|
||||
'\x1b' => { self.state = State::Escape; }
|
||||
ch => {
|
||||
self.dirty = true;
|
||||
self.cells[(self.cursor_pos.y as usize) * GRID_WIDTH + (self.cursor_pos.x as usize)] = Cell {
|
||||
fg: self.cur_fg,
|
||||
bg: self.cur_bg,
|
||||
ch,
|
||||
};
|
||||
self.cursor_pos.x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Escape => {
|
||||
match ch {
|
||||
'[' => { self.state = State::CSI; self.idx = 0; self.num[0] = 0; }
|
||||
_ => { self.state = State::Initial; }
|
||||
}
|
||||
}
|
||||
State::CSI => {
|
||||
match ch {
|
||||
'0'..='9' => {
|
||||
self.num[self.idx] *= 10;
|
||||
self.num[self.idx] += ((ch as u8) - b'0') as u16;
|
||||
}
|
||||
';' => {
|
||||
self.idx += 1;
|
||||
if self.idx == self.num.len() {
|
||||
// Too many arguments, ignore sequence
|
||||
self.state = State::Initial;
|
||||
} else {
|
||||
self.num[self.idx] = 0;
|
||||
}
|
||||
}
|
||||
'm' => {
|
||||
self.handle_sgr();
|
||||
self.state = State::Initial;
|
||||
}
|
||||
_ => {
|
||||
self.state = State::Initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// wrap around
|
||||
if self.cursor_pos.x == GRID_WIDTH as u16 {
|
||||
self.cursor_pos.x = 0;
|
||||
self.cursor_pos.y += 1;
|
||||
}
|
||||
if self.cursor_pos.y == GRID_HEIGHT as u16 {
|
||||
self.cursor_pos.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Put a string at current cursor position, interpreting control and escape codes. */
|
||||
pub fn puts(&mut self, s: &str) {
|
||||
for ch in s.chars() {
|
||||
self.putch(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Formatting adoption for console */
|
||||
impl fmt::Write for Console {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { self.puts(s); Ok(()) }
|
||||
fn write_char(&mut self, c: char) -> Result<(), fmt::Error> { self.putch(c); Ok(()) }
|
||||
}
|
||||
|
@ -1,9 +1,301 @@
|
||||
/** Table from cp437 to unicode char; generated with create_tables.py */
|
||||
static FROM: [char; 256] = [
|
||||
'\u{0000}', '\u{263a}', '\u{263b}', '\u{2665}', '\u{2666}', '\u{2663}', '\u{2660}', '\u{2022}',
|
||||
'\u{25d8}', '\u{25cb}', '\u{25d9}', '\u{2642}', '\u{2640}', '\u{266a}', '\u{266b}', '\u{263c}',
|
||||
'\u{25ba}', '\u{25c4}', '\u{2195}', '\u{203c}', '\u{00b6}', '\u{00a7}', '\u{25ac}', '\u{21a8}',
|
||||
'\u{2191}', '\u{2193}', '\u{2192}', '\u{2190}', '\u{221f}', '\u{2194}', '\u{25b2}', '\u{25bc}',
|
||||
'\u{0020}', '\u{0021}', '\u{0022}', '\u{0023}', '\u{0024}', '\u{0025}', '\u{0026}', '\u{0027}',
|
||||
'\u{0028}', '\u{0029}', '\u{002a}', '\u{002b}', '\u{002c}', '\u{002d}', '\u{002e}', '\u{002f}',
|
||||
'\u{0030}', '\u{0031}', '\u{0032}', '\u{0033}', '\u{0034}', '\u{0035}', '\u{0036}', '\u{0037}',
|
||||
'\u{0038}', '\u{0039}', '\u{003a}', '\u{003b}', '\u{003c}', '\u{003d}', '\u{003e}', '\u{003f}',
|
||||
'\u{0040}', '\u{0041}', '\u{0042}', '\u{0043}', '\u{0044}', '\u{0045}', '\u{0046}', '\u{0047}',
|
||||
'\u{0048}', '\u{0049}', '\u{004a}', '\u{004b}', '\u{004c}', '\u{004d}', '\u{004e}', '\u{004f}',
|
||||
'\u{0050}', '\u{0051}', '\u{0052}', '\u{0053}', '\u{0054}', '\u{0055}', '\u{0056}', '\u{0057}',
|
||||
'\u{0058}', '\u{0059}', '\u{005a}', '\u{005b}', '\u{005c}', '\u{005d}', '\u{005e}', '\u{005f}',
|
||||
'\u{0060}', '\u{0061}', '\u{0062}', '\u{0063}', '\u{0064}', '\u{0065}', '\u{0066}', '\u{0067}',
|
||||
'\u{0068}', '\u{0069}', '\u{006a}', '\u{006b}', '\u{006c}', '\u{006d}', '\u{006e}', '\u{006f}',
|
||||
'\u{0070}', '\u{0071}', '\u{0072}', '\u{0073}', '\u{0074}', '\u{0075}', '\u{0076}', '\u{0077}',
|
||||
'\u{0078}', '\u{0079}', '\u{007a}', '\u{007b}', '\u{007c}', '\u{007d}', '\u{007e}', '\u{2302}',
|
||||
'\u{00c7}', '\u{00fc}', '\u{00e9}', '\u{00e2}', '\u{00e4}', '\u{00e0}', '\u{00e5}', '\u{00e7}',
|
||||
'\u{00ea}', '\u{00eb}', '\u{00e8}', '\u{00ef}', '\u{00ee}', '\u{00ec}', '\u{00c4}', '\u{00c5}',
|
||||
'\u{00c9}', '\u{00e6}', '\u{00c6}', '\u{00f4}', '\u{00f6}', '\u{00f2}', '\u{00fb}', '\u{00f9}',
|
||||
'\u{00ff}', '\u{00d6}', '\u{00dc}', '\u{00a2}', '\u{00a3}', '\u{00a5}', '\u{20a7}', '\u{0192}',
|
||||
'\u{00e1}', '\u{00ed}', '\u{00f3}', '\u{00fa}', '\u{00f1}', '\u{00d1}', '\u{00aa}', '\u{00ba}',
|
||||
'\u{00bf}', '\u{2310}', '\u{00ac}', '\u{00bd}', '\u{00bc}', '\u{00a1}', '\u{00ab}', '\u{00bb}',
|
||||
'\u{2591}', '\u{2592}', '\u{2593}', '\u{2502}', '\u{2524}', '\u{2561}', '\u{2562}', '\u{2556}',
|
||||
'\u{2555}', '\u{2563}', '\u{2551}', '\u{2557}', '\u{255d}', '\u{255c}', '\u{255b}', '\u{2510}',
|
||||
'\u{2514}', '\u{2534}', '\u{252c}', '\u{251c}', '\u{2500}', '\u{253c}', '\u{255e}', '\u{255f}',
|
||||
'\u{255a}', '\u{2554}', '\u{2569}', '\u{2566}', '\u{2560}', '\u{2550}', '\u{256c}', '\u{2567}',
|
||||
'\u{2568}', '\u{2564}', '\u{2565}', '\u{2559}', '\u{2558}', '\u{2552}', '\u{2553}', '\u{256b}',
|
||||
'\u{256a}', '\u{2518}', '\u{250c}', '\u{2588}', '\u{2584}', '\u{258c}', '\u{2590}', '\u{2580}',
|
||||
'\u{03b1}', '\u{00df}', '\u{0393}', '\u{03c0}', '\u{03a3}', '\u{03c3}', '\u{00b5}', '\u{03c4}',
|
||||
'\u{03a6}', '\u{0398}', '\u{03a9}', '\u{03b4}', '\u{221e}', '\u{03c6}', '\u{03b5}', '\u{2229}',
|
||||
'\u{2261}', '\u{00b1}', '\u{2265}', '\u{2264}', '\u{2320}', '\u{2321}', '\u{00f7}', '\u{2248}',
|
||||
'\u{00b0}', '\u{2219}', '\u{00b7}', '\u{221a}', '\u{207f}', '\u{00b2}', '\u{25a0}', '\u{25a1}',
|
||||
];
|
||||
|
||||
pub fn from(ch: u8) -> char {
|
||||
// TODO: correct mapping
|
||||
ch as char
|
||||
FROM[ch as usize]
|
||||
}
|
||||
|
||||
pub fn to(ch: char) -> u8 {
|
||||
// TODO: correct mapping
|
||||
ch as u8
|
||||
match ch {
|
||||
'\u{0000}' => 0x00, // NUL
|
||||
'\u{263a}' => 0x01, // WHITE SMILING FACE
|
||||
'\u{263b}' => 0x02, // BLACK SMILING FACE
|
||||
'\u{2665}' => 0x03, // BLACK HEART SUIT
|
||||
'\u{2666}' => 0x04, // BLACK DIAMOND SUIT
|
||||
'\u{2663}' => 0x05, // BLACK CLUB SUIT
|
||||
'\u{2660}' => 0x06, // BLACK SPADE SUIT
|
||||
'\u{2022}' => 0x07, // BULLET
|
||||
'\u{25d8}' => 0x08, // INVERSE BULLET
|
||||
'\u{25cb}' => 0x09, // WHITE CIRCLE
|
||||
'\u{25d9}' => 0x0a, // INVERSE WHITE CIRCLE
|
||||
'\u{2642}' => 0x0b, // MALE SIGN
|
||||
'\u{2640}' => 0x0c, // FEMALE SIGN
|
||||
'\u{266a}' => 0x0d, // EIGHTH NOTE
|
||||
'\u{266b}' => 0x0e, // BEAMED EIGHTH NOTES
|
||||
'\u{263c}' => 0x0f, // WHITE SUN WITH RAYS
|
||||
'\u{25ba}' => 0x10, // BLACK RIGHT-POINTING POINTER
|
||||
'\u{25c4}' => 0x11, // BLACK LEFT-POINTING POINTER
|
||||
'\u{2195}' => 0x12, // UP DOWN ARROW
|
||||
'\u{203c}' => 0x13, // DOUBLE EXCLAMATION MARK
|
||||
'\u{00b6}' => 0x14, // PILCROW SIGN
|
||||
'\u{00a7}' => 0x15, // SECTION SIGN
|
||||
'\u{25ac}' => 0x16, // BLACK RECTANGLE
|
||||
'\u{21a8}' => 0x17, // UP DOWN ARROW WITH BASE
|
||||
'\u{2191}' => 0x18, // UPWARDS ARROW
|
||||
'\u{2193}' => 0x19, // DOWNWARDS ARROW
|
||||
'\u{2192}' => 0x1a, // RIGHTWARDS ARROW
|
||||
'\u{2190}' => 0x1b, // LEFTWARDS ARROW
|
||||
'\u{221f}' => 0x1c, // RIGHT ANGLE
|
||||
'\u{2194}' => 0x1d, // LEFT RIGHT ARROW
|
||||
'\u{25b2}' => 0x1e, // BLACK UP-POINTING TRIANGLE
|
||||
'\u{25bc}' => 0x1f, // BLACK DOWN-POINTING TRIANGLE
|
||||
'\u{0020}' => 0x20, // SPACE
|
||||
'\u{0021}' => 0x21, // EXCLAMATION MARK
|
||||
'\u{0022}' => 0x22, // QUOTATION MARK
|
||||
'\u{0023}' => 0x23, // NUMBER SIGN
|
||||
'\u{0024}' => 0x24, // DOLLAR SIGN
|
||||
'\u{0025}' => 0x25, // PERCENT SIGN
|
||||
'\u{0026}' => 0x26, // AMPERSAND
|
||||
'\u{0027}' => 0x27, // APOSTROPHE
|
||||
'\u{0028}' => 0x28, // LEFT PARENTHESIS
|
||||
'\u{0029}' => 0x29, // RIGHT PARENTHESIS
|
||||
'\u{002a}' => 0x2a, // ASTERISK
|
||||
'\u{002b}' => 0x2b, // PLUS SIGN
|
||||
'\u{002c}' => 0x2c, // COMMA
|
||||
'\u{002d}' => 0x2d, // HYPHEN-MINUS
|
||||
'\u{002e}' => 0x2e, // FULL STOP
|
||||
'\u{002f}' => 0x2f, // SOLIDUS
|
||||
'\u{0030}' => 0x30, // DIGIT ZERO
|
||||
'\u{0031}' => 0x31, // DIGIT ONE
|
||||
'\u{0032}' => 0x32, // DIGIT TWO
|
||||
'\u{0033}' => 0x33, // DIGIT THREE
|
||||
'\u{0034}' => 0x34, // DIGIT FOUR
|
||||
'\u{0035}' => 0x35, // DIGIT FIVE
|
||||
'\u{0036}' => 0x36, // DIGIT SIX
|
||||
'\u{0037}' => 0x37, // DIGIT SEVEN
|
||||
'\u{0038}' => 0x38, // DIGIT EIGHT
|
||||
'\u{0039}' => 0x39, // DIGIT NINE
|
||||
'\u{003a}' => 0x3a, // COLON
|
||||
'\u{003b}' => 0x3b, // SEMICOLON
|
||||
'\u{003c}' => 0x3c, // LESS-THAN SIGN
|
||||
'\u{003d}' => 0x3d, // EQUALS SIGN
|
||||
'\u{003e}' => 0x3e, // GREATER-THAN SIGN
|
||||
'\u{003f}' => 0x3f, // QUESTION MARK
|
||||
'\u{0040}' => 0x40, // COMMERCIAL AT
|
||||
'\u{0041}' => 0x41, // LATIN CAPITAL LETTER A
|
||||
'\u{0042}' => 0x42, // LATIN CAPITAL LETTER B
|
||||
'\u{0043}' => 0x43, // LATIN CAPITAL LETTER C
|
||||
'\u{0044}' => 0x44, // LATIN CAPITAL LETTER D
|
||||
'\u{0045}' => 0x45, // LATIN CAPITAL LETTER E
|
||||
'\u{0046}' => 0x46, // LATIN CAPITAL LETTER F
|
||||
'\u{0047}' => 0x47, // LATIN CAPITAL LETTER G
|
||||
'\u{0048}' => 0x48, // LATIN CAPITAL LETTER H
|
||||
'\u{0049}' => 0x49, // LATIN CAPITAL LETTER I
|
||||
'\u{004a}' => 0x4a, // LATIN CAPITAL LETTER J
|
||||
'\u{004b}' => 0x4b, // LATIN CAPITAL LETTER K
|
||||
'\u{004c}' => 0x4c, // LATIN CAPITAL LETTER L
|
||||
'\u{004d}' => 0x4d, // LATIN CAPITAL LETTER M
|
||||
'\u{004e}' => 0x4e, // LATIN CAPITAL LETTER N
|
||||
'\u{004f}' => 0x4f, // LATIN CAPITAL LETTER O
|
||||
'\u{0050}' => 0x50, // LATIN CAPITAL LETTER P
|
||||
'\u{0051}' => 0x51, // LATIN CAPITAL LETTER Q
|
||||
'\u{0052}' => 0x52, // LATIN CAPITAL LETTER R
|
||||
'\u{0053}' => 0x53, // LATIN CAPITAL LETTER S
|
||||
'\u{0054}' => 0x54, // LATIN CAPITAL LETTER T
|
||||
'\u{0055}' => 0x55, // LATIN CAPITAL LETTER U
|
||||
'\u{0056}' => 0x56, // LATIN CAPITAL LETTER V
|
||||
'\u{0057}' => 0x57, // LATIN CAPITAL LETTER W
|
||||
'\u{0058}' => 0x58, // LATIN CAPITAL LETTER X
|
||||
'\u{0059}' => 0x59, // LATIN CAPITAL LETTER Y
|
||||
'\u{005a}' => 0x5a, // LATIN CAPITAL LETTER Z
|
||||
'\u{005b}' => 0x5b, // LEFT SQUARE BRACKET
|
||||
'\u{005c}' => 0x5c, // REVERSE SOLIDUS
|
||||
'\u{005d}' => 0x5d, // RIGHT SQUARE BRACKET
|
||||
'\u{005e}' => 0x5e, // CIRCUMFLEX ACCENT
|
||||
'\u{005f}' => 0x5f, // LOW LINE
|
||||
'\u{0060}' => 0x60, // GRAVE ACCENT
|
||||
'\u{0061}' => 0x61, // LATIN SMALL LETTER A
|
||||
'\u{0062}' => 0x62, // LATIN SMALL LETTER B
|
||||
'\u{0063}' => 0x63, // LATIN SMALL LETTER C
|
||||
'\u{0064}' => 0x64, // LATIN SMALL LETTER D
|
||||
'\u{0065}' => 0x65, // LATIN SMALL LETTER E
|
||||
'\u{0066}' => 0x66, // LATIN SMALL LETTER F
|
||||
'\u{0067}' => 0x67, // LATIN SMALL LETTER G
|
||||
'\u{0068}' => 0x68, // LATIN SMALL LETTER H
|
||||
'\u{0069}' => 0x69, // LATIN SMALL LETTER I
|
||||
'\u{006a}' => 0x6a, // LATIN SMALL LETTER J
|
||||
'\u{006b}' => 0x6b, // LATIN SMALL LETTER K
|
||||
'\u{006c}' => 0x6c, // LATIN SMALL LETTER L
|
||||
'\u{006d}' => 0x6d, // LATIN SMALL LETTER M
|
||||
'\u{006e}' => 0x6e, // LATIN SMALL LETTER N
|
||||
'\u{006f}' => 0x6f, // LATIN SMALL LETTER O
|
||||
'\u{0070}' => 0x70, // LATIN SMALL LETTER P
|
||||
'\u{0071}' => 0x71, // LATIN SMALL LETTER Q
|
||||
'\u{0072}' => 0x72, // LATIN SMALL LETTER R
|
||||
'\u{0073}' => 0x73, // LATIN SMALL LETTER S
|
||||
'\u{0074}' => 0x74, // LATIN SMALL LETTER T
|
||||
'\u{0075}' => 0x75, // LATIN SMALL LETTER U
|
||||
'\u{0076}' => 0x76, // LATIN SMALL LETTER V
|
||||
'\u{0077}' => 0x77, // LATIN SMALL LETTER W
|
||||
'\u{0078}' => 0x78, // LATIN SMALL LETTER X
|
||||
'\u{0079}' => 0x79, // LATIN SMALL LETTER Y
|
||||
'\u{007a}' => 0x7a, // LATIN SMALL LETTER Z
|
||||
'\u{007b}' => 0x7b, // LEFT CURLY BRACKET
|
||||
'\u{007c}' => 0x7c, // VERTICAL LINE
|
||||
'\u{007d}' => 0x7d, // RIGHT CURLY BRACKET
|
||||
'\u{007e}' => 0x7e, // TILDE
|
||||
'\u{2302}' => 0x7f, // HOUSE
|
||||
'\u{00c7}' => 0x80, // LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
'\u{00fc}' => 0x81, // LATIN SMALL LETTER U WITH DIAERESIS
|
||||
'\u{00e9}' => 0x82, // LATIN SMALL LETTER E WITH ACUTE
|
||||
'\u{00e2}' => 0x83, // LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
'\u{00e4}' => 0x84, // LATIN SMALL LETTER A WITH DIAERESIS
|
||||
'\u{00e0}' => 0x85, // LATIN SMALL LETTER A WITH GRAVE
|
||||
'\u{00e5}' => 0x86, // LATIN SMALL LETTER A WITH RING ABOVE
|
||||
'\u{00e7}' => 0x87, // LATIN SMALL LETTER C WITH CEDILLA
|
||||
'\u{00ea}' => 0x88, // LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
'\u{00eb}' => 0x89, // LATIN SMALL LETTER E WITH DIAERESIS
|
||||
'\u{00e8}' => 0x8a, // LATIN SMALL LETTER E WITH GRAVE
|
||||
'\u{00ef}' => 0x8b, // LATIN SMALL LETTER I WITH DIAERESIS
|
||||
'\u{00ee}' => 0x8c, // LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
'\u{00ec}' => 0x8d, // LATIN SMALL LETTER I WITH GRAVE
|
||||
'\u{00c4}' => 0x8e, // LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
'\u{00c5}' => 0x8f, // LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
'\u{00c9}' => 0x90, // LATIN CAPITAL LETTER E WITH ACUTE
|
||||
'\u{00e6}' => 0x91, // LATIN SMALL LETTER AE
|
||||
'\u{00c6}' => 0x92, // LATIN CAPITAL LETTER AE
|
||||
'\u{00f4}' => 0x93, // LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
'\u{00f6}' => 0x94, // LATIN SMALL LETTER O WITH DIAERESIS
|
||||
'\u{00f2}' => 0x95, // LATIN SMALL LETTER O WITH GRAVE
|
||||
'\u{00fb}' => 0x96, // LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
'\u{00f9}' => 0x97, // LATIN SMALL LETTER U WITH GRAVE
|
||||
'\u{00ff}' => 0x98, // LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
'\u{00d6}' => 0x99, // LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
'\u{00dc}' => 0x9a, // LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
'\u{00a2}' => 0x9b, // CENT SIGN
|
||||
'\u{00a3}' => 0x9c, // POUND SIGN
|
||||
'\u{00a5}' => 0x9d, // YEN SIGN
|
||||
'\u{20a7}' => 0x9e, // PESETA SIGN
|
||||
'\u{0192}' => 0x9f, // LATIN SMALL LETTER F WITH HOOK
|
||||
'\u{00e1}' => 0xa0, // LATIN SMALL LETTER A WITH ACUTE
|
||||
'\u{00ed}' => 0xa1, // LATIN SMALL LETTER I WITH ACUTE
|
||||
'\u{00f3}' => 0xa2, // LATIN SMALL LETTER O WITH ACUTE
|
||||
'\u{00fa}' => 0xa3, // LATIN SMALL LETTER U WITH ACUTE
|
||||
'\u{00f1}' => 0xa4, // LATIN SMALL LETTER N WITH TILDE
|
||||
'\u{00d1}' => 0xa5, // LATIN CAPITAL LETTER N WITH TILDE
|
||||
'\u{00aa}' => 0xa6, // FEMININE ORDINAL INDICATOR
|
||||
'\u{00ba}' => 0xa7, // MASCULINE ORDINAL INDICATOR
|
||||
'\u{00bf}' => 0xa8, // INVERTED QUESTION MARK
|
||||
'\u{2310}' => 0xa9, // REVERSED NOT SIGN
|
||||
'\u{00ac}' => 0xaa, // NOT SIGN
|
||||
'\u{00bd}' => 0xab, // VULGAR FRACTION ONE HALF
|
||||
'\u{00bc}' => 0xac, // VULGAR FRACTION ONE QUARTER
|
||||
'\u{00a1}' => 0xad, // INVERTED EXCLAMATION MARK
|
||||
'\u{00ab}' => 0xae, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
'\u{00bb}' => 0xaf, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
'\u{2591}' => 0xb0, // LIGHT SHADE
|
||||
'\u{2592}' => 0xb1, // MEDIUM SHADE
|
||||
'\u{2593}' => 0xb2, // DARK SHADE
|
||||
'\u{2502}' => 0xb3, // BOX DRAWINGS LIGHT VERTICAL
|
||||
'\u{2524}' => 0xb4, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
'\u{2561}' => 0xb5, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
|
||||
'\u{2562}' => 0xb6, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
|
||||
'\u{2556}' => 0xb7, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
|
||||
'\u{2555}' => 0xb8, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
|
||||
'\u{2563}' => 0xb9, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
'\u{2551}' => 0xba, // BOX DRAWINGS DOUBLE VERTICAL
|
||||
'\u{2557}' => 0xbb, // BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
'\u{255d}' => 0xbc, // BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
'\u{255c}' => 0xbd, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
|
||||
'\u{255b}' => 0xbe, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
|
||||
'\u{2510}' => 0xbf, // BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
'\u{2514}' => 0xc0, // BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
'\u{2534}' => 0xc1, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
'\u{252c}' => 0xc2, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
'\u{251c}' => 0xc3, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
'\u{2500}' => 0xc4, // BOX DRAWINGS LIGHT HORIZONTAL
|
||||
'\u{253c}' => 0xc5, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
'\u{255e}' => 0xc6, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
|
||||
'\u{255f}' => 0xc7, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
|
||||
'\u{255a}' => 0xc8, // BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
'\u{2554}' => 0xc9, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
'\u{2569}' => 0xca, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
'\u{2566}' => 0xcb, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
'\u{2560}' => 0xcc, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
'\u{2550}' => 0xcd, // BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
'\u{256c}' => 0xce, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
'\u{2567}' => 0xcf, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
|
||||
'\u{2568}' => 0xd0, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
|
||||
'\u{2564}' => 0xd1, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
|
||||
'\u{2565}' => 0xd2, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
|
||||
'\u{2559}' => 0xd3, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
|
||||
'\u{2558}' => 0xd4, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
|
||||
'\u{2552}' => 0xd5, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
|
||||
'\u{2553}' => 0xd6, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
|
||||
'\u{256b}' => 0xd7, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
|
||||
'\u{256a}' => 0xd8, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
|
||||
'\u{2518}' => 0xd9, // BOX DRAWINGS LIGHT UP AND LEFT
|
||||
'\u{250c}' => 0xda, // BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
'\u{2588}' => 0xdb, // FULL BLOCK
|
||||
'\u{2584}' => 0xdc, // LOWER HALF BLOCK
|
||||
'\u{258c}' => 0xdd, // LEFT HALF BLOCK
|
||||
'\u{2590}' => 0xde, // RIGHT HALF BLOCK
|
||||
'\u{2580}' => 0xdf, // UPPER HALF BLOCK
|
||||
'\u{03b1}' => 0xe0, // GREEK SMALL LETTER ALPHA
|
||||
'\u{00df}' => 0xe1, // LATIN SMALL LETTER SHARP S
|
||||
'\u{0393}' => 0xe2, // GREEK CAPITAL LETTER GAMMA
|
||||
'\u{03c0}' => 0xe3, // GREEK SMALL LETTER PI
|
||||
'\u{03a3}' => 0xe4, // GREEK CAPITAL LETTER SIGMA
|
||||
'\u{03c3}' => 0xe5, // GREEK SMALL LETTER SIGMA
|
||||
'\u{00b5}' => 0xe6, // MICRO SIGN
|
||||
'\u{03c4}' => 0xe7, // GREEK SMALL LETTER TAU
|
||||
'\u{03a6}' => 0xe8, // GREEK CAPITAL LETTER PHI
|
||||
'\u{0398}' => 0xe9, // GREEK CAPITAL LETTER THETA
|
||||
'\u{03a9}' => 0xea, // GREEK CAPITAL LETTER OMEGA
|
||||
'\u{03b4}' => 0xeb, // GREEK SMALL LETTER DELTA
|
||||
'\u{221e}' => 0xec, // INFINITY
|
||||
'\u{03c6}' => 0xed, // GREEK SMALL LETTER PHI
|
||||
'\u{03b5}' => 0xee, // GREEK SMALL LETTER EPSILON
|
||||
'\u{2229}' => 0xef, // INTERSECTION
|
||||
'\u{2261}' => 0xf0, // IDENTICAL TO
|
||||
'\u{00b1}' => 0xf1, // PLUS-MINUS SIGN
|
||||
'\u{2265}' => 0xf2, // GREATER-THAN OR EQUAL TO
|
||||
'\u{2264}' => 0xf3, // LESS-THAN OR EQUAL TO
|
||||
'\u{2320}' => 0xf4, // TOP HALF INTEGRAL
|
||||
'\u{2321}' => 0xf5, // BOTTOM HALF INTEGRAL
|
||||
'\u{00f7}' => 0xf6, // DIVISION SIGN
|
||||
'\u{2248}' => 0xf7, // ALMOST EQUAL TO
|
||||
'\u{00b0}' => 0xf8, // DEGREE SIGN
|
||||
'\u{2219}' => 0xf9, // BULLET OPERATOR
|
||||
'\u{00b7}' => 0xfa, // MIDDLE DOT
|
||||
'\u{221a}' => 0xfb, // SQUARE ROOT
|
||||
'\u{207f}' => 0xfc, // SUPERSCRIPT LATIN SMALL LETTER N
|
||||
'\u{00b2}' => 0xfd, // SUPERSCRIPT TWO
|
||||
'\u{25a0}' => 0xfe, // BLACK SQUARE
|
||||
'\u{25a1}' => 0xff, // WHITE SQUARE
|
||||
_ => 254, // Unknown
|
||||
}
|
||||
}
|
||||
|
6
rust/k210-console/src/lib.rs
Normal file
6
rust/k210-console/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![no_std]
|
||||
|
||||
pub mod console;
|
||||
pub mod cp437;
|
||||
pub mod cp437_8x8;
|
||||
pub mod palette_xterm256;
|
@ -4,11 +4,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod console;
|
||||
mod cp437;
|
||||
mod cp437_8x8;
|
||||
mod lfsr;
|
||||
mod palette_xterm256;
|
||||
|
||||
use k210_hal::pac;
|
||||
use k210_hal::prelude::*;
|
||||
@ -22,8 +18,9 @@ use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
use riscv_rt::entry;
|
||||
|
||||
use crate::console::{Color, Console, ScreenImage, DISP_HEIGHT, DISP_WIDTH};
|
||||
use crate::palette_xterm256::PALETTE;
|
||||
use k210_console::console::{Color, Console, ScreenImage, DISP_HEIGHT, DISP_WIDTH};
|
||||
use k210_console::cp437;
|
||||
use k210_console::palette_xterm256::PALETTE;
|
||||
|
||||
/** Connect pins to internal functions */
|
||||
fn io_mux_init() {
|
||||
@ -120,7 +117,7 @@ fn main() -> ! {
|
||||
let spi = p.SPI0.constrain();
|
||||
let mut lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_RLDU);
|
||||
lcd.set_direction(lcd::direction::YX_LRUD);
|
||||
lcd.clear(lcd_colors::PURPLE);
|
||||
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
|
4
rust/weather/.gitignore
vendored
Normal file
4
rust/weather/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
# Do not check in secrets file
|
||||
config.rs
|
16
rust/weather/Cargo.toml
Normal file
16
rust/weather/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "weather"
|
||||
version = "0.1.0"
|
||||
authors = ["W.J. van der Laan <laanwj@protonmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
embedded-hal = { version = "0.2.1", features = ["unproven"] }
|
||||
nb = "0.1.1"
|
||||
riscv-rt = "0.5.0"
|
||||
k210-hal = "0.1.0"
|
||||
riscv = "0.5"
|
||||
k210-shared = { path = "../k210-shared" }
|
||||
k210-console = { path = "../k210-console" }
|
||||
esp8266at = { path = "../esp8266at", default-features = false }
|
||||
nom = { version = "4", default-features = false }
|
15
rust/weather/README.md
Normal file
15
rust/weather/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# `weather`
|
||||
|
||||
Uses the ESP8285 WiFi chip of the Maix Go to fetch weather data from
|
||||
[wttr.in](https://wttr.in) and print it to the display using `k210-console`.
|
||||
|
||||
As it needs to connect to an access point first, this needs configuration of one
|
||||
to connect to in `src/config.rs`:
|
||||
|
||||
```bash
|
||||
cp src/config.rs.example src/config.rs
|
||||
vim src/config.rs # ...
|
||||
```
|
||||
|
||||
Set `<ap name>` and `<ap password>` accordingly. Do not check in `src/config.rs` !
|
||||
(gitignore settings should prevent this)
|
8
rust/weather/src/config.rs.example
Normal file
8
rust/weather/src/config.rs.example
Normal file
@ -0,0 +1,8 @@
|
||||
/** Secrets */
|
||||
|
||||
/** Access point name */
|
||||
pub const APNAME: &str = "<ap name>";
|
||||
|
||||
/** Access point password */
|
||||
pub const APPASS: &str = "<ap password>";
|
||||
|
236
rust/weather/src/main.rs
Normal file
236
rust/weather/src/main.rs
Normal file
@ -0,0 +1,236 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::str;
|
||||
use embedded_hal::serial;
|
||||
use esp8266at::handler::{NetworkEvent, SerialNetworkHandler};
|
||||
use esp8266at::response::{parse_response, ConnectionType};
|
||||
use esp8266at::traits::{self, Write};
|
||||
use k210_hal::pac;
|
||||
use k210_hal::prelude::*;
|
||||
use k210_hal::stdout::Stdout;
|
||||
use k210_shared::board::def::io;
|
||||
use k210_shared::board::lcd::{self, LCD, LCDHL};
|
||||
use k210_shared::soc::fpioa;
|
||||
use k210_shared::soc::gpio;
|
||||
use k210_shared::soc::gpiohs;
|
||||
use k210_shared::soc::sleep::usleep;
|
||||
use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
use nb::block;
|
||||
use nom::Offset;
|
||||
use riscv::register::mcycle;
|
||||
use riscv_rt::entry;
|
||||
use k210_console::console::{Console, ScreenImage, DISP_HEIGHT, DISP_WIDTH};
|
||||
|
||||
mod config;
|
||||
|
||||
const DEFAULT_BAUD: u32 = 115_200;
|
||||
const TIMEOUT: usize = 390_000_000 * 40 / 115200;
|
||||
|
||||
struct WriteAdapter<'a, TX>
|
||||
where
|
||||
TX: serial::Write<u8>,
|
||||
{
|
||||
tx: &'a mut TX,
|
||||
}
|
||||
impl<'a, TX> WriteAdapter<'a, TX>
|
||||
where
|
||||
TX: serial::Write<u8>,
|
||||
TX::Error: core::fmt::Debug,
|
||||
{
|
||||
fn new(tx: &'a mut TX) -> Self {
|
||||
Self { tx }
|
||||
}
|
||||
}
|
||||
impl<'a, TX> traits::Write for WriteAdapter<'a, TX>
|
||||
where
|
||||
TX: serial::Write<u8>,
|
||||
TX::Error: core::fmt::Debug,
|
||||
{
|
||||
type Error = TX::Error;
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
|
||||
for ch in buf {
|
||||
block!(self.tx.write(*ch))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/** Connect pins to internal functions */
|
||||
fn io_init() {
|
||||
/* Init SPI IO map and function settings */
|
||||
fpioa::set_function(
|
||||
io::LCD_RST.into(),
|
||||
fpioa::function::gpiohs(lcd::RST_GPIONUM),
|
||||
);
|
||||
fpioa::set_io_pull(io::LCD_RST.into(), fpioa::pull::DOWN); // outputs must be pull-down
|
||||
fpioa::set_function(io::LCD_DC.into(), fpioa::function::gpiohs(lcd::DCX_GPIONUM));
|
||||
fpioa::set_io_pull(io::LCD_DC.into(), fpioa::pull::DOWN);
|
||||
fpioa::set_function(io::LCD_CS.into(), fpioa::function::SPI0_SS3);
|
||||
fpioa::set_function(io::LCD_WR.into(), fpioa::function::SPI0_SCLK);
|
||||
|
||||
sysctl::set_spi0_dvp_data(true);
|
||||
|
||||
/* Set dvp and spi pin to 1.8V */
|
||||
sysctl::set_power_mode(sysctl::power_bank::BANK6, sysctl::io_power_mode::V18);
|
||||
sysctl::set_power_mode(sysctl::power_bank::BANK7, sysctl::io_power_mode::V18);
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let p = pac::Peripherals::take().unwrap();
|
||||
let clocks = k210_hal::clock::Clocks::new();
|
||||
|
||||
usleep(200000);
|
||||
io_init();
|
||||
|
||||
// Configure UARTHS (→host)
|
||||
let mut serial = p.UARTHS.constrain(DEFAULT_BAUD.bps(), &clocks);
|
||||
let (mut tx, mut rx) = serial.split();
|
||||
let mut debug = Stdout(&mut tx);
|
||||
|
||||
// Configure UART1 (→WIFI)
|
||||
sysctl::clock_enable(sysctl::clock::UART1);
|
||||
sysctl::reset(sysctl::reset::UART1);
|
||||
fpioa::set_function(io::WIFI_RX as u8, fpioa::function::UART1_TX);
|
||||
fpioa::set_function(io::WIFI_TX as u8, fpioa::function::UART1_RX);
|
||||
fpioa::set_function(io::WIFI_EN as u8, fpioa::function::GPIOHS8);
|
||||
fpioa::set_io_pull(io::WIFI_EN as u8, fpioa::pull::DOWN);
|
||||
gpiohs::set_pin(8, true);
|
||||
gpiohs::set_direction(8, gpio::direction::OUTPUT);
|
||||
let mut wifi_serial = p.UART1.constrain(DEFAULT_BAUD.bps(), &clocks);
|
||||
let (mut wtx, mut wrx) = wifi_serial.split();
|
||||
|
||||
let mut wa = WriteAdapter::new(&mut wtx);
|
||||
let mut sh = SerialNetworkHandler::new(&mut wa, config::APNAME.as_bytes(), config::APPASS.as_bytes());
|
||||
|
||||
// LCD ini
|
||||
let spi = p.SPI0.constrain();
|
||||
let mut lcd = LCD::new(spi);
|
||||
lcd.init();
|
||||
lcd.set_direction(lcd::direction::YX_LRUD);
|
||||
let mut console: Console = Console::new();
|
||||
|
||||
let mut i:u16 = 0;
|
||||
writeln!(console, "\x1b[48;2;128;192;255;38;5;0m WEATHER \x1b[0m \x1b[38;2;128;128;128mfetching...\x1b[0m").unwrap();
|
||||
|
||||
// Start off connection process state machine
|
||||
sh.start(false);
|
||||
writeln!(console, "∙ Connecting to AP").unwrap();
|
||||
|
||||
let mut serial_buf = [0u8; 2560]; // 2048 + some
|
||||
let mut ofs: usize = 0;
|
||||
|
||||
let mut cur_link = 0;
|
||||
loop {
|
||||
if console.dirty {
|
||||
let mut image: ScreenImage = [0; DISP_WIDTH * DISP_HEIGHT / 2];
|
||||
console.render(&mut image);
|
||||
lcd.draw_picture(0, 0, DISP_WIDTH as u16, DISP_HEIGHT as u16, &image);
|
||||
console.dirty = false;
|
||||
}
|
||||
|
||||
// Receive byte into buffer
|
||||
if let Ok(ch) = wrx.read() {
|
||||
let ofs0 = ofs;
|
||||
serial_buf[ofs] = ch;
|
||||
ofs += 1;
|
||||
let mut lastrecv = mcycle::read();
|
||||
loop {
|
||||
// Read until we stop receiving for a certain duration
|
||||
// This is a hack around the fact that in the time that the parser runs,
|
||||
// more than one FIFO full of characters can be received so characters could be
|
||||
// lost. The right way would be to receive in an interrupt handler, but,
|
||||
// we don't have that yet.
|
||||
if let Ok(ch) = wrx.read() {
|
||||
serial_buf[ofs] = ch;
|
||||
ofs += 1;
|
||||
lastrecv = mcycle::read();
|
||||
} else if (mcycle::read().wrapping_sub(lastrecv)) >= TIMEOUT {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//writeln!(debug, "ofs: {} received {} chars {:?}", ofs0, ofs - ofs0,
|
||||
// &serial_buf[ofs0..ofs]).unwrap();
|
||||
|
||||
// Loop as long as there's something in the buffer to parse, starting at the
|
||||
// beginning
|
||||
let mut start = 0;
|
||||
while start < ofs {
|
||||
// try parsing
|
||||
let tail = &serial_buf[start..ofs];
|
||||
let erase = match parse_response(tail) {
|
||||
Ok((residue, resp)) => {
|
||||
sh.message(&resp, &mut |port, ev, debug| {
|
||||
match ev {
|
||||
NetworkEvent::Ready => {
|
||||
writeln!(console, "∙ Connected to AP").unwrap();
|
||||
cur_link = port.connect(ConnectionType::TCP, b"wttr.in", 80).unwrap();
|
||||
writeln!(console, "∙ \x1b[38;5;141m[{}]\x1b[0m Opening TCP conn", cur_link).unwrap();
|
||||
}
|
||||
NetworkEvent::Error => {
|
||||
writeln!(console, "∙ Could not connect to AP").unwrap();
|
||||
}
|
||||
NetworkEvent::ConnectionEstablished(link) => {
|
||||
if link == cur_link {
|
||||
writeln!(console, "∙ \x1b[38;5;141m[{}]\x1b[0m Sending HTTP request", link).unwrap();
|
||||
port.write_all(b"GET /?0qA HTTP/1.1\r\nHost: wttr.in\r\nConnection: close\r\nUser-Agent: Weather-Spy\r\n\r\n").unwrap();
|
||||
port.send(link).unwrap();
|
||||
}
|
||||
}
|
||||
NetworkEvent::Data(link, data) => {
|
||||
// write!(debug, "{}", str::from_utf8(data).unwrap());
|
||||
if link == cur_link {
|
||||
console.puts(str::from_utf8(data).unwrap_or("???"));
|
||||
}
|
||||
}
|
||||
NetworkEvent::ConnectionClosed(link) => {
|
||||
writeln!(console, "∙ \x1b[38;5;141m[{}]\x1b[0m \x1b[38;2;100;100;100m[closed]\x1b[0m", link).unwrap();
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}, &mut debug).unwrap();
|
||||
|
||||
tail.offset(residue)
|
||||
}
|
||||
Err(nom::Err::Incomplete(_)) => {
|
||||
// Incomplete, ignored, just retry after a new receive
|
||||
0
|
||||
}
|
||||
Err(err) => {
|
||||
writeln!(debug, "err: {:?}", err).unwrap();
|
||||
// Erase unparseable data to next line, if line is complete
|
||||
if let Some(ofs) = tail.iter().position(|&x| x == b'\n') {
|
||||
ofs + 1
|
||||
} else {
|
||||
// If not, retry next time
|
||||
0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if erase == 0 {
|
||||
// End of input or remainder unparseable
|
||||
break;
|
||||
}
|
||||
start += erase;
|
||||
}
|
||||
// Erase everything before new starting offset
|
||||
for i in start..ofs {
|
||||
serial_buf[i - start] = serial_buf[i];
|
||||
}
|
||||
ofs -= start;
|
||||
}
|
||||
|
||||
/*
|
||||
if let Ok(ch) = rx.read() {
|
||||
let _res = block!(wtx.write(ch));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user