Skip to content

Commit 71d7a63

Browse files
authored
Don't silently fail if defmt data isn't available/correct (#524)
* Error if defmt option is used without a parsed Table * Return meaningful errors if defmt data wasn't found * Transform bails into an error enum * Add changelog entry
1 parent 0420d79 commit 71d7a63

File tree

7 files changed

+78
-44
lines changed

7 files changed

+78
-44
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
[Unreleased]
99

1010
### Added
11+
1112
- Added reset strategies (#487)
1213
- Read esp-println generated defmt messages (#466)
1314
- Add --target-app-partition argument to flash command (#461)
@@ -24,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2425

2526
### Changed
2627

28+
- espflash will now exit with an error if `defmt` is selected but not usable (#524)
29+
2730
### Removed
2831

2932
## [2.1.0] - 2023-10-03

cargo-espflash/src/main.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,10 +350,9 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
350350
args.flash_args.monitor_baud.unwrap_or(default_baud),
351351
args.flash_args.log_format,
352352
)
353-
.into_diagnostic()?;
353+
} else {
354+
Ok(())
354355
}
355-
356-
Ok(())
357356
}
358357

359358
fn build(

espflash/src/bin/espflash.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,9 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
272272
args.flash_args.monitor_baud.unwrap_or(default_baud),
273273
args.flash_args.log_format,
274274
)
275-
.into_diagnostic()?;
275+
} else {
276+
Ok(())
276277
}
277-
278-
Ok(())
279278
}
280279

281280
fn save_image(args: SaveImageArgs) -> Result<()> {

espflash/src/cli/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,6 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> {
325325
args.connect_args.baud.unwrap_or(default_baud),
326326
args.log_format,
327327
)
328-
.into_diagnostic()?;
329-
330-
Ok(())
331328
}
332329

333330
/// Convert the provided firmware image from ELF to binary

