]> patrickod personal git archive - keywing-rs.git/commitdiff
Working little text editor
authorJames Munns <james.munns@ferrous-systems.com>
Tue, 26 May 2020 23:15:17 +0000 (01:15 +0200)
committerJames Munns <james.munns@ferrous-systems.com>
Tue, 26 May 2020 23:15:17 +0000 (01:15 +0200)
.gitmodules
bbq10kbd [new submodule]
keywing/Cargo.lock
keywing/Cargo.toml
keywing/src/buffer.rs
keywing/src/main.rs

index ef75d6c17d134580de10a5a42c4c9825b492b18b..8971b258df421a83404f7ec16ea973eec22da24b 100644 (file)
@@ -4,3 +4,6 @@
 [submodule "nrf-hal"]
        path = nrf-hal
        url = git@github.com:jamesmunns/nrf-hal.git
+[submodule "bbq10kbd"]
+       path = bbq10kbd
+       url = https://github.com/jamesmunns/bbq10kbd
diff --git a/bbq10kbd b/bbq10kbd
new file mode 160000 (submodule)
index 0000000..5900ad8
--- /dev/null
+++ b/bbq10kbd
@@ -0,0 +1 @@
+Subproject commit 5900ad89a6221e93702278a5fadc8dd2b65f0479
index 7b27e81104b82ff0c208b1993d3d2ee0a95bf6b9..56bb41201d3fea22bb57ae6a73d68094412b8968 100644 (file)
@@ -25,6 +25,13 @@ dependencies = [
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "bbq10kbd"
+version = "0.1.0"
+dependencies = [
+ "embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "byteorder"
 version = "1.3.2"
@@ -285,6 +292,7 @@ dependencies = [
 name = "tiny-nrf52"
 version = "0.1.0"
 dependencies = [
+ "bbq10kbd 0.1.0",
  "cortex-m 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cortex-m-rt 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "embedded-graphics 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
index 85b93b8ac66d6150764d8db43fbeb7bf53152a60..e1f5723c32b9083ee20eb8e7b7367fec4786dc2b 100644 (file)
@@ -17,6 +17,10 @@ embedded-graphics = "0.6.2"
 version = "0.3.0"
 path = "../ili9341-rs"
 
+[dependencies.bbq10kbd]
+version = "0.1.0"
+path = "../bbq10kbd"
+
 [dependencies.nrf52840-hal]
 version = "0.10.0"
 features = ["rt"]
index da912ad88afcf4876ac81d64537bbc888583c6b7..f334eb4d5d5338e97cb2158c07a5ff1414beba40 100644 (file)
@@ -12,32 +12,38 @@ use embedded_graphics::{
 
 pub struct FrameBuffer<'a> {
     buf: &'a mut [[u16; 320]; 240],
+    dirty: bool,
 }
 
 impl<'a> FrameBuffer<'a> {
     pub fn new(raw: &'a mut [[u16; 320]; 240]) -> Self {
-        Self {
-            buf: raw
-        }
+        Self { buf: raw, dirty: false }
     }
 
-    pub fn inner(&self) -> &[u16] {
-        unsafe {
-            core::slice::from_raw_parts(self.buf.as_ptr().cast::<u16>(), (self.width() * self.height()) as usize)
+    pub fn inner(&mut self) -> Option<&[u16]> {
+        if self.dirty {
+            self.dirty = false;
+            Some(unsafe {
+                core::slice::from_raw_parts(
+                    self.buf.as_ptr().cast::<u16>(),
+                    (self.width() * self.height()) as usize,
+                )
+            })
+        } else {
+            None
         }
     }
 
     fn width(&self) -> u32 {
-        self.buf.len() as u32
+        self.buf[0].len() as u32
     }
 
     fn height(&self) -> u32 {
-        self.buf[0].len() as u32
+        self.buf.len() as u32
     }
 }
 
-impl<'a> DrawTarget<Rgb565> for FrameBuffer<'a>
-{
+impl<'a> DrawTarget<Rgb565> for FrameBuffer<'a> {
     type Error = ();
 
     fn size(&self) -> Size {
@@ -50,13 +56,12 @@ impl<'a> DrawTarget<Rgb565> for FrameBuffer<'a>
         if pos.x < 0 || pos.y < 0 || pos.x >= self.width() as i32 || pos.y >= self.height() as i32 {
             return Ok(());
         }
-
+        self.dirty = true;
         self.buf[pos.y as usize][pos.x as usize] = swap(RawU16::from(color).into_inner());
         Ok(())
     }
 }
 
 const fn swap(inp: u16) -> u16 {
-    (inp & 0x00FF) << 8 |
-    (inp & 0xFF00) >> 8
+    (inp & 0x00FF) << 8 | (inp & 0xFF00) >> 8
 }
index fd713503492fd18b2c906c1443cade2fc638dd25..15df83b6a085c773dc318c48a87743b1dfbc4af2 100644 (file)
@@ -2,36 +2,23 @@
 #![no_main]
 
 // Panic provider crate
-use panic_persist;
 use cortex_m;
+use panic_persist;
 
 // Used to set the program entry point
 use cortex_m_rt::entry;
 
 // Provides definitions for our development board
 use nrf52840_hal::{
+    gpio::{p0::Parts as P0Parts, p1::Parts as P1Parts, Level},
     prelude::*,
-    target::{Peripherals, CorePeripherals},
-    Timer,
-    Rng,
-    Spim,
-    spim::{
-        Pins as SpimPins,
-        Frequency as SpimFrequency,
-        MODE_0,
-    },
-    gpio::{
-        p0::Parts as P0Parts,
-        p1::Parts as P1Parts,
-        Level,
-    },
-    Clocks,
+    spim::{Frequency as SpimFrequency, Pins as SpimPins, MODE_0},
+    target::{CorePeripherals, Peripherals},
+    twim::{Frequency as TwimFrequency, Pins as TwimPins},
+    Clocks, Rng, Spim, Timer, Twim,
 };
 
-use rtt_target::{
-    rprint, rprintln,
-    rtt_init_print,
-};
+use rtt_target::{rprint, rprintln, rtt_init_print};
 
 use embedded_graphics::{
     fonts::{Font8x16, Text},
@@ -40,6 +27,8 @@ use embedded_graphics::{
     style::{TextStyle, TextStyleBuilder},
 };
 
+use bbq10kbd::{Bbq10Kbd, KeyRaw};
+
 mod buffer;
 
 use ili9341::{Ili9341, Orientation};
@@ -64,31 +53,107 @@ const TEXT_SAMPLE: &[&str] = &[
 
 const TEXT_SAMPLE2: &[&[(i32, Rgb565, &str)]] = &[
     // "for x in 0..10 {",
-    &[(0, Rgb565::RED, "for "), (4, Rgb565::WHITE, "x "), (6, Rgb565::RED, "in "), (9, Rgb565::MAGENTA, "0"), (10, Rgb565::RED, ".."), (12, Rgb565::MAGENTA, "10"), (14, Rgb565::WHITE, " {")],
+    &[
+        (0, Rgb565::RED, "for "),
+        (4, Rgb565::WHITE, "x "),
+        (6, Rgb565::RED, "in "),
+        (9, Rgb565::MAGENTA, "0"),
+        (10, Rgb565::RED, ".."),
+        (12, Rgb565::MAGENTA, "10"),
+        (14, Rgb565::WHITE, " {"),
+    ],
     // "  for y in 0..10 {",
-    &[(2, Rgb565::RED, "for "), (6, Rgb565::WHITE, "y "), (8, Rgb565::RED, "in "), (11, Rgb565::MAGENTA, "0"), (12, Rgb565::RED, ".."), (14, Rgb565::MAGENTA, "10"), (16, Rgb565::WHITE, " {")],
+    &[
+        (2, Rgb565::RED, "for "),
+        (6, Rgb565::WHITE, "y "),
+        (8, Rgb565::RED, "in "),
+        (11, Rgb565::MAGENTA, "0"),
+        (12, Rgb565::RED, ".."),
+        (14, Rgb565::MAGENTA, "10"),
+        (16, Rgb565::WHITE, " {"),
+    ],
     // "    let rand: u16 = rng.random_u16();",
-    &[(4, Rgb565::CYAN, "let "), (8, Rgb565::WHITE, "rand: "), (14, Rgb565::CYAN, "u16 "), (18, Rgb565::RED, "= "), (20, Rgb565::WHITE, "rng."), (24, Rgb565::CYAN, "random_u16"), (34, Rgb565::WHITE, "();")],
+    &[
+        (4, Rgb565::CYAN, "let "),
+        (8, Rgb565::WHITE, "rand: "),
+        (14, Rgb565::CYAN, "u16 "),
+        (18, Rgb565::RED, "= "),
+        (20, Rgb565::WHITE, "rng."),
+        (24, Rgb565::CYAN, "random_u16"),
+        (34, Rgb565::WHITE, "();"),
+    ],
     // "    buffy.iter_mut().for_each(|px| {",
-    &[(4, Rgb565::WHITE, "buffy."), (10, Rgb565::CYAN, "iter_mut"), (18, Rgb565::WHITE, "()."), (21, Rgb565::CYAN, "for_each"), (29, Rgb565::WHITE, "(|"), (31, Rgb565::YELLOW, "px"), (33, Rgb565::WHITE, "| {")],
+    &[
+        (4, Rgb565::WHITE, "buffy."),
+        (10, Rgb565::CYAN, "iter_mut"),
+        (18, Rgb565::WHITE, "()."),
+        (21, Rgb565::CYAN, "for_each"),
+        (29, Rgb565::WHITE, "(|"),
+        (31, Rgb565::YELLOW, "px"),
+        (33, Rgb565::WHITE, "| {"),
+    ],
     // "      *px = swap(rand)",
-    &[(6, Rgb565::RED, "*"), (7, Rgb565::WHITE, "px "), (10, Rgb565::RED, "= "), (12, Rgb565::CYAN, "swap"), (16, Rgb565::WHITE, "(rand)")],
+    &[
+        (6, Rgb565::RED, "*"),
+        (7, Rgb565::WHITE, "px "),
+        (10, Rgb565::RED, "= "),
+        (12, Rgb565::CYAN, "swap"),
+        (16, Rgb565::WHITE, "(rand)"),
+    ],
     // "    });",
     &[(4, Rgb565::WHITE, "});")],
     // "    lcd.draw_raw(",
-    &[(4, Rgb565::WHITE, "lcd."), (8, Rgb565::CYAN, "draw_raw"), (16, Rgb565::WHITE, "(")],
+    &[
+        (4, Rgb565::WHITE, "lcd."),
+        (8, Rgb565::CYAN, "draw_raw"),
+        (16, Rgb565::WHITE, "("),
+    ],
     // "      32 * x,",
-    &[(6, Rgb565::MAGENTA, "32 "), (9, Rgb565::RED, "* "), (11, Rgb565::WHITE, "x,")],
+    &[
+        (6, Rgb565::MAGENTA, "32 "),
+        (9, Rgb565::RED, "* "),
+        (11, Rgb565::WHITE, "x,"),
+    ],
     // "      24 * y,",
-    &[(6, Rgb565::MAGENTA, "24 "), (9, Rgb565::RED, "* "), (11, Rgb565::WHITE, "y,")],
+    &[
+        (6, Rgb565::MAGENTA, "24 "),
+        (9, Rgb565::RED, "* "),
+        (11, Rgb565::WHITE, "y,"),
+    ],
     // "      (32 * (x + 1)) - 1,",
-    &[(6, Rgb565::WHITE, "("), (7, Rgb565::MAGENTA,"32 "), (10, Rgb565::RED, "* "), (12, Rgb565::WHITE, "(x "), (15, Rgb565::RED, "+ "), (17, Rgb565::MAGENTA, "1"), (18, Rgb565::WHITE, ")) "), (21, Rgb565::RED, "- "), (23, Rgb565::MAGENTA, "1"), (24, Rgb565::WHITE, ",")],
+    &[
+        (6, Rgb565::WHITE, "("),
+        (7, Rgb565::MAGENTA, "32 "),
+        (10, Rgb565::RED, "* "),
+        (12, Rgb565::WHITE, "(x "),
+        (15, Rgb565::RED, "+ "),
+        (17, Rgb565::MAGENTA, "1"),
+        (18, Rgb565::WHITE, ")) "),
+        (21, Rgb565::RED, "- "),
+        (23, Rgb565::MAGENTA, "1"),
+        (24, Rgb565::WHITE, ","),
+    ],
     // "      (24 * (y + 1)) - 1,",
-    &[(6, Rgb565::WHITE, "("), (7, Rgb565::MAGENTA,"24 "), (10, Rgb565::RED, "* "), (12, Rgb565::WHITE, "(y "), (15, Rgb565::RED, "+ "), (17, Rgb565::MAGENTA, "1"), (18, Rgb565::WHITE, ")) "), (21, Rgb565::RED, "- "), (23, Rgb565::MAGENTA, "1"), (24, Rgb565::WHITE, ",")],
+    &[
+        (6, Rgb565::WHITE, "("),
+        (7, Rgb565::MAGENTA, "24 "),
+        (10, Rgb565::RED, "* "),
+        (12, Rgb565::WHITE, "(y "),
+        (15, Rgb565::RED, "+ "),
+        (17, Rgb565::MAGENTA, "1"),
+        (18, Rgb565::WHITE, ")) "),
+        (21, Rgb565::RED, "- "),
+        (23, Rgb565::MAGENTA, "1"),
+        (24, Rgb565::WHITE, ","),
+    ],
     // "      &buffy,",
     &[(6, Rgb565::RED, "&"), (7, Rgb565::WHITE, "buffy,")],
     // "    ).unwrap();",
-    &[(4, Rgb565::WHITE, ")."), (6, Rgb565::CYAN, "unwrap"), (12, Rgb565::WHITE, "();")],
+    &[
+        (4, Rgb565::WHITE, ")."),
+        (6, Rgb565::CYAN, "unwrap"),
+        (12, Rgb565::WHITE, "();"),
+    ],
     // "  }",
     &[(2, Rgb565::WHITE, "}")],
     // "}",
@@ -121,7 +186,6 @@ fn inner_main() -> Result<(), &'static str> {
         rprintln!("Clean boot!");
     }
 
-
     let p0 = P0Parts::new(board.P0);
     let p1 = P1Parts::new(board.P1);
 
@@ -130,8 +194,23 @@ fn inner_main() -> Result<(), &'static str> {
     let lcd_cs = p0.p0_26; // GPIO9, D9,
     let lcd_dc = p0.p0_27; // GPIO10, D10
 
-    // Pull the neopixel line low so noise doesn't make it turn on spuriously
+    let kbd_sda = p0.p0_12.into_floating_input().degrade();
+    let kbd_scl = p0.p0_11.into_floating_input().degrade();
+
+    let kbd_i2c = Twim::new(
+        board.TWIM0,
+        TwimPins {
+            sda: kbd_sda,
+            scl: kbd_scl,
+        },
+        TwimFrequency::K100,
+    );
+
+    let mut kbd = Bbq10Kbd::new(kbd_i2c);
+
+    // Pull the neopixel lines low so noise doesn't make it turn on spuriously
     let keywing_neopixel = p0.p0_06.into_push_pull_output(Level::Low); // GPIO11, D11
+    let feather_neopixel = p0.p0_16.into_push_pull_output(Level::Low);
 
     let spim = Spim::new(
         board.SPIM3,
@@ -151,11 +230,12 @@ fn inner_main() -> Result<(), &'static str> {
         lcd_dc.into_push_pull_output(Level::High),
         kbd_lcd_reset.into_push_pull_output(Level::High),
         &mut delay,
-    ).unwrap();
+    )
+    .unwrap();
 
     lcd.set_orientation(Orientation::Landscape).unwrap();
 
-    let mut buffy = [0u16; 24 * 32];
+    let mut _buffy = [0u16; 24 * 32];
     let mut buffy2 = [[0u16; 320]; 240];
 
     let mut fbuffy = buffer::FrameBuffer::new(&mut buffy2);
@@ -163,321 +243,208 @@ fn inner_main() -> Result<(), &'static str> {
     // //                                     rrrrr gggggg bbbbb
     // buffy.iter_mut().for_each(|px| *px = 0b11111_000000_00000);
 
-    let style = TextStyleBuilder::new(Font8x16)
+    let mut style = TextStyleBuilder::new(Font8x16)
         .text_color(Rgb565::WHITE)
         .background_color(Rgb565::BLACK)
         .build();
 
-    loop {
+    let mut ctr: u8 = 0;
+    kbd.set_backlight(ctr).unwrap();
 
-        rprintln!("Start colors raw");
-
-        for x in 0..10 {
-            for y in 0..10 {
-                let rand: u16 = rng.random_u16();
-                buffy.iter_mut().for_each(|px| {
-                    *px = swap(rand)
-                });
-
-                lcd.draw_raw(
-                    32 * x,
-                    24 * y,
-                    (32 * (x + 1)) - 1,
-                    (24 * (y + 1)) - 1,
-                    &buffy,
-                ).unwrap();
-            }
-        }
+    let vers = kbd.get_version().unwrap();
 
-        rprintln!("Done.\n");
+    rprintln!("Vers: {:?}", vers);
 
-        timer.delay_ms(1000u16);
+    kbd.sw_reset().unwrap();
+    timer.delay_ms(10u8);
 
-        rprintln!("Start colors raw");
+    let vers = kbd.get_version().unwrap();
 
-        for x in 0..10 {
-            for y in 0..10 {
-                let rand: u16 = 0;
-                buffy.iter_mut().for_each(|px| {
-                    *px = swap(rand)
-                });
+    rprintln!("Vers: {:?}", vers);
 
-                lcd.draw_raw(
-                    32 * x,
-                    24 * y,
-                    (32 * (x + 1)) - 1,
-                    (24 * (y + 1)) - 1,
-                    &buffy,
-                ).unwrap();
-            }
-        }
-
-        rprintln!("Done.\n");
-
-
-        timer.delay_ms(1000u16);
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_000000_00000));
-        // rprintln!("Start black");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        rprintln!("text start");
-
-        for row in 0..15 {
-            Text::new(
-                TEXT_SAMPLE[row as usize],
-                Point::new(0, row * 16)
-            ).into_styled(style)
-            .draw(&mut lcd)
-            .unwrap();
-        }
-
-        rprintln!("text done");
-
-        timer.delay_ms(3000u16);
-
-        rprintln!("Start colors raw");
+    let mut cursor_y = 0;
+    let mut cursor_x = 0;
 
-        for x in 0..10 {
-            for y in 0..10 {
-                let rand: u16 = 0;
-                buffy.iter_mut().for_each(|px| {
-                    *px = swap(rand)
-                });
-
-                lcd.draw_raw(
-                    32 * x,
-                    24 * y,
-                    (32 * (x + 1)) - 1,
-                    (24 * (y + 1)) - 1,
-                    &buffy,
-                ).unwrap();
-            }
-        }
+    let mut cursor = Cursor { x: 0, y: 0 };
 
-        rprintln!("Done.\n");
+    lcd.clear(Rgb565::BLACK).map_err(|_| "Fade to error")?;
+    fbuffy.clear(Rgb565::BLACK).map_err(|_| "Fade to error")?;
 
+    loop {
+        let key = kbd.get_fifo_key_raw().map_err(|_| "bad fifo")?;
 
-        timer.delay_ms(1000u16);
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_000000_00000));
-        // rprintln!("Start black");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        rprintln!("text2 start");
-
-        for (i, row) in TEXT_SAMPLE2.iter().enumerate() {
-            for (offset, color, text) in row.iter() {
-                let styled = TextStyleBuilder::new(Font8x16)
-                    .text_color(*color)
+        match key {
+            // LL
+            KeyRaw::Pressed(6) => {
+                style = TextStyleBuilder::new(Font8x16)
+                    .text_color(Rgb565::WHITE)
                     .background_color(Rgb565::BLACK)
                     .build();
-
-                Text::new(
-                    text,
-                    Point::new(*offset * 8, i as i32 * 16)
-                ).into_styled(styled)
-                .draw(&mut lcd)
-                .unwrap();
             }
-        }
-
-        rprintln!("text2 done");
-
-        timer.delay_ms(3000u16);
-
-        rprintln!("Start colors raw");
-
-        for x in 0..10 {
-            for y in 0..10 {
-                let rand: u16 = 0;
-                buffy.iter_mut().for_each(|px| {
-                    *px = swap(rand)
-                });
-
-                lcd.draw_raw(
-                    32 * x,
-                    24 * y,
-                    (32 * (x + 1)) - 1,
-                    (24 * (y + 1)) - 1,
-                    &buffy,
-                ).unwrap();
+            // LR
+            KeyRaw::Pressed(17) => {
+                style = TextStyleBuilder::new(Font8x16)
+                    .text_color(Rgb565::RED)
+                    .background_color(Rgb565::BLACK)
+                    .build();
             }
-        }
-
-        rprintln!("Done.\n");
-
-        timer.delay_ms(1000u16);
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_000000_00000));
-        // rprintln!("Start black");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        timer.start(1_000_000u32);
-
-        let start: u32 = timer.read();
-
-        for row in 0..15 {
-            Text::new(
-                TEXT_SAMPLE[row as usize],
-                Point::new(0, row * 16)
-            ).into_styled(style)
-            .draw(&mut fbuffy)
-            .unwrap();
-        }
-
-        let middle: u32 = timer.read();
-
-        lcd.draw_raw(0, 0, 319, 239, fbuffy.inner()).unwrap();
-
-        let end: u32 = timer.read();
-
-        rprintln!("text buffered done");
-        rprintln!("start: 0x{:08X}, middle: 0x{:08X}, end: 0x{:08X}", start, middle, end);
-        rprintln!("render: {} cycs", middle - start);
-        rprintln!("draw:   {} cycs", end - middle);
-
-
-
-
-
-        timer.delay_ms(3000u16);
-
-        rprintln!("Start colors raw");
-
-        for x in 0..10 {
-            for y in 0..10 {
-                let rand: u16 = 0;
-                buffy.iter_mut().for_each(|px| {
-                    *px = swap(rand)
-                });
-
-                lcd.draw_raw(
-                    32 * x,
-                    24 * y,
-                    (32 * (x + 1)) - 1,
-                    (24 * (y + 1)) - 1,
-                    &buffy,
-                ).unwrap();
+            // RL
+            KeyRaw::Pressed(7) => {
+                style = TextStyleBuilder::new(Font8x16)
+                    .text_color(Rgb565::GREEN)
+                    .background_color(Rgb565::BLACK)
+                    .build();
             }
-        }
-
-        rprintln!("Done.\n");
-
-
-        timer.delay_ms(1000u16);
-
-        rprintln!("text2 buffered middle");
-
-        for (i, row) in TEXT_SAMPLE2.iter().enumerate() {
-            for (offset, color, text) in row.iter() {
-                let styled = TextStyleBuilder::new(Font8x16)
-                    .text_color(*color)
+            // RR
+            KeyRaw::Pressed(18) => {
+                style = TextStyleBuilder::new(Font8x16)
+                    .text_color(Rgb565::BLUE)
                     .background_color(Rgb565::BLACK)
                     .build();
+            }
+            // Up
+            KeyRaw::Pressed(1) => {
+                cursor.up();
+            }
+            // Down
+            KeyRaw::Pressed(2) => {
+                cursor.down();
+            }
+            // Left
+            KeyRaw::Pressed(3) => {
+                cursor.left();
+            }
+            // Right
+            KeyRaw::Pressed(4) => {
+                cursor.right();
+            }
+            // Center
+            KeyRaw::Pressed(5) => {
+                kbd.sw_reset().unwrap();
+                cursor = Cursor { x: 0, y: 0 };
+                fbuffy.clear(Rgb565::BLACK).map_err(|_| "Fade to error")?;
+            }
+            // Backspace
+            KeyRaw::Pressed(8) => {
+                cursor.left();
+                Text::new(" ", cursor.pos())
+                    .into_styled(style)
+                    .draw(&mut fbuffy)
+                    .map_err(|_| "bad lcd")?;
+            }
+            // Enter
+            KeyRaw::Pressed(10) => {
+                cursor.enter();
+            }
+            KeyRaw::Pressed(k) => {
+                rprintln!("Got key {}", k);
+                if let Ok(s) = core::str::from_utf8(&[k]) {
+                    Text::new(s, cursor.pos())
+                        .into_styled(style)
+                        .draw(&mut fbuffy)
+                        .map_err(|_| "bad lcd")?;
+
+                    cursor.right();
+                }
+            }
+            KeyRaw::Invalid => {
+                if let Some(buf) = fbuffy.inner() {
+                    timer.start(1_000_000u32);
+                    lcd.draw_raw(
+                        0, 0,
+                        319, 239,
+                        buf
+                    ).map_err(|_| "bad buffy")?;
+                    let done = timer.read();
+                    rprintln!("Drew in {}ms.", done / 1000);
+                } else {
+                    timer.delay_ms(38u8);
+                }
 
-                Text::new(
-                    text,
-                    Point::new(*offset * 8, i as i32 * 16)
-                ).into_styled(styled)
-                .draw(&mut fbuffy)
-                .unwrap();
             }
+            _ => {}
         }
+    }
 
-        rprintln!("text2 buffered middle");
-
-        lcd.draw_raw(0, 0, 319, 239, fbuffy.inner()).unwrap();
-
-        rprintln!("text2 buffered done");
-
-        timer.delay_ms(3000u16);
-
-        continue;
-
-
-        // // SHOULD BE
-        // //                                      rrrrr gggggg bbbbb
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b11111_000000_00000));
-        // rprintln!("Start red");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        // timer.delay_ms(250u16);
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_111111_00000));
-        // rprintln!("Start green");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        // timer.delay_ms(250u16);
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_000000_11111));
-        // rprintln!("Start blue");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_000000_00000));
-        // rprintln!("Start black");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
+    Ok(())
+}
 
-        // 240 / 16: 15
-        // 320 /  8: 40
+struct Cursor {
+    x: i32,
+    y: i32,
+}
 
-        let text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+impl Cursor {
+    fn up(&mut self) {
+        self.y -= 1;
+        if self.y < 0 {
+            self.y = 0;
+        }
+    }
 
-        let mut textiter = text.chars().cycle();
+    fn down(&mut self) {
+        self.y += 1;
+        if self.y >= 15 {
+            self.y = 14;
+        }
+    }
 
-        for row in 0..15 {
-            for col in 0..40 {
-                let mut buf = [0u8; 4];
-                let txt = textiter.next().unwrap().encode_utf8(&mut buf);
-                Text::new(
-                    txt,
-                    Point::new(col * 8, row * 16)
-                ).into_styled(style)
-                .draw(&mut lcd)
-                .unwrap();
+    fn left(&mut self) {
+        self.x -= 1;
+        if self.x < 0 {
+            if self.y != 0 {
+                self.x = 39;
+                self.up();
+            } else {
+                self.x = 0;
             }
-            timer.delay_ms(500u16);
         }
+    }
 
-        timer.delay_ms(1000u16);
-
-
-        // buffy2.iter_mut().for_each(|px| *px = swap(0b00000_000000_00000));
-        // rprintln!("Start black");
-        // lcd.draw_raw(0, 0, 319, 239, &buffy2).unwrap();
-        // rprintln!("Done.\n");
-
-        rprintln!("Starting Text Fill...");
-
-        let mut text = Text::new(
-            "1234567890123456789012345678901234567890",
-            Point::new(0, 0)
-        ).into_styled(style);
-
-        for _y in 0..15 {
-            text.draw(&mut lcd).unwrap();
-            text = text.translate(Point::new(0, 16));
+    fn right(&mut self) {
+        self.x += 1;
+        if self.x >= 40 {
+            self.x = 0;
+            self.down();
         }
+    }
 
-        rprintln!("Finished Text Fill.");
-
-
-        timer.delay_ms(1000u16);
-
-
+    fn enter(&mut self) {
+        if self.y != 14 {
+            self.x = 0;
+            self.down();
+        }
     }
 
-    Ok(())
+    fn pos(&self) -> Point {
+        Point::new(self.x * 8, self.y * 16)
+    }
 }
 
-const fn swap(inp: u16) -> u16 {
-    (inp & 0x00FF) << 8 |
-    (inp & 0xFF00) >> 8
-}
+// let key_raw = kbd.get_fifo_key_raw().unwrap();
+
+// match key_raw {
+//     KeyRaw::Invalid => {
+//         timer.delay_ms(1000u16);
+//         let state = kbd.get_key_status().unwrap();
+//         rprintln!("Key Status: {:?}", state);
+//     }
+//     key @ _ => {
+//         ctr = ctr.wrapping_add(5);
+//         rprintln!("Key: {:?} - {}", key, ctr);
+//         kbd.set_backlight(ctr).unwrap();
+//         assert_eq!(kbd.get_backlight().unwrap(), ctr);
+//     }
+// }
+
+// Special keys
+// LL: 6
+// LR: 17
+// RL: 7
+// RR: 18
+//
+// D-L: 3
+// D-U: 1
+// D-R: 4
+// D-D: 2
+// D-C: 5