Skip to content

Commit ffb4767

Browse files
authored
Feature: add subcommand for merging binaries (#152)
* Feature: add option for mergin bootloader, partition-table and application binary into single one binary * Add padding bytes to whole remaining flash
1 parent ff0f619 commit ffb4767

File tree

3 files changed

+100
-1
lines changed

3 files changed

+100
-1
lines changed

cargo-espflash/src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ pub struct SaveImageOpts {
9191
pub build_opts: BuildOpts,
9292
/// File name to save the generated image to
9393
pub file: PathBuf,
94+
/// Boolean flag to merge binaries into single binary
95+
#[clap(long, short = 'M')]
96+
pub merge: bool,
97+
/// Custom bootloader for merging
98+
#[clap(long, short = 'B')]
99+
pub bootloader: Option<PathBuf>,
100+
/// Custom partition table for merging
101+
#[clap(long, short = 'T')]
102+
pub partition_table: Option<PathBuf>,
94103
}
95104

96105
fn main() -> Result<()> {
@@ -326,6 +335,9 @@ fn save_image(
326335
opts.build_opts.flash_config_opts.flash_mode,
327336
opts.build_opts.flash_config_opts.flash_size,
328337
opts.build_opts.flash_config_opts.flash_freq,
338+
opts.merge,
339+
opts.bootloader,
340+
opts.partition_table,
329341
)?;
330342

331343
Ok(())

espflash/src/cli/mod.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
use std::{
66
fs,
7+
io::Write,
78
path::{Path, PathBuf},
89
};
910

@@ -101,6 +102,9 @@ pub fn save_elf_as_image(
101102
flash_mode: Option<FlashMode>,
102103
flash_size: Option<FlashSize>,
103104
flash_freq: Option<FlashFrequency>,
105+
merge: bool,
106+
bootloader_path: Option<PathBuf>,
107+
partition_table_path: Option<PathBuf>,
104108
) -> Result<()> {
105109
let image = FirmwareImageBuilder::new(elf_data)
106110
.flash_mode(flash_mode)
@@ -112,7 +116,7 @@ pub fn save_elf_as_image(
112116
let parts: Vec<_> = flash_image.ota_segments().collect();
113117

114118
match parts.as_slice() {
115-
[single] => fs::write(path, &single.data).into_diagnostic()?,
119+
[single] => fs::write(&path, &single.data).into_diagnostic()?,
116120
parts => {
117121
for part in parts {
118122
let part_path = format!("{:#x}_{}", part.addr, path.display());
@@ -121,6 +125,77 @@ pub fn save_elf_as_image(
121125
}
122126
}
123127

128+
// merge_bin is TRUE
129+
// merge bootloader, partition table and app binaries
130+
// basic functionality, only merge 3 binaries
131+
if merge {
132+
// If the '-B' option is provided, load the bootloader binary file at the
133+
// specified path.
134+
let bootloader = if let Some(bootloader_path) = bootloader_path {
135+
let path = fs::canonicalize(bootloader_path).into_diagnostic()?;
136+
let data = fs::read(path).into_diagnostic()?;
137+
138+
Some(data)
139+
} else {
140+
None
141+
};
142+
143+
// If the '-T' option is provided, load the partition table from
144+
// the CSV at the specified path.
145+
let partition_table = if let Some(partition_table_path) = partition_table_path {
146+
let path = fs::canonicalize(partition_table_path).into_diagnostic()?;
147+
let data = fs::read_to_string(path)
148+
.into_diagnostic()
149+
.wrap_err("Failed to open partition table")?;
150+
151+
let table =
152+
PartitionTable::try_from_str(data).wrap_err("Failed to parse partition table")?;
153+
154+
Some(table)
155+
} else {
156+
None
157+
};
158+
159+
// To get a chip revision, the connection is needed
160+
// For simplicity, the revision None is used
161+
let image =
162+
chip.get_flash_image(&image, bootloader, partition_table, image_format, None)?;
163+
164+
let merged_bin = format!(
165+
"merged_{path}",
166+
path = &path.to_str().unwrap_or("merged_bins.bin")
167+
);
168+
169+
if Path::new(&merged_bin).exists() {
170+
fs::remove_file(&merged_bin).into_diagnostic()?;
171+
}
172+
173+
let mut file = fs::OpenOptions::new()
174+
.write(true)
175+
.create_new(true)
176+
.open(merged_bin)
177+
.into_diagnostic()?;
178+
179+
for segment in image.flash_segments() {
180+
let padding_bytes = vec![
181+
0xffu8;
182+
segment.addr as usize
183+
- file.metadata().into_diagnostic()?.len() as usize
184+
];
185+
file.write_all(&padding_bytes).into_diagnostic()?;
186+
file.write_all(&segment.data).into_diagnostic()?;
187+
}
188+
189+
// Take flash_size as input parameter, if None, use default value of 4Mb
190+
let padding_bytes = vec![
191+
0xffu8;
192+
flash_size.unwrap_or(FlashSize::Flash4Mb).size() as usize
193+
- file.metadata().into_diagnostic()?.len() as usize
194+
];
195+
file.write_all(&padding_bytes).into_diagnostic()?;
196+
}
197+
198+
println!("The final merge binary was created successfully.");
124199
Ok(())
125200
}
126201

espflash/src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ pub struct SaveImageOpts {
4949
image: PathBuf,
5050
/// File name to save the generated image to
5151
file: PathBuf,
52+
/// Boolean flag, if set, bootloader, partition table and application binaries will be merged into single binary
53+
#[clap(long, short = 'M')]
54+
pub merge: bool,
55+
/// Custom bootloader for merging
56+
#[clap(long, short = 'B')]
57+
pub bootloader: Option<PathBuf>,
58+
/// Custom partition table for merging
59+
#[clap(long, short = 'T')]
60+
pub partition_table: Option<PathBuf>,
5261
}
5362

5463
fn main() -> Result<()> {
@@ -150,6 +159,9 @@ fn save_image(opts: SaveImageOpts) -> Result<()> {
150159
opts.flash_config_opts.flash_mode,
151160
opts.flash_config_opts.flash_size,
152161
opts.flash_config_opts.flash_freq,
162+
opts.merge,
163+
opts.bootloader,
164+
opts.partition_table,
153165
)?;
154166

155167
Ok(())

0 commit comments

Comments
 (0)