Skip to content

Commit fb0877e

Browse files
authored
Only display progress bars when cli feature is enabled, allow passing progress callback (#283)
* Remove progress bars from flash target modules, make `indicatif` optional * Make flash targets take an optional callback function to update progress * Add back in our progress bars, but only when the `cli` feature is enabled
1 parent 0353e11 commit fb0877e

File tree

8 files changed

+154
-73
lines changed

8 files changed

+154
-73
lines changed

espflash/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ directories-next = { version = "2.0.0", optional = true }
4747
esp-idf-part = "0.1.1"
4848
env_logger = { version = "0.9.1", optional = true }
4949
flate2 = "1.0.24"
50-
indicatif = "0.17.1"
50+
indicatif = { version = "0.17.1", optional = true }
5151
lazy_static = { version = "1.4.0", optional = true }
5252
log = "0.4.17"
5353
miette = { version = "5.3.0", features = ["fancy"] }
@@ -69,7 +69,7 @@ xmas-elf = "0.8.0"
6969
default = ["cli"]
7070
cli = [
7171
"dep:addr2line", "dep:clap", "dep:comfy-table", "dep:crossterm", "dep:dialoguer",
72-
"dep:directories-next", "dep:env_logger", "dep:lazy_static", "dep:parse_int",
73-
"dep:regex", "dep:serde-hex", "dep:update-informer"
72+
"dep:directories-next", "dep:env_logger", "dep:indicatif", "dep:lazy_static",
73+
"dep:parse_int", "dep:regex", "dep:serde-hex", "dep:update-informer"
7474
]
7575
raspberry = ["dep:rppal"]

espflash/src/bin/espflash.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ use std::{
88
use clap::{Args, Parser, Subcommand};
99
use espflash::{
1010
cli::{
11-
self, board_info, clap_enum_variants, config::Config, connect, erase_partitions,
12-
flash_elf_image, monitor::monitor, parse_partition_table, partition_table,
13-
save_elf_as_image, serial_monitor, ConnectArgs, FlashConfigArgs, PartitionTableArgs,
11+
self, board_info, build_progress_bar_callback, clap_enum_variants, config::Config, connect,
12+
erase_partitions, flash_elf_image, monitor::monitor, parse_partition_table,
13+
partition_table, progress_bar, save_elf_as_image, serial_monitor, ConnectArgs,
14+
FlashConfigArgs, PartitionTableArgs,
1415
},
1516
image_format::ImageFormatKind,
1617
logging::initialize_logger,
@@ -206,7 +207,10 @@ fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
206207
let mut buffer = Vec::with_capacity(size.try_into().into_diagnostic()?);
207208
f.read_to_end(&mut buffer).into_diagnostic()?;
208209

209-
flasher.write_bin_to_flash(args.addr, &buffer)?;
210+
let progress = progress_bar(format!("segment 0x{:X}", args.addr), None);
211+
let progress_cb = Some(build_progress_bar_callback(progress));
212+
213+
flasher.write_bin_to_flash(args.addr, &buffer, progress_cb)?;
210214

211215
Ok(())
212216
}

espflash/src/cli/mod.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//! [espflash]: https://crates.io/crates/espflash
99
1010
use std::{
11+
borrow::Cow,
1112
collections::HashMap,
1213
fs,
1314
io::Write,
@@ -17,7 +18,7 @@ use std::{
1718
use clap::{builder::ArgPredicate, Args};
1819
use comfy_table::{modifiers, presets::UTF8_FULL, Attribute, Cell, Color, Table};
1920
use esp_idf_part::{DataType, Partition, PartitionTable};
20-
use indicatif::HumanCount;
21+
use indicatif::{style::ProgressStyle, HumanCount, ProgressBar, ProgressDrawTarget};
2122
use log::{debug, info};
2223
use miette::{IntoDiagnostic, Result, WrapErr};
2324
use serialport::{SerialPortType, UsbPortInfo};
@@ -169,6 +170,57 @@ pub struct SaveImageArgs {
169170
pub skip_padding: bool,
170171
}
171172

173+
/// Create a new [ProgressBar] with some message and styling applied
174+
pub fn progress_bar<S>(msg: S, len: Option<u64>) -> ProgressBar
175+
where
176+
S: Into<Cow<'static, str>>,
177+
{
178+
// If no length was provided, or the provided length is 0, we will initially
179+
// hide the progress bar. This is done to avoid drawing a full-width progress
180+
// bar before we've determined the length.
181+
let draw_target = match len {
182+
Some(len) if len > 0 => ProgressDrawTarget::stderr(),
183+
_ => ProgressDrawTarget::hidden(),
184+
};
185+
186+
let progress = ProgressBar::with_draw_target(len, draw_target)
187+
.with_message(msg)
188+
.with_style(
189+
ProgressStyle::default_bar()
190+
.template("[{elapsed_precise}] [{bar:40}] {pos:>7}/{len:7} {msg}")
191+
.unwrap()
192+
.progress_chars("=> "),
193+
);
194+
195+
progress
196+
}
197+
198+
/// Create a callback function for the provided [ProgressBar]
199+
pub fn build_progress_bar_callback(pb: ProgressBar) -> Box<dyn Fn(usize, usize)> {
200+
// This is a bit of an odd callback function, as it handles the entire lifecycle
201+
// of the progress bar.
202+
Box::new(move |current: usize, total: usize| {
203+
// If the length has not yet been set, set it and then change the draw target to
204+
// make the progress bar visible.
205+
match pb.length() {
206+
Some(0) | None => {
207+
pb.set_length(total as u64);
208+
pb.set_draw_target(ProgressDrawTarget::stderr());
209+
}
210+
_ => {}
211+
}
212+
213+
// Set the new position of the progress bar.
214+
pb.set_position(current as u64);
215+
216+
// If we have reached the end, make sure to finish the progress bar to ensure
217+
// proper output on the terminal.
218+
if current == total {
219+
pb.finish();
220+
}
221+
})
222+
}
223+
172224
/// Select a serial port and establish a connection with a target device
173225
pub fn connect(args: &ConnectArgs, config: &Config) -> Result<Flasher> {
174226
let port_info = get_serial_port_info(args, config)?;

espflash/src/flasher/mod.rs

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ impl Flasher {
394394
addr: text_addr,
395395
data: Cow::Borrowed(&text),
396396
},
397+
None,
397398
)
398399
.flashing()?;
399400

@@ -407,6 +408,7 @@ impl Flasher {
407408
addr: data_addr,
408409
data: Cow::Borrowed(&data),
409410
},
411+
None,
410412
)
411413
.flashing()?;
412414

@@ -637,6 +639,9 @@ impl Flasher {
637639
/// Note that this will not touch the flash on the device
638640
pub fn load_elf_to_ram(&mut self, elf_data: &[u8]) -> Result<(), Error> {
639641
let image = ElfFirmwareImage::try_from(elf_data)?;
642+
if image.rom_segments(self.chip).next().is_some() {
643+
return Err(Error::ElfNotRamLoadable);
644+
}
640645

641646
let mut target = self.chip.ram_target(
642647
Some(image.entry()),
@@ -646,19 +651,21 @@ impl Flasher {
646651
);
647652
target.begin(&mut self.connection).flashing()?;
648653

649-
if image.rom_segments(self.chip).next().is_some() {
650-
return Err(Error::ElfNotRamLoadable);
651-
}
652-
653654
for segment in image.ram_segments(self.chip) {
655+
// Only display progress bars when the "cli" feature is enabled.
656+
let progress_cb = if cfg!(feature = "cli") {
657+
use crate::cli::{build_progress_bar_callback, progress_bar};
658+
659+
let progress = progress_bar(format!("segment 0x{:X}", segment.addr), None);
660+
let progress_cb = build_progress_bar_callback(progress);
661+
662+
Some(progress_cb)
663+
} else {
664+
None
665+
};
666+
654667
target
655-
.write_segment(
656-
&mut self.connection,
657-
RomSegment {
658-
addr: segment.addr,
659-
data: Cow::Borrowed(segment.data()),
660-
},
661-
)
668+
.write_segment(&mut self.connection, segment.into(), progress_cb)
662669
.flashing()?;
663670
}
664671

@@ -694,12 +701,25 @@ impl Flasher {
694701
flash_freq,
695702
)?;
696703

704+
// When the "cli" feature is enabled, display the image size information.
697705
#[cfg(feature = "cli")]
698706
crate::cli::display_image_size(image.app_size(), image.part_size());
699707

700708
for segment in image.flash_segments() {
709+
// Only display progress bars when the "cli" feature is enabled.
710+
let progress_cb = if cfg!(feature = "cli") {
711+
use crate::cli::{build_progress_bar_callback, progress_bar};
712+
713+
let progress = progress_bar(format!("segment 0x{:X}", segment.addr), None);
714+
let progress_cb = build_progress_bar_callback(progress);
715+
716+
Some(progress_cb)
717+
} else {
718+
None
719+
};
720+
701721
target
702-
.write_segment(&mut self.connection, segment)
722+
.write_segment(&mut self.connection, segment, progress_cb)
703723
.flashing()?;
704724
}
705725

@@ -709,15 +729,22 @@ impl Flasher {
709729
}
710730

711731
/// Load an bin image to flash at a specific address
712-
pub fn write_bin_to_flash(&mut self, addr: u32, data: &[u8]) -> Result<(), Error> {
713-
let mut target = self.chip.flash_target(self.spi_params, self.use_stub);
714-
target.begin(&mut self.connection).flashing()?;
732+
pub fn write_bin_to_flash(
733+
&mut self,
734+
addr: u32,
735+
data: &[u8],
736+
progress_cb: Option<Box<dyn Fn(usize, usize)>>,
737+
) -> Result<(), Error> {
715738
let segment = RomSegment {
716739
addr,
717740
data: Cow::from(data),
718741
};
719-
target.write_segment(&mut self.connection, segment)?;
742+
743+
let mut target = self.chip.flash_target(self.spi_params, self.use_stub);
744+
target.begin(&mut self.connection).flashing()?;
745+
target.write_segment(&mut self.connection, segment, progress_cb)?;
720746
target.finish(&mut self.connection, true).flashing()?;
747+
721748
Ok(())
722749
}
723750

espflash/src/targets/flash_target/esp32.rs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use flate2::{
44
write::{ZlibDecoder, ZlibEncoder},
55
Compression,
66
};
7-
use indicatif::{ProgressBar, ProgressStyle};
87

98
use super::FlashTarget;
109
use crate::{
@@ -36,49 +35,52 @@ impl Esp32Target {
3635
impl FlashTarget for Esp32Target {
3736
fn begin(&mut self, connection: &mut Connection) -> Result<(), Error> {
3837
connection.with_timeout(CommandType::SpiAttach.timeout(), |connection| {
39-
connection.command(if self.use_stub {
38+
let command = if self.use_stub {
4039
Command::SpiAttachStub {
4140
spi_params: self.spi_attach_params,
4241
}
4342
} else {
4443
Command::SpiAttach {
4544
spi_params: self.spi_attach_params,
4645
}
47-
})
46+
};
47+
48+
connection.command(command)
4849
})?;
4950

50-
// TODO remove this when we use the stub, the stub should be taking care of
51-
// this. TODO do we also need to disable rtc super wdt?
51+
// TODO: Remove this when we use the stub, the stub should be taking care of
52+
// this.
53+
// TODO: Do we also need to disable RTC super WDT?
5254
if connection.get_usb_pid()? == USB_SERIAL_JTAG_PID {
5355
match self.chip {
5456
Chip::Esp32c3 => {
5557
connection.command(Command::WriteReg {
56-
address: 0x600080a8,
57-
value: 0x50D83AA1u32,
58+
address: 0x6000_80a8,
59+
value: 0x50D8_3AA1,
5860
mask: None,
5961
})?; // WP disable
6062
connection.command(Command::WriteReg {
61-
address: 0x60008090,
63+
address: 0x6000_8090,
6264
value: 0x0,
6365
mask: None,
64-
})?; // turn off RTC WDG
66+
})?; // turn off RTC WDT
6567
connection.command(Command::WriteReg {
66-
address: 0x600080a8,
68+
address: 0x6000_80a8,
6769
value: 0x0,
6870
mask: None,
6971
})?; // WP enable
7072
}
7173
Chip::Esp32s3 => {
7274
connection.command(Command::WriteReg {
7375
address: 0x6000_80B0,
74-
value: 0x50D83AA1u32,
76+
value: 0x50D8_3AA1,
7577
mask: None,
7678
})?; // WP disable
7779
connection.command(Command::WriteReg {
7880
address: 0x6000_8098,
7981
value: 0x0,
8082
mask: None,
81-
})?; // turn off RTC WDG
83+
})?; // turn off RTC WDT
8284
connection.command(Command::WriteReg {
8385
address: 0x6000_80B0,
8486
value: 0x0,
@@ -96,6 +98,7 @@ impl FlashTarget for Esp32Target {
9698
&mut self,
9799
connection: &mut Connection,
98100
segment: RomSegment,
101+
progress_cb: Option<Box<dyn Fn(usize, usize)>>,
99102
) -> Result<(), Error> {
100103
let addr = segment.addr;
101104

@@ -126,16 +129,7 @@ impl FlashTarget for Esp32Target {
126129
)?;
127130

128131
let chunks = compressed.chunks(flash_write_size);
129-
130-
let (_, chunk_size) = chunks.size_hint();
131-
let chunk_size = chunk_size.unwrap_or(0) as u64;
132-
let pb_chunk = ProgressBar::new(chunk_size);
133-
pb_chunk.set_style(
134-
ProgressStyle::default_bar()
135-
.template("[{elapsed_precise}] [{bar:40}] {pos:>7}/{len:7} {msg}")
136-
.unwrap()
137-
.progress_chars("=> "),
138-
);
132+
let num_chunks = chunks.len();
139133

140134
// decode the chunks to see how much data the device will have to save
141135
let mut decoder = ZlibDecoder::new(Vec::new());
@@ -147,7 +141,6 @@ impl FlashTarget for Esp32Target {
147141
let size = decoder.get_ref().len() - decoded_size;
148142
decoded_size = decoder.get_ref().len();
149143

150-
pb_chunk.set_message(format!("segment 0x{:X} writing chunks", addr));
151144
connection.with_timeout(
152145
CommandType::FlashDeflateData.timeout_for_size(size as u32),
153146
|connection| {
@@ -160,10 +153,11 @@ impl FlashTarget for Esp32Target {
160153
Ok(())
161154
},
162155
)?;
163-
pb_chunk.inc(1);
164-
}
165156

166-
pb_chunk.finish_with_message(format!("segment 0x{:X}", addr));
157+
if let Some(ref cb) = progress_cb {
158+
cb(i + 1, num_chunks);
159+
}
160+
}
167161

168162
Ok(())
169163
}
@@ -172,10 +166,11 @@ impl FlashTarget for Esp32Target {
172166
connection.with_timeout(CommandType::FlashDeflateEnd.timeout(), |connection| {
173167
connection.command(Command::FlashDeflateEnd { reboot: false })
174168
})?;
169+
175170
if reboot {
176-
connection.reset()
177-
} else {
178-
Ok(())
171+
connection.reset()?;
179172
}
173+
174+
Ok(())
180175
}
181176
}

0 commit comments

Comments
 (0)