/src/console/serial.rs
use arraydeque::ArrayDeque;
use core::fmt;
use nb::block;
use embedded_hal::serial::*;
use atsam3xa::interrupt;
use cortex_m::interrupt as cm_interrupt;
use crate::console::key::*;
use crate::console::traits::*;
use crate::console::get_global_console;
const BUFFER_SIZE: usize = 16;
pub struct SerialTerminal {
input_buffer: ArrayDeque<[u8; BUFFER_SIZE], arraydeque::Saturating>,
uart: atsam3xa_hal::uart::UART,
}
impl SerialTerminal {
pub fn new(uart: atsam3xa_hal::uart::UART) -> SerialTerminal {
SerialTerminal {
input_buffer: ArrayDeque::new(),
uart,
}
}
pub fn handle_interrupt(&mut self) {
if let Ok(b) = self.uart.read() {
self.input_buffer.push_back(b).ok();
}
}
}
impl ConsoleIO for SerialTerminal {
fn readkey(&mut self) -> Option<Key> {
cm_interrupt::free(|_| {
let b = self.input_buffer.pop_front()?;
match b {
0x1b => {
if self.input_buffer.len() >= 2 {
// escape sequence incoming
let b = self.input_buffer.pop_front().unwrap();
if b != 0x5b {
return None;
}
let b = self.input_buffer.pop_front().unwrap();
match b {
0x41 => Some(Key::Command(Command::Up)),
0x42 => Some(Key::Command(Command::Down)),
0x43 => Some(Key::Command(Command::Right)),
0x44 => Some(Key::Command(Command::Left)),
_ => None,
}
} else {
// not enough characters yet, put the ESC back in the buffer
self.input_buffer.push_front(0x1b).unwrap();
None
}
},
0x0d => Some(Key::Command(Command::Enter)),
0x08 => Some(Key::Command(Command::Backspace)),
0x09 => Some(Key::Command(Command::Tab)),
0x03 => Some(Key::Command(Command::Break)),
b => Some(Key::Char(b as char)),
}
})
}
fn readline(&mut self, buf: &mut [u8]) -> usize {
let mut c = 0;
let mut cursor = 0;
loop {
match self.readkey() {
Some(k) => match k {
Key::Char(x) => {
if c == buf.len() {
// Don't overflow the buffer
continue;
}
// FIXME proper unicode output
self.writeb(x as u8);
if cursor < c {
// reprint everything to the right of the cursor
for i in cursor..c {
self.writeb(buf[i]);
}
for i in (cursor..c).rev() {
buf[i + 1] = buf[i];
self.writeb(0x08);
}
}
buf[cursor] = x as u8;
c += 1;
cursor += 1;
},
Key::Command(x) => match x {
Command::Backspace => {
if c == 0 || cursor == 0 {
// buffer empty
continue;
}
self.writeb(0x08);
for i in cursor..c {
// reprint everything from the cursor rightward
self.writeb(buf[i]);
}
self.writeb(0x20);
for i in cursor..c {
buf[i - 1] = buf[i];
self.writeb(0x08);
}
self.writeb(0x08);
c -= 1;
cursor -= 1;
},
Command::Enter => {
break;
},
Command::Left => {
if cursor == 0 {
continue;
}
cursor -= 1;
self.write("\x1b[1D");
},
Command::Right => {
if cursor == c {
continue;
}
cursor += 1;
self.write("\x1b[1C");
},
_ => continue,
}
},
None => continue,
};
}
c
}
fn discard(&mut self) {
cm_interrupt::free(|_| {
self.input_buffer.clear();
});
}
fn pos(&mut self, x: usize, y: usize) {
use core::fmt::Write;
assert!(x < 40 && y < 25);
write!(self, "\x1b[{};{}H", y, x).ok();
}
fn writeb(&mut self, b: u8) {
block!(self.uart.write(b)).ok();
}
fn write<T: AsRef<[u8]>>(&mut self, a: T) {
let bytes = a.as_ref();
for b in bytes {
self.writeb(*b);
}
}
fn clear(&mut self) {
self.write(&[0x1b, b'[', b'2', b'J', 0x1b, b'[', b'H']);
}
}
impl fmt::Write for SerialTerminal {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
self.write(s);
Ok(())
}
}
#[interrupt]
fn UART() {
get_global_console().handle_interrupt();
}