Skip to content

Commit bf10e1e

Browse files
author
Eric Douglass
committed
a bunch of stuff: fixed a parse bug and added a new esc seq parse, parsing now is buffered on str instead of individual chars; added some small performance profiling, terminal is also str buffered, uart by default has software control flow turned on
1 parent febb9b1 commit bf10e1e

File tree

11 files changed

+327
-235
lines changed

11 files changed

+327
-235
lines changed

Cargo.lock

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ critical-section = "1.1.1"
4040
embedded-graphics = "0.7.1"
4141
embedded-hal = "0.2"
4242
esp-alloc = { version = "0.2.0", features = ["oom-handler"] }
43-
esp-println = { version = "0.4.0", features = ["esp32c3"] }
43+
esp-println = { version = "0.4.0", default-features = false, features = ["esp32c3", "jtag_serial"] }
4444
esp32c3-hal = { features = [
4545
"direct-boot",
4646
], version = "*" }
@@ -51,15 +51,15 @@ nb = "1.1"
5151
nom = { version = "7.1.3", default-features = false, features = ["alloc"] }
5252
riscv = "0.10.1"
5353
unroll = "0.1.5"
54-
55-
[dev-dependencies]
5654
esp-backtrace = { version = "0.6.0", features = [
5755
"esp32c3",
5856
"panic-handler",
5957
"exception-handler",
60-
"print-uart",
58+
"print-jtag-serial",
6159
] }
6260

61+
[dev-dependencies]
62+
6363

6464
[patch.crates-io]
6565
# TODO: automate these updates

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ At this point you are ready to build and upload
3030

3131
2. Flash to the CPU
3232

33-
`espflash /dev/ttyUSB0 target/riscv32imc-unknown-none-elf/debug/vgaterm --monitor --format direct-boot`
33+
`espflash flash /dev/ttyUSB0 target/riscv32imac-unknown-none-elf/debug/vgaterm --monitor --format direct-boot`
3434

3535
Where `/dev/ttyUSB0` should be whatever serial port the esp32 is connected to. It's highly recommended that your user
3636
is added to the `dialout` group which will allow you to interact with `/dev/ttyUSB0` without using sudo.

examples/escape_seq.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use esp32c3_hal::{
1313
};
1414
use esp_println::{print, println};
1515
use riscv::asm::wfi;
16-
use vgaterm::ansi::{OpChar, TerminalEsc};
16+
use vgaterm::ansi;
1717

1818
core::arch::global_asm!(".global _heap_size; _heap_size = 0x8000");
1919

