@@ -22,7 +22,7 @@ use clap::{Args, ValueEnum};
2222use clap_complete:: Shell ;
2323use comfy_table:: { modifiers, presets:: UTF8_FULL , Attribute , Cell , Color , Table } ;
2424use esp_idf_part:: { DataType , Partition , PartitionTable } ;
25- use indicatif:: { style:: ProgressStyle , HumanCount , ProgressBar } ;
25+ use indicatif:: { style:: ProgressStyle , HumanBytes , HumanCount , ProgressBar } ;
2626use log:: { debug, info, warn} ;
2727use miette:: { IntoDiagnostic , Result , WrapErr } ;
2828use serialport:: { FlowControl , SerialPortInfo , SerialPortType , UsbPortInfo } ;
@@ -324,9 +324,13 @@ pub struct ListPortsArgs {
324324#[ derive( Debug , Args ) ]
325325#[ non_exhaustive]
326326pub 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]
344366pub 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
10121034pub 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 ( ) ;
0 commit comments