Skip to content

Commit 8137c43

Browse files
authored
Allow flashing binary to a named partition (#828)
* Allow flashing binary to a named partition * Test
1 parent 007881f commit 8137c43

File tree

5 files changed

+102
-18
lines changed

5 files changed

+102
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222
- Added chip detection based on security info, where supported (#814)
2323
- `espflash` can detect the chip from ESP-HAL metadata to prevent flashing firmware built for a different device. Reqires `esp-hal` 1.0.0-beta.0 (presumably, yet to be released) (#816)
2424
- `espflash` no longer allows flashing a too-big partition table (#830)
25+
- Allow specifying a partition label for `write-bin`, add `--partition-table`. (#828)
2526

2627
### Changed
2728

cargo-espflash/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ enum Commands {
117117
/// Otherwise, each segment will be saved as individual binaries, prefixed
118118
/// with their intended addresses in flash.
119119
SaveImage(SaveImageArgs),
120-
/// Write a binary file to a specific address in a target device's flash
120+
/// Write a binary file to a specific address or partition in a target
121+
/// device's flash
121122
WriteBin(WriteBinArgs),
122123
}
123124

espflash/src/bin/espflash.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ enum Commands {
8888
/// Otherwise, each segment will be saved as individual binaries, prefixed
8989
/// with their intended addresses in flash.
9090
SaveImage(SaveImageArgs),
91-
/// Write a binary file to a specific address in a target device's flash
91+
/// Write a binary file to a specific address or partition in a target
92+
/// device's flash
9293
WriteBin(WriteBinArgs),
9394
}
9495

espflash/src/cli/mod.rs

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use clap::{Args, ValueEnum};
2222
use clap_complete::Shell;
2323
use comfy_table::{modifiers, presets::UTF8_FULL, Attribute, Cell, Color, Table};
2424
use esp_idf_part::{DataType, Partition, PartitionTable};
25-
use indicatif::{style::ProgressStyle, HumanCount, ProgressBar};
25+
use indicatif::{style::ProgressStyle, HumanBytes, HumanCount, ProgressBar};
2626
use log::{debug, info, warn};
2727
use miette::{IntoDiagnostic, Result, WrapErr};
2828
use serialport::{FlowControl, SerialPortInfo, SerialPortType, UsbPortInfo};
@@ -324,9 +324,13 @@ pub struct ListPortsArgs {
324324
#[derive(Debug, Args)]
325325
#[non_exhaustive]
326326
pub struct WriteBinArgs {
327-
/// Address at which to write the binary file
328-
#[arg(value_parser = parse_u32)]
329-
pub address: u32,
327+
/// Address or partition label at which to write the binary file
328+
#[arg(value_parser = parse_write_target)]
329+
pub target: WriteTarget,
330+
/// Path to a CSV file containing partition table, needed to resolve the
331+
/// partition label.
332+
#[arg(long, value_name = "FILE")]
333+
pub partition_table: Option<PathBuf>,
330334
/// File containing the binary data to write
331335
pub file: String,
332336
/// Connection configuration
@@ -340,6 +344,24 @@ pub struct WriteBinArgs {
340344
pub monitor_args: MonitorConfigArgs,
341345
}
342346

347+
/// Represents the target address for writing a binary file
348+
#[derive(Debug, Clone)]
349+
pub enum WriteTarget {
350+
Address(u32),
351+
Partition(String),
352+
}
353+
354+
/// Parses a string into a [WriteTarget].
355+
///
356+
/// If the input is a valid u32, it is treated as an address, otherwise as a
357+
/// partition label.
358+
pub fn parse_write_target(input: &str) -> Result<WriteTarget, ParseIntError> {
359+
Ok(parse_u32(input).map_or_else(
360+
|_| WriteTarget::Partition(input.to_string()),
361+
WriteTarget::Address,
362+
))
363+
}
364+
343365
/// Parses an integer, in base-10 or hexadecimal format, into a [u32]
344366
pub fn parse_u32(input: &str) -> Result<u32, ParseIntError> {
345367
let input: &str = &input.replace('_', "");
@@ -1010,13 +1032,7 @@ pub fn make_flash_data(
10101032

10111033
/// Write a binary to the flash memory of a target device
10121034
pub fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
1013-
let mut flasher = connect(&args.connect_args, config, false, false)?;
1014-
print_board_info(&mut flasher)?;
1015-
1016-
let chip = flasher.chip();
1017-
let target = chip.into_target();
1018-
let target_xtal_freq = target.crystal_freq(flasher.connection())?;
1019-
1035+
// Load the file to be flashed
10201036
let mut f = File::open(&args.file).into_diagnostic()?;
10211037

10221038
// If the file size is not divisible by 4, we need to pad `FF` bytes to the end
@@ -1029,11 +1045,56 @@ pub fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
10291045
f.read_to_end(&mut buffer).into_diagnostic()?;
10301046
buffer.extend(std::iter::repeat_n(0xFF, padded_bytes as usize));
10311047

1032-
flasher.write_bin_to_flash(
1033-
args.address,
1034-
&buffer,
1035-
Some(&mut EspflashProgress::default()),
1036-
)?;
1048+
// Figure out where to flash the file
1049+
let address = match args.target {
1050+
WriteTarget::Address(address) => address,
1051+
WriteTarget::Partition(label) => {
1052+
let Some(partition_table) = args
1053+
.partition_table
1054+
.as_deref()
1055+
.or(config.partition_table.as_deref())
1056+
else {
1057+
miette::bail!("A partition table is required to resolve partition label");
1058+
};
1059+
1060+
let data = fs::read(partition_table)
1061+
.into_diagnostic()
1062+
.with_context(|| {
1063+
format!(
1064+
"Failed to read partition table from {}",
1065+
partition_table.display(),
1066+
)
1067+
})?;
1068+
1069+
let partition_table = PartitionTable::try_from(data)
1070+
.into_diagnostic()
1071+
.context("Failed to parse partition table")?;
1072+
1073+
let Some(partition) = partition_table.find(&label) else {
1074+
miette::bail!("{} partition not found in partition table", label);
1075+
};
1076+
1077+
if partition.size() < buffer.len() as u32 {
1078+
miette::bail!(
1079+
"Can not flash a binary image of {} to {} partition ({})",
1080+
HumanBytes(buffer.len() as u64),
1081+
label,
1082+
HumanBytes(partition.size() as u64)
1083+
);
1084+
}
1085+
1086+
partition.offset()
1087+
}
1088+
};
1089+
1090+
let mut flasher = connect(&args.connect_args, config, false, false)?;
1091+
print_board_info(&mut flasher)?;
1092+
1093+
let chip = flasher.chip();
1094+
let target = chip.into_target();
1095+
let target_xtal_freq = target.crystal_freq(flasher.connection())?;
1096+
1097+
flasher.write_bin_to_flash(address, &buffer, Some(&mut EspflashProgress::default()))?;
10371098

10381099
if args.monitor {
10391100
let pid = flasher.usb_pid();

espflash/tests/scripts/write-bin.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env bash
2+
part_table="espflash/tests/data/partitions.csv"
23

34
# https://github.com/esp-rs/espflash/issues/622 reproducer
45
echo -ne "\x01\xa0" >binary_file.bin
@@ -20,3 +21,22 @@ if ! grep -q -a -F $'\x01\xa0' flash_content.bin; then
2021
echo "Failed verifying content"
2122
exit 1
2223
fi
24+
25+
result=$(espflash write-bin nvs binary_file.bin --partition-table $part_table 2>&1)
26+
echo "$result"
27+
if [[ ! $result =~ "Binary successfully written to flash!" ]]; then
28+
echo "Failed to write binary to the nvs partition label"
29+
exit 1
30+
fi
31+
32+
result=$(espflash read-flash 0x9000 64 flash_content.bin 2>&1)
33+
echo "$result"
34+
if [[ ! $result =~ "Flash content successfully read and written to" ]]; then
35+
echo "Failed to read flash content"
36+
exit 1
37+
fi
38+
# Check that the flash_content.bin contains the '01 a0' bytes
39+
if ! grep -q -a -F $'\x01\xa0' flash_content.bin; then
40+
echo "Failed verifying content"
41+
exit 1
42+
fi

0 commit comments

Comments
 (0)