Skip to content

Commit 0353e11

Browse files
authored
Print app size when using any image format, cleanup/use new features (#281)
* Use the new #[default] enum variant attribute * Add support for printing app size using any image format
1 parent 4dd748e commit 0353e11

File tree

7 files changed

+92
-38
lines changed

7 files changed

+92
-38
lines changed

espflash/src/cli/mod.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::{
1717
use clap::{builder::ArgPredicate, Args};
1818
use comfy_table::{modifiers, presets::UTF8_FULL, Attribute, Cell, Color, Table};
1919
use esp_idf_part::{DataType, Partition, PartitionTable};
20+
use indicatif::HumanCount;
2021
use log::{debug, info};
2122
use miette::{IntoDiagnostic, Result, WrapErr};
2223
use serialport::{SerialPortType, UsbPortInfo};
@@ -296,6 +297,8 @@ pub fn save_elf_as_image(
296297
flash_freq,
297298
)?;
298299

300+
display_image_size(image.app_size(), image.part_size());
301+
299302
let mut file = fs::OpenOptions::new()
300303
.write(true)
301304
.truncate(true)
@@ -317,13 +320,13 @@ pub fn save_elf_as_image(
317320
// Take flash_size as input parameter, if None, use default value of 4Mb
318321
let padding_bytes = vec![
319322
0xffu8;
320-
flash_size.unwrap_or(FlashSize::Flash4Mb).size() as usize
323+
flash_size.unwrap_or_default().size() as usize
321324
- file.metadata().into_diagnostic()?.len() as usize
322325
];
323326
file.write_all(&padding_bytes).into_diagnostic()?;
324327
}
325328
} else {
326-
let flash_image = chip.into_target().get_flash_image(
329+
let image = chip.into_target().get_flash_image(
327330
&image,
328331
None,
329332
None,
@@ -333,8 +336,10 @@ pub fn save_elf_as_image(
333336
flash_size,
334337
flash_freq,
335338
)?;
336-
let parts: Vec<_> = flash_image.ota_segments().collect();
337339

340+
display_image_size(image.app_size(), image.part_size());
341+
342+
let parts = image.ota_segments().collect::<Vec<_>>();
338343
match parts.as_slice() {
339344
[single] => fs::write(&image_path, &single.data).into_diagnostic()?,
340345
parts => {
@@ -349,6 +354,20 @@ pub fn save_elf_as_image(
349354
Ok(())
350355
}
351356

357+
pub(crate) fn display_image_size(app_size: u32, part_size: Option<u32>) {
358+
if let Some(part_size) = part_size {
359+
let percent = app_size as f32 / part_size as f32 * 100.0;
360+
println!(
361+
"App/part. size: {}/{} bytes, {:.2}%",
362+
HumanCount(app_size as u64),
363+
HumanCount(part_size as u64),
364+
percent
365+
);
366+
} else {
367+
println!("App size: {} bytes", HumanCount(app_size as u64));
368+
}
369+
}
370+
352371
/// Write an ELF image to a target device's flash
353372
pub fn flash_elf_image(
354373
flasher: &mut Flasher,
@@ -425,7 +444,8 @@ pub fn erase_partitions(
425444
}
426445

427446
// Look for any data partitions with specific data subtype
428-
// There might be multiple partition of the same subtype, e.g. when using multiple FAT partitions
447+
// There might be multiple partition of the same subtype, e.g. when using
448+
// multiple FAT partitions
429449
if let Some(partition_types) = erase_data_parts {
430450
for ty in partition_types {
431451
for part in partition_table.partitions() {

espflash/src/flasher/mod.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const FLASH_SECTORS_PER_BLOCK: usize = FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE;
3838
/// Supported flash frequencies
3939
///
4040
/// Note that not all frequencies are supported by each target device.
41-
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Display, EnumVariantNames)]
41+
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, Display, EnumVariantNames)]
4242
#[repr(u8)]
4343
pub enum FlashFrequency {
4444
/// 12 MHz
@@ -63,6 +63,7 @@ pub enum FlashFrequency {
6363
#[strum(serialize = "30M")]
6464
Flash30M,
6565
/// 40 MHz
66+
#[default]
6667
#[strum(serialize = "40M")]
6768
Flash40M,
6869
/// 48 MHz
@@ -100,14 +101,15 @@ impl FromStr for FlashFrequency {
100101
}
101102

102103
/// Supported flash modes
103-
#[derive(Copy, Clone, Debug, EnumVariantNames)]
104+
#[derive(Copy, Clone, Debug, Default, EnumVariantNames)]
104105
#[strum(serialize_all = "lowercase")]
105106
pub enum FlashMode {
106107
/// Quad I/O (4 pins used for address & data)
107108
Qio,
108109
/// Quad Output (4 pins used for data)
109110
Qout,
110111
/// Dual I/O (2 pins used for address & data)
112+
#[default]
111113
Dio,
112114
/// Dual Output (2 pins used for data)
113115
Dout,
@@ -132,7 +134,7 @@ impl FromStr for FlashMode {
132134
/// Supported flash sizes
133135
///
134136
/// Note that not all sizes are supported by each target device.
135-
#[derive(Clone, Copy, Debug, Eq, PartialEq, Display, EnumVariantNames)]
137+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Display, EnumVariantNames)]
136138
#[repr(u8)]
137139
pub enum FlashSize {
138140
/// 256 KB
@@ -148,6 +150,7 @@ pub enum FlashSize {
148150
#[strum(serialize = "2M")]
149151
Flash2Mb = 0x15,
150152
/// 4 MB
153+
#[default]
151154
#[strum(serialize = "4M")]
152155
Flash4Mb = 0x16,
153156
/// 8 MB
@@ -472,7 +475,7 @@ impl Flasher {
472475
Ok(size) => size,
473476
Err(_) => {
474477
warn!(
475-
"Could not detect flash size (FlashID=0x{:02X}, SizeID=0x{:02X}), defaulting to 4MB\n",
478+
"Could not detect flash size (FlashID=0x{:02X}, SizeID=0x{:02X}), defaulting to 4MB",
476479
flash_id,
477480
size_id
478481
);
@@ -678,7 +681,7 @@ impl Flasher {
678681
let mut target = self.chip.flash_target(self.spi_params, self.use_stub);
679682
target.begin(&mut self.connection).flashing()?;
680683

681-
let flash_image = self.chip.into_target().get_flash_image(
684+
let image = self.chip.into_target().get_flash_image(
682685
&image,
683686
bootloader,
684687
partition_table,
@@ -691,7 +694,10 @@ impl Flasher {
691694
flash_freq,
692695
)?;
693696

694-
for segment in flash_image.flash_segments() {
697+
#[cfg(feature = "cli")]
698+
crate::cli::display_image_size(image.app_size(), image.part_size());
699+
700+
for segment in image.flash_segments() {
695701
target
696702
.write_segment(&mut self.connection, segment)
697703
.flashing()?;

espflash/src/image_format/direct_boot.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ impl<'a> ImageFormat<'a> for DirectBootFormat<'a> {
5656
{
5757
Box::new(once(self.segment.borrow()))
5858
}
59+
60+
fn app_size(&self) -> u32 {
61+
self.segment.data.len() as u32
62+
}
63+
64+
fn part_size(&self) -> Option<u32> {
65+
None
66+
}
5967
}
6068

6169
#[cfg(test)]

espflash/src/image_format/esp8266.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
pub struct Esp8266Format<'a> {
1818
irom_data: Option<RomSegment<'a>>,
1919
flash_segment: RomSegment<'a>,
20+
app_size: u32,
2021
}
2122

2223
impl<'a> Esp8266Format<'a> {
@@ -37,9 +38,9 @@ impl<'a> Esp8266Format<'a> {
3738
);
3839

3940
// Common header
40-
let flash_mode = flash_mode.unwrap_or(FlashMode::Dio) as u8;
41-
let flash_freq = flash_freq.unwrap_or(FlashFrequency::Flash40M);
42-
let flash_size = flash_size.unwrap_or(FlashSize::Flash4Mb);
41+
let flash_mode = flash_mode.unwrap_or_default() as u8;
42+
let flash_freq = flash_freq.unwrap_or_default();
43+
let flash_size = flash_size.unwrap_or_default();
4344
let flash_config =
4445
encode_flash_size(flash_size)? + encode_flash_frequency(Chip::Esp8266, flash_freq)?;
4546
let segment_count = image.ram_segments(Chip::Esp8266).count() as u8;
@@ -87,9 +88,16 @@ impl<'a> Esp8266Format<'a> {
8788
data: Cow::Owned(common_data),
8889
};
8990

91+
let app_size = irom_data
92+
.clone()
93+
.map(|d| d.data.len() as u32)
94+
.unwrap_or_default()
95+
+ flash_segment.data.len() as u32;
96+
9097
Ok(Self {
9198
irom_data,
9299
flash_segment,
100+
app_size,
93101
})
94102
}
95103
}
@@ -118,6 +126,14 @@ impl<'a> ImageFormat<'a> for Esp8266Format<'a> {
118126
.chain(once(self.flash_segment.borrow())),
119127
)
120128
}
129+
130+
fn app_size(&self) -> u32 {
131+
self.app_size
132+
}
133+
134+
fn part_size(&self) -> Option<u32> {
135+
None
136+
}
121137
}
122138

123139
fn merge_rom_segments<'a>(

espflash/src/image_format/idf_bootloader.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use std::{borrow::Cow, io::Write, iter::once};
22

33
use bytemuck::{bytes_of, from_bytes, Pod, Zeroable};
4-
use esp_idf_part::{Partition, PartitionTable, Type};
5-
use indicatif::HumanCount;
4+
use esp_idf_part::{PartitionTable, Type};
65
use sha2::{Digest, Sha256};
76

87
use super::{
@@ -39,6 +38,8 @@ pub struct IdfBootloaderFormat<'a> {
3938
bootloader: Cow<'a, [u8]>,
4039
partition_table: PartitionTable,
4140
flash_segment: RomSegment<'a>,
41+
app_size: u32,
42+
part_size: u32,
4243
}
4344

4445
impl<'a> IdfBootloaderFormat<'a> {
@@ -179,7 +180,14 @@ impl<'a> IdfBootloaderFormat<'a> {
179180
.or_else(|| partition_table.find_by_type(Type::App))
180181
.unwrap();
181182

182-
check_partition_stats(factory_partition, &data)?;
183+
let app_size = data.len() as u32;
184+
let part_size = factory_partition.size();
185+
186+
// The size of the application must not exceed the size of the factory
187+
// partition.
188+
if app_size as f32 / part_size as f32 > 1.0 {
189+
return Err(Error::ElfTooBig);
190+
}
183191

184192
let flash_segment = RomSegment {
185193
addr: factory_partition.offset(),
@@ -191,6 +199,8 @@ impl<'a> IdfBootloaderFormat<'a> {
191199
bootloader,
192200
partition_table,
193201
flash_segment,
202+
app_size,
203+
part_size,
194204
})
195205
}
196206
}
@@ -219,6 +229,14 @@ impl<'a> ImageFormat<'a> for IdfBootloaderFormat<'a> {
219229
{
220230
Box::new(once(self.flash_segment.borrow()))
221231
}
232+
233+
fn app_size(&self) -> u32 {
234+
self.app_size
235+
}
236+
237+
fn part_size(&self) -> Option<u32> {
238+
Some(self.part_size)
239+
}
222240
}
223241

224242
fn encode_flash_size(size: FlashSize) -> Result<u8, FlashDetectError> {
@@ -237,22 +255,6 @@ fn encode_flash_size(size: FlashSize) -> Result<u8, FlashDetectError> {
237255
}
238256
}
239257

240-
fn check_partition_stats(part: &Partition, data: &Vec<u8>) -> Result<(), Error> {
241-
let perc = data.len() as f32 / part.size() as f32 * 100.0;
242-
println!(
243-
"App/part. size: {}/{} bytes, {:.2}%",
244-
HumanCount(data.len() as u64),
245-
HumanCount(part.size() as u64),
246-
perc
247-
);
248-
249-
if perc > 100.0 {
250-
return Err(Error::ElfTooBig);
251-
}
252-
253-
Ok(())
254-
}
255-
256258
/// Actual alignment (in data bytes) required for a segment header: positioned
257259
/// so that after we write the next 8 byte header, file_offs % IROM_ALIGN ==
258260
/// segment.addr % IROM_ALIGN

espflash/src/image_format/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ pub trait ImageFormat<'a>: Send {
5555
fn ota_segments<'b>(&'b self) -> Box<dyn Iterator<Item = RomSegment<'b>> + 'b>
5656
where
5757
'a: 'b;
58+
59+
/// The size of the application binary
60+
fn app_size(&self) -> u32;
61+
62+
/// If applicable, the size of the application partition (if it can be
63+
/// determined)
64+
fn part_size(&self) -> Option<u32>;
5865
}
5966

6067
/// All supported firmware image formats

espflash/src/targets/flash_target/esp8266.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
};
1111

1212
/// Applications running from an ESP8266's flash
13+
#[derive(Default)]
1314
pub struct Esp8266Target;
1415

1516
impl Esp8266Target {
@@ -18,12 +19,6 @@ impl Esp8266Target {
1819
}
1920
}
2021

21-
impl Default for Esp8266Target {
22-
fn default() -> Self {
23-
Self::new()
24-
}
25-
}
26-
2722
impl FlashTarget for Esp8266Target {
2823
fn begin(&mut self, connection: &mut Connection) -> Result<(), Error> {
2924
connection.command(Command::FlashBegin {

0 commit comments

Comments
 (0)