espflash/src/cli/monitor/mod.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,22 @@ pub fn monitor(
7070
pid: u16,
7171
baud: u32,
7272
log_format: LogFormat,
73-
) -> serialport::Result<()> {
73+
) -> miette::Result<()> {
7474
println!("Commands:");
7575
println!(" CTRL+R Reset chip");
7676
println!(" CTRL+C Exit");
7777
println!();
7878

7979
// Explicitly set the baud rate when starting the serial monitor, to allow using
8080
// different rates for flashing.
81-
serial.serial_port_mut().set_baud_rate(baud)?;
8281
serial
8382
.serial_port_mut()
84-
.set_timeout(Duration::from_millis(5))?;
83+
.set_baud_rate(baud)
84+
.into_diagnostic()?;
85+
serial
86+
.serial_port_mut()
87+
.set_timeout(Duration::from_millis(5))
88+
.into_diagnostic()?;
8589

8690
// We are in raw mode until `_raw_mode` is dropped (ie. this function returns).
8791
let _raw_mode = RawModeGuard::new();
@@ -90,7 +94,7 @@ pub fn monitor(
9094
let mut stdout = ResolvingPrinter::new(elf, stdout.lock());
9195

9296
let mut parser: Box<dyn InputParser> = match log_format {
93-
LogFormat::Defmt => Box::new(parser::esp_defmt::EspDefmt::new(elf)),
97+
LogFormat::Defmt => Box::new(parser::esp_defmt::EspDefmt::new(elf)?),
9498
LogFormat::Serial => Box::new(parser::serial::Serial),
9599
};
96100

@@ -100,30 +104,33 @@ pub fn monitor(
100104
Ok(count) => Ok(count),
101105
Err(e) if e.kind() == ErrorKind::TimedOut => Ok(0),
102106
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
103-
err => err,
107+
err => err.into_diagnostic(),
104108
}?;
105109

106110
parser.feed(&buff[0..read_count], &mut stdout);
107111

108112
// Don't forget to flush the writer!
109113
stdout.flush().ok();
110114

111-
if poll(Duration::from_secs(0))? {
112-
if let Event::Key(key) = read()? {
115+
if poll(Duration::from_secs(0)).into_diagnostic()? {
116+
if let Event::Key(key) = read().into_diagnostic()? {
113117
if key.modifiers.contains(KeyModifiers::CONTROL) {
114118
match key.code {
115119
KeyCode::Char('c') => break,
116120
KeyCode::Char('r') => {
117-
reset_after_flash(&mut serial, pid)?;
121+
reset_after_flash(&mut serial, pid).into_diagnostic()?;
118122
continue;
119123
}
120124
_ => {}
121125
}
122126
}
123127

124128
if let Some(bytes) = handle_key_event(key) {
125-
serial.serial_port_mut().write_all(&bytes)?;
126-
serial.serial_port_mut().flush()?;
129+
serial
130+
.serial_port_mut()
131+
.write_all(&bytes)
132+
.into_diagnostic()?;
133+
serial.serial_port_mut().flush().into_diagnostic()?;
127134
}
128135
}
129136
}

espflash/src/cli/monitor/parser/esp_defmt.rs

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,31 @@ use crossterm::{
55
QueueableCommand,
66
};
77
use defmt_decoder::{Frame, Table};
8+
use miette::{bail, Context, Diagnostic, Result};
9+
use thiserror::Error;
810

911
use crate::cli::monitor::parser::InputParser;
1012

13+
#[derive(Clone, Copy, Debug, Diagnostic, Error)]
14+
#[error("Could not set up defmt logger")]
15+
pub enum DefmtError {
16+
#[error("No elf data available")]
17+
#[diagnostic(code(espflash::monitor::defmt::no_elf))]
18+
NoElf,
19+
20+
#[error("No defmt data was found in the elf file")]
21+
#[diagnostic(code(espflash::monitor::defmt::no_defmt))]
22+
NoDefmtData,
23+
24+
#[error("Failed to parse defmt data")]
25+
#[diagnostic(code(espflash::monitor::defmt::parse_failed))]
26+
TableParseFailed,
27+
28+
#[error("Unsupported defmt encoding: {0:?}. Only rzcobs is supported.")]
29+
#[diagnostic(code(espflash::monitor::defmt::unsupported_encoding))]
30+
UnsupportedEncoding(defmt_decoder::Encoding),
31+
}
32+
1133
#[derive(Debug, PartialEq)]
1234
enum FrameKind<'a> {
1335
Defmt(&'a [u8]),
@@ -79,31 +101,38 @@ impl FrameDelimiter {
79101

80102
pub struct EspDefmt {
81103
delimiter: FrameDelimiter,
82-
table: Option<Table>,
104+
table: Table,
83105
}
84106

85107
impl EspDefmt {
86-
fn load_table(elf: Option<&[u8]>) -> Option<Table> {
87-
// Load symbols from the ELF file (if provided) and initialize the context.
88-
Table::parse(elf?).ok().flatten().and_then(|table| {
89-
let encoding = table.encoding();
90-
91-
// We only support rzcobs encoding because it is the only way to multiplex
92-
// a defmt stream and an ASCII log stream over the same serial port.
93-
if encoding == defmt_decoder::Encoding::Rzcobs {
94-
Some(table)
95-
} else {
96-
log::warn!("Unsupported defmt encoding: {:?}", encoding);
97-
None
98-
}
99-
})
108+
/// Loads symbols from the ELF file (if provided) and initializes the context.
109+
fn load_table(elf: Option<&[u8]>) -> Result<Table> {
110+
let Some(elf) = elf else {
111+
bail!(DefmtError::NoElf);
112+
};
113+
114+
let table = match Table::parse(elf) {
115+
Ok(Some(table)) => table,
116+
Ok(None) => bail!(DefmtError::NoDefmtData),
117+
Err(e) => return Err(DefmtError::TableParseFailed).with_context(|| e),
118+
};
119+
120+
let encoding = table.encoding();
121+
122+
// We only support rzcobs encoding because it is the only way to multiplex
123+
// a defmt stream and an ASCII log stream over the same serial port.
124+
if encoding == defmt_decoder::Encoding::Rzcobs {
125+
Ok(table)
126+
} else {
127+
bail!(DefmtError::UnsupportedEncoding(encoding))
128+
}
100129
}
101130

102-
pub fn new(elf: Option<&[u8]>) -> Self {
103-
Self {
131+
pub fn new(elf: Option<&[u8]>) -> Result<Self> {
132+
Self::load_table(elf).map(|table| Self {
104133
delimiter: FrameDelimiter::new(),
105-
table: Self::load_table(elf),
106-
}
134+
table,
135+
})
107136
}
108137

109138
fn handle_raw(bytes: &[u8], out: &mut dyn Write) {
@@ -143,12 +172,7 @@ impl EspDefmt {
143172

144173
impl InputParser for EspDefmt {
145174
fn feed(&mut self, bytes: &[u8], out: &mut dyn Write) {
146-
let Some(table) = self.table.as_mut() else {
147-
Self::handle_raw(bytes, out);
148-
return;
149-
};
150-
151-
let mut decoder = table.new_stream_decoder();
175+
let mut decoder = self.table.new_stream_decoder();
152176

153177
self.delimiter.feed(bytes, |frame| match frame {
154178
FrameKind::Defmt(frame) => {

espflash/src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use strum::{FromRepr, VariantNames};
1111
use thiserror::Error;
1212

1313
use crate::{
14+
cli::monitor::parser::esp_defmt::DefmtError,
1415
command::CommandType,
1516
flasher::{FlashFrequency, FlashSize},
1617
image_format::ImageFormatKind,
@@ -159,6 +160,10 @@ pub enum Error {
159160
#[error(transparent)]
160161
#[diagnostic(transparent)]
161162
UnsupportedImageFormat(#[from] UnsupportedImageFormatError),
163+
164+
#[error(transparent)]
165+
#[diagnostic(transparent)]
166+
Defmt(#[from] DefmtError),
162167
}
163168

164169
impl From<io::Error> for Error {

0 commit comments

Comments
 (0)