@@ -80,23 +80,34 @@ fn main() -> ! {
8080
init_heap();
8181

8282
vgaterm::configure_timer0(peripherals.TIMG0, &clocks);
83-
let mut rx = vgaterm::uart::configure0(peripherals.UART0);
83+
let mut _rx = vgaterm::uart::configure0(peripherals.UART0);
8484
vgaterm::uart::interrupt_enable0(vgaterm::interrupt::Priority::Priority5);
8585

8686
unsafe {
8787
riscv::interrupt::enable();
8888
}
8989

90-
let mut escape = TerminalEsc::new();
90+
91+
let r = ansi::parse_esc_str("abcd\u{1B}[XYZ\u{1B}[");
92+
println!("{:?}", r);
93+
94+
// match escape.push_str("abcd\u{1B}[5") {
95+
// ParseRes::InSequence(s) => {
96+
// println!("string {}", s.escape_default());
97+
// },
98+
// ParseRes::OpStr(v) => {
99+
// println!("vec {:?}", v);
100+
// }
101+
// }
91102

92103
loop {
93-
while let Some(c) = rx.recv() {
94-
match escape.push(c) {
95-
None => print!("{}", c.escape_default()),
96-
Some(OpChar::Char(h)) => println!("> {h}"),
97-
Some(OpChar::Op(p)) => println!("{c}\nOp: {p:?}"),
98-
}
99-
}
104+
// while let Some(c) = rx.recv() {
105+
// match escape.push_str(c) {
106+
// None => print!("{}", c.escape_default()),
107+
// Some(OpChar::Char(h)) => println!("> {h}"),
108+
// Some(OpChar::Op(p)) => println!("{c}\nOp: {p:?}"),
109+
// }
110+
// }
100111

101112
unsafe {
102113
wfi();

src/ansi.rs

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@
4949
//! [Op(name), [Param(value)]]
5050
//!
5151
52-
use alloc::{borrow::ToOwned, string::String, vec::Vec};
52+
use alloc::{
53+
borrow::ToOwned,
54+
string::{String, ToString},
55+
vec,
56+
vec::Vec,
57+
};
5358
use core::{fmt::Debug, str::FromStr};
5459
use nom::{IResult, Parser};
5560

@@ -406,21 +411,21 @@ fn set_text_mode_atom(input: &str) -> TextOpResult {
406411
})(input)
407412
}
408413

409-
/// ESC [ ? <anything> h
414+
/// ESC [ ? <numbers> h
410415
fn set_private_sequence(input: &str) -> OpResult {
411416
nom::sequence::tuple((
412417
nom::character::streaming::char('?'),
413-
nom::bytes::streaming::take_till(|c| c == 'h'),
418+
nom::character::streaming::digit0,
414419
nom::character::streaming::char('h'),
415420
))(input)
416421
.map(|(rest, (_, b, _))| (rest, Op::DecPrivateSet(b.to_owned())))
417422
}
418423

419-
/// ESC [ ? <anything> l
424+
/// ESC [ ? <numbers> l
420425
fn reset_private_sequence(input: &str) -> OpResult {
421426
nom::sequence::tuple((
422427
nom::character::streaming::char('?'),
423-
nom::bytes::streaming::take_till(|c| c == 'l'),
428+
nom::character::streaming::digit0,
424429
nom::character::streaming::char('l'),
425430
))(input)
426431
.map(|(rest, (_, b, _))| (rest, Op::DecPrivateReset(b.to_owned())))
@@ -477,10 +482,29 @@ pub enum OpChar {
477482
Op(Op),
478483
}
479484

485+
#[derive(Debug)]
480486
pub enum OpStr {
481487
Str(String),
482488
Op(Op),
483-
InSequence,
489+
}
490+
491+
#[derive(Debug)]
492+
pub struct ParseRes<'a> {
493+
pub rest: &'a str,
494+
pub opstr: Vec<OpStr>,
495+
}
496+
497+
impl<'a> ParseRes<'a> {
498+
fn from_ops(ops: Vec<OpStr>) -> ParseRes<'a> {
499+
ParseRes {
500+
rest: "",
501+
opstr: ops,
502+
}
503+
}
504+
505+
fn new(ops: Vec<OpStr>, rest: &'a str) -> ParseRes<'a> {
506+
ParseRes { rest, opstr: ops }
507+
}
484508
}
485509

486510
impl From<char> for OpChar {
@@ -489,58 +513,51 @@ impl From<char> for OpChar {
489513
}
490514
}
491515

492-
pub struct TerminalEsc {
493-
buffer: String,
516+
pub fn parse_esc_str(s: &str) -> ParseRes {
517+
parse_esc_str_tail(s, vec![])
494518
}
495519

496520
///
497-
/// Future buffered version
521+
/// buffered version
498522
/// "hello" -> "hello" (nom returns Error)
499523
/// "ESC[","garbage" -> `InSequence`, "arbage" (nom returns Failure)
500-
/// "ESC[Ablah", "garbage" -> [Foo(Op), Foo("blah")], [Foo("garbage")],
524+
/// "ESC[Ablah", "garbage" -> [Foo(Op(A)), Foo("blah")], [Foo("garbage")],
525+
/// "garbageESC[Ablah" -> ["garbage", Op(A), "blah"]
526+
/// "garbageESC[Xblah" -> ["garbage", "blah"]
501527
///
502-
impl TerminalEsc {
503-
pub fn new() -> TerminalEsc {
504-
TerminalEsc {
505-
buffer: String::new(),
506-
}
528+
pub fn parse_esc_str_tail(s: &str, mut current: Vec<OpStr>) -> ParseRes {
529+
if s.is_empty() {
530+
return ParseRes::from_ops(current);
507531
}
508-
509-
pub fn push(&mut self, c: char) -> Option<OpChar> {
510-
self.buffer.push(c);
511-
512-
let seq = self.buffer.as_str();
513-
match parse(seq) {
514-
Err(nom::Err::Incomplete(_)) => {
515-
// If we are incomplete, then do nothing
516-
// print!("{}", c.escape_default());
517-
None
518-
}
519-
Err(nom::Err::Error(_)) => {
520-
// If we got an error, then we didn't recognize an esc seq at all
521-
// So pop the char back off the buffer
522-
self.buffer.pop().map(OpChar::from)
523-
// h e l l o
524-
}
525-
Err(nom::Err::Failure(_)) => {
526-
// And clear the buffer
527-
// ESC [ 6 * ESC [ 6 * ESC [ 6 * h e l l o literally the word loop and then some returns
528-
529-
// If failure, then we were in a sequence but bombed out, and consume all the chars
530-
self.buffer.clear();
531-
None
532-
}
533-
Ok((_, op)) => {
534-
// If we parsed an escape sequence, then clear the buffer and return the Op
535-
self.buffer.clear();
536-
Some(OpChar::Op(op))
537-
}
532+
match parse(s) {
533+
Err(nom::Err::Incomplete(_)) => {
534+
// If we are incomplete, then do nothing
535+
// print!("{}", c.escape_default());
536+
ParseRes::new(current, s)
538537
}
539-
}
540-
}
538+
Err(nom::Err::Error(_)) => {
539+
// If we got an error, then we didn't recognize an esc seq at all
540+
// So pop the char back off the buffer
541+
let (rest, esc) = s.find(ESC).map_or((s, ""), |i| s.split_at(i));
542+
// abcde,ESC[
543+
current.push(OpStr::Str(rest.to_string()));
544+
parse_esc_str_tail(esc, current)
545+
// h e l l o
546+
}
547+
Err(nom::Err::Failure(e)) => {
548+
// And clear the buffer
549+
// ESC [ 6 * ESC [ 6 * ESC [ 6 * h e l l o literally the word loop and then some returns
550+
551+
// If failure, then we were in a sequence but bombed out, and consume all the chars
552+
// ESC [ XYZ
553+
let skip_index = e.input.ceil_char_boundary(1);
554+
parse_esc_str_tail(&e.input[skip_index..], current)
555+
}
556+
Ok((rest, op)) => {
557+
// If we parsed an escape sequence, then clear the buffer and return the Op
541558

542-
impl Default for TerminalEsc {
543-
fn default() -> Self {
544-
TerminalEsc::new()
559+
current.push(OpStr::Op(op));
560+
parse_esc_str_tail(rest, current)
561+
}
545562
}
546563
}

0 commit comments

Comments
 (0)