Skip to content

Commit 88639c4

Browse files
committed
implement basic serial monitor
1 parent 351a4d9 commit 88639c4

File tree

3 files changed

+121
-1
lines changed

3 files changed

+121
-1
lines changed

cargo-espflash/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ guess_host_triple = "0.1"
3232
serde = { version = "1.0", features = ["derive"] }
3333
serial = "0.4"
3434
toml = "0.5"
35+
termion = "1"
3536
thiserror = "1"

cargo-espflash/src/line_endings.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Adapted from https://github.com/derekdreery/normalize-line-endings
2+
3+
struct Normalized<I> {
4+
iter: I,
5+
prev_was_cr: bool,
6+
peeked: Option<u8>,
7+
}
8+
9+
pub fn normalized(iter: impl Iterator<Item = u8>) -> impl Iterator<Item = u8> {
10+
Normalized {
11+
iter,
12+
prev_was_cr: false,
13+
peeked: None,
14+
}
15+
}
16+
17+
impl<I> Iterator for Normalized<I>
18+
where
19+
I: Iterator<Item = u8>,
20+
{
21+
type Item = u8;
22+
fn next(&mut self) -> Option<u8> {
23+
if let Some(peeked) = self.peeked.take() {
24+
return Some(peeked);
25+
}
26+
match self.iter.next() {
27+
Some(b'\n') if !self.prev_was_cr => {
28+
self.peeked = Some(b'\n');
29+
self.prev_was_cr = false;
30+
Some(b'\r')
31+
}
32+
Some(b'\r') => {
33+
self.prev_was_cr = true;
34+
Some(b'\r')
35+
}
36+
any => {
37+
self.prev_was_cr = false;
38+
any
39+
}
40+
}
41+
}
42+
}
43+
44+
// tests
45+
#[cfg(test)]
46+
mod tests {
47+
use std::iter::FromIterator;
48+
49+
#[test]
50+
fn normalized() {
51+
let input = b"This is a string \n with \n some \n\r\n random newlines\r\n\n";
52+
assert_eq!(
53+
&Vec::from_iter(super::normalized(input.iter().copied())),
54+
b"This is a string \r\n with \r\n some \r\n\r\n random newlines\r\n\r\n"
55+
);
56+
}
57+
}

cargo-espflash/src/main.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clap::{App, Arg, SubCommand};
33
use error::Error;
44
use espflash::{Config, Flasher, PartitionTable};
55
use miette::{IntoDiagnostic, Result, WrapErr};
6-
use serial::{BaudRate, SerialPort};
6+
use serial::{BaudRate, SerialPort, SystemPort};
77

88
use std::{
99
fs,
@@ -14,8 +14,14 @@ use std::{
1414

1515
mod cargo_config;
1616
mod error;
17+
mod line_endings;
1718

19+
use crate::line_endings::normalized;
1820
use cargo_config::has_build_std;
21+
use std::io::{stdout, ErrorKind, Read, Write};
22+
use std::thread::sleep;
23+
use std::time::Duration;
24+
use termion::{async_stdin, raw::IntoRawMode};
1925

2026
fn main() -> Result<()> {
2127
let mut app = App::new(env!("CARGO_PKG_NAME"))
@@ -80,6 +86,11 @@ fn main() -> Result<()> {
8086
.takes_value(true)
8187
.value_name("SERIAL")
8288
.help("Serial port connected to target device"),
89+
)
90+
.arg(
91+
Arg::with_name("monitor")
92+
.long("monitor")
93+
.help("Open a serial monitor after flashing"),
8394
),
8495
);
8596

@@ -178,6 +189,10 @@ fn main() -> Result<()> {
178189
flasher.load_elf_to_flash(&elf_data, bootloader, partition_table)?;
179190
}
180191

192+
if matches.is_present("monitor") {
193+
monitor(flasher.into_serial())?;
194+
}
195+
181196
// We're all done!
182197
Ok(())
183198
}
@@ -280,3 +295,50 @@ fn exit_with_process_status(status: ExitStatus) -> ! {
280295

281296
exit(code)
282297
}
298+
299+
const KEYCODE_CTRL_C: u8 = 3;
300+
const KEYCODE_CTRL_R: u8 = 18;
301+
302+
fn monitor(mut serial: SystemPort) -> anyhow::Result<()> {
303+
println!("Commands:");
304+
println!(" CTRL+R Reset chip");
305+
println!(" CTRL+C Exit");
306+
println!();
307+
308+
let mut buff = [0; 128];
309+
serial.set_timeout(Duration::from_millis(5))?;
310+
311+
let mut stdin = async_stdin().bytes();
312+
let stdout = stdout().into_raw_mode()?;
313+
let mut stdout = stdout.lock();
314+
loop {
315+
let read = match serial.read(&mut buff) {
316+
Ok(count) => Ok(count),
317+
Err(e) if e.kind() == ErrorKind::TimedOut => Ok(0),
318+
err => err,
319+
}?;
320+
if read > 0 {
321+
let data: Vec<u8> = normalized(buff[0..read].iter().copied()).collect();
322+
stdout.write_all(&data).ok();
323+
stdout.flush()?;
324+
}
325+
if let Some(Ok(byte)) = stdin.next() {
326+
match byte {
327+
KEYCODE_CTRL_C => break,
328+
KEYCODE_CTRL_R => {
329+
serial.set_dtr(false)?;
330+
serial.set_rts(true)?;
331+
332+
sleep(Duration::from_millis(100));
333+
334+
serial.set_rts(false)?;
335+
}
336+
_ => {
337+
serial.write_all(&[byte])?;
338+
serial.flush()?;
339+
}
340+
}
341+
}
342+
}
343+
Ok(())
344+
}

0 commit comments

Comments
 (0)