Skip to content

Commit 421a8dc

Browse files
committed
Add an optional callback trait which can be implemented and provided to most flashing functions
1 parent 911b28d commit 421a8dc

File tree

8 files changed

+95
-112
lines changed

8 files changed

+95
-112
lines changed

cargo-espflash/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use espflash::{
1010
cli::{
1111
self, board_info, config::Config, connect, erase_partitions, flash_elf_image,
1212
monitor::monitor, parse_partition_table, partition_table, print_board_info,
13-
save_elf_as_image, serial_monitor, ConnectArgs, FlashConfigArgs, MonitorArgs,
14-
PartitionTableArgs,
13+
save_elf_as_image, serial_monitor, ConnectArgs, EspflashProgress, FlashConfigArgs,
14+
MonitorArgs, PartitionTableArgs,
1515
},
1616
image_format::ImageFormatKind,
1717
logging::initialize_logger,
@@ -171,7 +171,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
171171
print_board_info(&mut flasher)?;
172172

173173
if args.flash_args.ram {
174-
flasher.load_elf_to_ram(&elf_data)?;
174+
flasher.load_elf_to_ram(&elf_data, Some(&mut EspflashProgress::default()))?;
175175
} else {
176176
let bootloader = args
177177
.flash_args

espflash/src/bin/espflash.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use std::{
88
use clap::{Args, Parser, Subcommand};
99
use espflash::{
1010
cli::{
11-
self, board_info, build_progress_bar_callback, config::Config, connect, erase_partitions,
12-
flash_elf_image, monitor::monitor, parse_partition_table, partition_table,
13-
print_board_info, progress_bar, save_elf_as_image, serial_monitor, ConnectArgs,
14-
FlashConfigArgs, MonitorArgs, PartitionTableArgs,
11+
self, board_info, config::Config, connect, erase_partitions, flash_elf_image,
12+
monitor::monitor, parse_partition_table, partition_table, print_board_info,
13+
save_elf_as_image, serial_monitor, ConnectArgs, EspflashProgress, FlashConfigArgs,
14+
MonitorArgs, PartitionTableArgs,
1515
},
1616
image_format::ImageFormatKind,
1717
logging::initialize_logger,
@@ -126,7 +126,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
126126
let elf_data = fs::read(&args.image).into_diagnostic()?;
127127

128128
if args.flash_args.ram {
129-
flasher.load_elf_to_ram(&elf_data)?;
129+
flasher.load_elf_to_ram(&elf_data, Some(&mut EspflashProgress::default()))?;
130130
} else {
131131
let bootloader = args.flash_args.bootloader.as_deref();
132132
let partition_table = args.flash_args.partition_table.as_deref();
@@ -233,10 +233,7 @@ fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
233233
let mut buffer = Vec::with_capacity(size.try_into().into_diagnostic()?);
234234
f.read_to_end(&mut buffer).into_diagnostic()?;
235235

236-
let progress = progress_bar(format!("segment 0x{:X}", args.addr), None);
237-
let progress_cb = Some(build_progress_bar_callback(progress));
238-
239-
flasher.write_bin_to_flash(args.addr, &buffer, progress_cb)?;
236+
flasher.write_bin_to_flash(args.addr, &buffer, Some(&mut EspflashProgress::default()))?;
240237

241238
Ok(())
242239
}

espflash/src/cli/mod.rs

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
//! [espflash]: https://crates.io/crates/espflash
99
1010
use std::{
11-
borrow::Cow,
1211
collections::HashMap,
1312
fs,
1413
io::Write,
@@ -18,7 +17,7 @@ use std::{
1817
use clap::Args;
1918
use comfy_table::{modifiers, presets::UTF8_FULL, Attribute, Cell, Color, Table};
2019
use esp_idf_part::{DataType, Partition, PartitionTable};
21-
use indicatif::{style::ProgressStyle, HumanCount, ProgressBar, ProgressDrawTarget};
20+
use indicatif::{style::ProgressStyle, HumanCount, ProgressBar};
2221
use log::{debug, info};
2322
use miette::{IntoDiagnostic, Result, WrapErr};
2423
use serialport::{SerialPortType, UsbPortInfo};
@@ -27,7 +26,7 @@ use self::{config::Config, monitor::monitor, serial::get_serial_port_info};
2726
use crate::{
2827
elf::ElfFirmwareImage,
2928
error::{MissingPartition, MissingPartitionTable},
30-
flasher::{FlashFrequency, FlashMode, FlashSize, Flasher},
29+
flasher::{FlashFrequency, FlashMode, FlashSize, Flasher, ProgressCallbacks},
3130
image_format::ImageFormatKind,
3231
interface::Interface,
3332
targets::Chip,
@@ -165,55 +164,6 @@ pub struct MonitorArgs {
165164
connect_args: ConnectArgs,
166165
}
167166

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

406+
/// Progress callback implementations for use in `cargo-espflash` and `espflash`
407+
#[derive(Default)]
408+
pub struct EspflashProgress {
409+
pb: Option<ProgressBar>,
410+
}
411+
412+
impl ProgressCallbacks for EspflashProgress {
413+
fn init(&mut self, addr: u32, len: usize) {
414+
let pb = ProgressBar::new(len as u64)
415+
.with_message(format!("{addr:#X}"))
416+
.with_style(
417+
ProgressStyle::default_bar()
418+
.template("[{elapsed_precise}] [{bar:40}] {pos:>7}/{len:7} {msg}")
419+
.unwrap()
420+
.progress_chars("=> "),
421+
);
422+
423+
self.pb = Some(pb);
424+
}
425+
426+
fn update(&mut self, current: usize) {
427+
if let Some(ref pb) = self.pb {
428+
pb.set_position(current as u64);
429+
}
430+
}
431+
432+
fn finish(&mut self) {
433+
if let Some(ref pb) = self.pb {
434+
pb.finish();
435+
}
436+
}
437+
}
438+
456439
/// Write an ELF image to a target device's flash
457440
pub fn flash_elf_image(
458441
flasher: &mut Flasher,
@@ -485,6 +468,7 @@ pub fn flash_elf_image(
485468
flash_mode,
486469
flash_size,
487470
flash_freq,
471+
Some(&mut EspflashProgress::default()),
488472
)?;
489473
info!("Flashing has completed!");
490474

espflash/src/flasher/mod.rs

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,16 @@ pub struct DeviceInfo {
263263
pub mac_address: String,
264264
}
265265

266+
/// Progress update callbacks
267+
pub trait ProgressCallbacks {
268+
/// Initialize some progress report
269+
fn init(&mut self, addr: u32, total: usize);
270+
/// Update some progress report
271+
fn update(&mut self, current: usize);
272+
/// Finish some prgoress report
273+
fn finish(&mut self);
274+
}
275+
266276
/// Connect to and flash a target device
267277
pub struct Flasher {
268278
/// Connection for flash operations
@@ -352,7 +362,7 @@ impl Flasher {
352362
addr: text_addr,
353363
data: Cow::Borrowed(&text),
354364
},
355-
None,
365+
&mut None,
356366
)
357367
.flashing()?;
358368

@@ -366,7 +376,7 @@ impl Flasher {
366376
addr: data_addr,
367377
data: Cow::Borrowed(&data),
368378
},
369-
None,
379+
&mut None,
370380
)
371381
.flashing()?;
372382

@@ -605,7 +615,11 @@ impl Flasher {
605615
/// Load an elf image to ram and execute it
606616
///
607617
/// Note that this will not touch the flash on the device
608-
pub fn load_elf_to_ram(&mut self, elf_data: &[u8]) -> Result<(), Error> {
618+
pub fn load_elf_to_ram(
619+
&mut self,
620+
elf_data: &[u8],
621+
mut progress: Option<&mut dyn ProgressCallbacks>,
622+
) -> Result<(), Error> {
609623
let image = ElfFirmwareImage::try_from(elf_data)?;
610624
if image.rom_segments(self.chip).next().is_some() {
611625
return Err(Error::ElfNotRamLoadable);
@@ -620,20 +634,8 @@ impl Flasher {
620634
target.begin(&mut self.connection).flashing()?;
621635

622636
for segment in image.ram_segments(self.chip) {
623-
// Only display progress bars when the "cli" feature is enabled.
624-
let progress_cb = if cfg!(feature = "cli") {
625-
use crate::cli::{build_progress_bar_callback, progress_bar};
626-
627-
let progress = progress_bar(format!("segment 0x{:X}", segment.addr), None);
628-
let progress_cb = build_progress_bar_callback(progress);
629-
630-
Some(progress_cb)
631-
} else {
632-
None
633-
};
634-
635637
target
636-
.write_segment(&mut self.connection, segment.into(), progress_cb)
638+
.write_segment(&mut self.connection, segment.into(), &mut progress)
637639
.flashing()?;
638640
}
639641

@@ -650,6 +652,7 @@ impl Flasher {
650652
flash_mode: Option<FlashMode>,
651653
flash_size: Option<FlashSize>,
652654
flash_freq: Option<FlashFrequency>,
655+
mut progress: Option<&mut dyn ProgressCallbacks>,
653656
) -> Result<(), Error> {
654657
let image = ElfFirmwareImage::try_from(elf_data)?;
655658

@@ -676,20 +679,8 @@ impl Flasher {
676679
crate::cli::display_image_size(image.app_size(), image.part_size());
677680

678681
for segment in image.flash_segments() {
679-
// Only display progress bars when the "cli" feature is enabled.
680-
let progress_cb = if cfg!(feature = "cli") {
681-
use crate::cli::{build_progress_bar_callback, progress_bar};
682-
683-
let progress = progress_bar(format!("segment 0x{:X}", segment.addr), None);
684-
let progress_cb = build_progress_bar_callback(progress);
685-
686-
Some(progress_cb)
687-
} else {
688-
None
689-
};
690-
691682
target
692-
.write_segment(&mut self.connection, segment, progress_cb)
683+
.write_segment(&mut self.connection, segment, &mut progress)
693684
.flashing()?;
694685
}
695686

@@ -703,7 +694,7 @@ impl Flasher {
703694
&mut self,
704695
addr: u32,
705696
data: &[u8],
706-
progress_cb: Option<Box<dyn Fn(usize, usize)>>,
697+
mut progress: Option<&mut dyn ProgressCallbacks>,
707698
) -> Result<(), Error> {
708699
let segment = RomSegment {
709700
addr,
@@ -712,7 +703,7 @@ impl Flasher {
712703

713704
let mut target = self.chip.flash_target(self.spi_params, self.use_stub);
714705
target.begin(&mut self.connection).flashing()?;
715-
target.write_segment(&mut self.connection, segment, progress_cb)?;
706+
target.write_segment(&mut self.connection, segment, &mut progress)?;
716707
target.finish(&mut self.connection, true).flashing()?;
717708

718709
Ok(())
@@ -727,6 +718,7 @@ impl Flasher {
727718
flash_mode: Option<FlashMode>,
728719
flash_size: Option<FlashSize>,
729720
flash_freq: Option<FlashFrequency>,
721+
progress: Option<&mut dyn ProgressCallbacks>,
730722
) -> Result<(), Error> {
731723
self.load_elf_to_flash_with_format(
732724
elf_data,
@@ -736,6 +728,7 @@ impl Flasher {
736728
flash_mode,
737729
flash_size,
738730
flash_freq,
731+
progress,
739732
)
740733
}
741734

espflash/src/targets/flash_target/esp32.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
connection::{Connection, USB_SERIAL_JTAG_PID},
1212
elf::RomSegment,
1313
error::Error,
14-
flasher::{SpiAttachParams, FLASH_SECTOR_SIZE},
14+
flasher::{ProgressCallbacks, SpiAttachParams, FLASH_SECTOR_SIZE},
1515
targets::Chip,
1616
};
1717

@@ -98,7 +98,7 @@ impl FlashTarget for Esp32Target {
9898
&mut self,
9999
connection: &mut Connection,
100100
segment: RomSegment,
101-
progress_cb: Option<Box<dyn Fn(usize, usize)>>,
101+
progress: &mut Option<&mut dyn ProgressCallbacks>,
102102
) -> Result<(), Error> {
103103
let addr = segment.addr;
104104

@@ -131,6 +131,8 @@ impl FlashTarget for Esp32Target {
131131
let chunks = compressed.chunks(flash_write_size);
132132
let num_chunks = chunks.len();
133133

134+
progress.as_mut().map(|cb| cb.init(addr, num_chunks));
135+
134136
// decode the chunks to see how much data the device will have to save
135137
let mut decoder = ZlibDecoder::new(Vec::new());
136138
let mut decoded_size = 0;
@@ -154,11 +156,11 @@ impl FlashTarget for Esp32Target {
154156
},
155157
)?;
156158

157-
if let Some(ref cb) = progress_cb {
158-
cb(i + 1, num_chunks);
159-
}
159+
progress.as_mut().map(|cb| cb.update(i + 1));
160160
}
161161

162+
progress.as_mut().map(|cb| cb.finish());
163+
162164
Ok(())
163165
}
164166

0 commit comments

Comments
 (0)