@@ -22,7 +22,7 @@ use clap::{Args, ValueEnum};
22
22
use clap_complete:: Shell ;
23
23
use comfy_table:: { modifiers, presets:: UTF8_FULL , Attribute , Cell , Color , Table } ;
24
24
use esp_idf_part:: { DataType , Partition , PartitionTable } ;
25
- use indicatif:: { style:: ProgressStyle , HumanCount , ProgressBar } ;
25
+ use indicatif:: { style:: ProgressStyle , HumanBytes , HumanCount , ProgressBar } ;
26
26
use log:: { debug, info, warn} ;
27
27
use miette:: { IntoDiagnostic , Result , WrapErr } ;
28
28
use serialport:: { FlowControl , SerialPortInfo , SerialPortType , UsbPortInfo } ;
@@ -324,9 +324,13 @@ pub struct ListPortsArgs {
324
324
#[ derive( Debug , Args ) ]
325
325
#[ non_exhaustive]
326
326
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 > ,
330
334
/// File containing the binary data to write
331
335
pub file : String ,
332
336
/// Connection configuration
@@ -340,6 +344,24 @@ pub struct WriteBinArgs {
340
344
pub monitor_args : MonitorConfigArgs ,
341
345
}
342
346
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
+
343
365
/// Parses an integer, in base-10 or hexadecimal format, into a [u32]
344
366
pub fn parse_u32 ( input : & str ) -> Result < u32 , ParseIntError > {
345
367
let input: & str = & input. replace ( '_' , "" ) ;
@@ -1010,13 +1032,7 @@ pub fn make_flash_data(
1010
1032
1011
1033
/// Write a binary to the flash memory of a target device
1012
1034
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
1020
1036
let mut f = File :: open ( & args. file ) . into_diagnostic ( ) ?;
1021
1037
1022
1038
// 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<()> {
1029
1045
f. read_to_end ( & mut buffer) . into_diagnostic ( ) ?;
1030
1046
buffer. extend ( std:: iter:: repeat_n ( 0xFF , padded_bytes as usize ) ) ;
1031
1047
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 ( ) ) ) ?;
1037
1098
1038
1099
if args. monitor {
1039
1100
let pid = flasher. usb_pid ( ) ;
0 commit comments