Skip to content

Commit 0fc516b

Browse files
committed
Simplify using esp-println's framing
1 parent 865f4a4 commit 0fc516b

File tree

1 file changed

+34
-112
lines changed
  • espflash/src/cli/monitor

1 file changed

+34
-112
lines changed

espflash/src/cli/monitor/mod.rs

Lines changed: 34 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crossterm::{
2121
terminal::{disable_raw_mode, enable_raw_mode},
2222
QueueableCommand,
2323
};
24-
use defmt_decoder::{DecodeError, Frame, Table};
24+
use defmt_decoder::{Frame, StreamDecoder, Table};
2525
use lazy_static::lazy_static;
2626
use log::error;
2727
use miette::{IntoDiagnostic, Result};
@@ -78,127 +78,47 @@ enum FrameKind<'a> {
7878
Raw(&'a [u8]),
7979
}
8080

81-
struct FrameDelimiter {
81+
struct FrameDelimiter<'a> {
8282
buffer: Vec<u8>,
83-
table: Option<Table>,
84-
started: bool,
83+
decoder: Option<Box<dyn StreamDecoder + 'a>>,
84+
in_frame: bool,
8585
}
8686

87-
impl FrameDelimiter {
87+
const FRAME_START: &[u8] = &[0xFF, 0x00];
88+
const FRAME_END: &[u8] = &[0xFC, 0x00];
89+
90+
fn search(haystack: &[u8], look_for_end: bool) -> Option<(&[u8], usize)> {
91+
let needle = if look_for_end { FRAME_END } else { FRAME_START };
92+
haystack
93+
.windows(needle.len())
94+
.position(|window| window == FRAME_START || window == FRAME_END)
95+
.map(|pos| (&haystack[pos..][..2], pos))
96+
}
97+
98+
impl FrameDelimiter<'_> {
8899
pub fn feed(&mut self, buffer: &[u8], mut process: impl FnMut(FrameKind<'_>)) {
89-
let Some(table) = self.table.as_mut() else {
100+
let Some(table) = self.decoder.as_mut() else {
90101
process(FrameKind::Raw(buffer));
91102
return;
92103
};
93104

94-
let mut buffer = buffer;
95-
let mut retry = false;
96-
while !buffer.is_empty() || retry {
97-
retry = false;
98-
// try to break buffer into 0-bounded frames
99-
let end_of_frame = buffer.iter().position(|&x| x == 0);
100-
let Some(pos) = end_of_frame else {
101-
// we either have a frame open already, or we are in serial output mode
102-
// either case, we consume everything so we can break out of the loop
103-
104-
self.buffer.extend_from_slice(buffer);
105-
return;
106-
};
107-
108-
let consumed = pos + 1; // also take the trailing 0 byte
109-
let (frame_bytes, rest) = buffer.split_at(consumed);
110-
buffer = rest;
111-
112-
// Print bootloader output as is
113-
if !self.started {
114-
self.started = true;
115-
self.buffer.extend_from_slice(frame_bytes);
116-
process(FrameKind::Raw(&self.buffer));
117-
self.buffer.clear();
118-
continue;
119-
}
105+
self.buffer.extend_from_slice(buffer);
120106

121-
let frame_bytes = if !self.buffer.is_empty() {
122-
self.buffer.extend_from_slice(frame_bytes);
123-
self.buffer.as_slice()
107+
while let Some((delimiter, pos)) = search(&self.buffer, self.in_frame) {
108+
let frame = &self.buffer[..pos];
109+
if delimiter == FRAME_START {
110+
process(FrameKind::Raw(frame));
124111
} else {
125-
frame_bytes
126-
};
127-
128-
// we have a complete frame, try to decode it
129-
let mut decoder = table.new_stream_decoder();
130-
decoder.received(frame_bytes);
131-
132-
match decoder.decode() {
133-
Ok(frame) => process(FrameKind::Defmt(frame)),
134-
135-
Err(DecodeError::UnexpectedEof) => unreachable!(),
136-
Err(DecodeError::Malformed) => try_parse_mixed(&mut process, table, frame_bytes),
137-
}
138-
139-
// We ended on a 0 byte, and we have processed everything one way or another.
140-
self.buffer.clear();
141-
}
142-
}
143-
}
144-
145-
fn try_parse_mixed(process: &mut impl FnMut(FrameKind<'_>), table: &Table, frame_bytes: &[u8]) {
146-
// We have a frame that mixes regular serial output and a defmt frame in the end.
147-
// We walk backwards and try to decode the frame that starts at our moving index.
148-
// If deconding is successful, we move backwards some more.
149-
// We stop when we don't find more starting points.
150-
151-
// This is a weird and probably not very fast heuristic, that assumes ASCII
152-
// strings will rarely contain valid defmt frames and that a defmt frame will rarely be valid
153-
// ASCII.
154-
155-
let mut frame_start = frame_bytes.len();
156-
let mut candidate_frame_start = frame_start - 2;
157-
158-
let is_valid_frame = |frame_bytes| {
159-
let mut decoder = table.new_stream_decoder();
160-
decoder.received(frame_bytes);
161-
match decoder.decode() {
162-
Ok(frame) => frame.display_message().to_string().len() > frame_bytes.len(),
163-
Err(_) => false,
164-
}
165-
};
166-
167-
let assume_text = |frame_bytes: &[u8]| {
168-
frame_bytes
169-
.iter()
170-
.any(|b| *b > 0x20 || [b'\n', b'\r', b'\t'].contains(b))
171-
};
172-
173-
let mut first_valid = true;
174-
175-
// We're checking as far back as there can be a valid Rzcobs run, which is
176-
// 134 data bytes and a 0xFF.
177-
while candidate_frame_start >= frame_start.saturating_sub(135) {
178-
if is_valid_frame(&frame_bytes[candidate_frame_start..]) {
179-
// Assume a frame can't be valid ASCII.
180-
if first_valid || !assume_text(&frame_bytes[candidate_frame_start..frame_start]) {
181-
frame_start = candidate_frame_start;
182-
first_valid = false;
112+
table.received(frame);
113+
if let Ok(frame) = table.decode() {
114+
process(FrameKind::Defmt(frame));
115+
} else {
116+
log::warn!("Failed to decode defmt frame");
117+
log::debug!("Frame contents: {:02X?}", frame);
118+
}
183119
}
120+
self.buffer.drain(..pos + delimiter.len());
184121
}
185-
186-
if candidate_frame_start == 0 {
187-
break;
188-
}
189-
190-
candidate_frame_start -= 1;
191-
}
192-
193-
let (raw, frame) = frame_bytes.split_at(frame_start);
194-
if !raw.is_empty() {
195-
process(FrameKind::Raw(raw));
196-
}
197-
198-
let mut decoder = table.new_stream_decoder();
199-
decoder.received(frame);
200-
if let Ok(frame) = decoder.decode() {
201-
process(FrameKind::Defmt(frame));
202122
}
203123
}
204124

@@ -258,8 +178,10 @@ pub fn monitor(
258178

259179
let mut delimiter = FrameDelimiter {
260180
buffer: Vec::new(),
261-
table: defmt_encoding.map(|(table, _)| table),
262-
started: false,
181+
decoder: defmt_encoding
182+
.as_ref()
183+
.map(|(table, _)| table.new_stream_decoder()),
184+
in_frame: false,
263185
};
264186

265187
loop {

0 commit comments

Comments
 (0)