@@ -8,8 +8,11 @@ use std::{
8
8
use cargo_metadata:: Message ;
9
9
use clap:: { AppSettings , Parser } ;
10
10
use espflash:: {
11
- cli:: { clap:: * , connect, monitor:: monitor} ,
12
- Chip , Config , FirmwareImage , ImageFormatId , PartitionTable ,
11
+ cli:: {
12
+ board_info, connect, flash_elf_image, monitor:: monitor, save_elf_as_image, ConnectOpts ,
13
+ FlashOpts ,
14
+ } ,
15
+ Chip , Config , ImageFormatId ,
13
16
} ;
14
17
use miette:: { IntoDiagnostic , Result , WrapErr } ;
15
18
@@ -24,12 +27,11 @@ mod error;
24
27
mod package_metadata;
25
28
26
29
#[ derive( Parser ) ]
30
+ #[ clap( bin_name = "cargo" , version) ]
27
31
#[ clap( global_setting = AppSettings :: PropagateVersion ) ]
28
- #[ clap( bin_name = "cargo" ) ]
29
- #[ clap( version = env!( "CARGO_PKG_VERSION" ) ) ]
30
32
struct Opts {
31
33
#[ clap( subcommand) ]
32
- sub_cmd : CargoSubCommand ,
34
+ subcommand : CargoSubCommand ,
33
35
}
34
36
35
37
#[ derive( Parser ) ]
@@ -40,122 +42,137 @@ enum CargoSubCommand {
40
42
#[ derive( Parser ) ]
41
43
struct EspFlashOpts {
42
44
#[ clap( flatten) ]
43
- flash_args : FlashArgs ,
45
+ flash_opts : FlashOpts ,
44
46
#[ clap( flatten) ]
45
- build_args : BuildArgs ,
47
+ build_opts : BuildOpts ,
46
48
#[ clap( flatten) ]
47
- connect_args : ConnectArgs ,
49
+ connect_opts : ConnectOpts ,
48
50
#[ clap( subcommand) ]
49
- sub_cmd : Option < SubCommand > ,
51
+ subcommand : Option < SubCommand > ,
50
52
}
51
53
52
54
#[ derive( Parser ) ]
53
55
pub enum SubCommand {
56
+ /// Display information about the connected board and exit without flashing
57
+ BoardInfo ( ConnectOpts ) ,
58
+ /// Save the image to disk instead of flashing to device
54
59
SaveImage ( SaveImageOpts ) ,
55
- BoardInfo ( BoardInfoOpts ) ,
60
+ }
61
+
62
+ #[ derive( Parser ) ]
63
+ pub struct BuildOpts {
64
+ /// Build the application using the release profile
65
+ #[ clap( long) ]
66
+ pub release : bool ,
67
+ /// Example to build and flash
68
+ #[ clap( long) ]
69
+ pub example : Option < String > ,
70
+ /// Specify a (binary) package within a workspace to be built
71
+ #[ clap( long) ]
72
+ pub package : Option < String > ,
73
+ /// Comma delimited list of build features
74
+ #[ clap( long, use_delimiter = true ) ]
75
+ pub features : Option < Vec < String > > ,
76
+ /// Image format to flash (bootloader/direct-boot)
77
+ #[ clap( long) ]
78
+ pub format : Option < String > ,
79
+ /// Target to build for
80
+ #[ clap( long) ]
81
+ pub target : Option < String > ,
82
+ /// Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
83
+ #[ clap( short = 'Z' ) ]
84
+ pub unstable : Option < Vec < String > > ,
85
+ }
86
+
87
+ #[ derive( Parser ) ]
88
+ pub struct SaveImageOpts {
89
+ #[ clap( flatten) ]
90
+ pub build_args : BuildOpts ,
91
+ /// File name to save the generated image to
92
+ pub file : PathBuf ,
56
93
}
57
94
58
95
fn main ( ) -> Result < ( ) > {
59
96
miette:: set_panic_hook ( ) ;
60
97
61
- let CargoSubCommand :: Espflash ( opts) = Opts :: parse ( ) . sub_cmd ;
98
+ let CargoSubCommand :: Espflash ( opts) = Opts :: parse ( ) . subcommand ;
62
99
63
100
let config = Config :: load ( ) ?;
64
101
let metadata = CargoEspFlashMeta :: load ( "Cargo.toml" ) ?;
65
102
let cargo_config = parse_cargo_config ( "." ) ?;
66
103
67
- match opts. sub_cmd {
68
- Some ( SubCommand :: BoardInfo ( matches) ) => board_info ( matches, config, metadata, cargo_config) ,
69
- Some ( SubCommand :: SaveImage ( matches) ) => save_image ( matches, config, metadata, cargo_config) ,
70
- None => flash ( opts, config, metadata, cargo_config) ,
104
+ if let Some ( subcommand) = opts. subcommand {
105
+ use SubCommand :: * ;
106
+
107
+ match subcommand {
108
+ BoardInfo ( opts) => board_info ( opts, config) ,
109
+ SaveImage ( opts) => save_image ( opts, metadata, cargo_config) ,
110
+ }
111
+ } else {
112
+ flash ( opts, config, metadata, cargo_config)
71
113
}
72
114
}
73
115
74
116
fn flash (
75
- matches : EspFlashOpts ,
117
+ opts : EspFlashOpts ,
76
118
config : Config ,
77
119
metadata : CargoEspFlashMeta ,
78
120
cargo_config : CargoConfig ,
79
121
) -> Result < ( ) > {
80
- // Connect the Flasher to the target device and print the board information
81
- // upon connection. If the '--board-info' flag has been provided, we have
82
- // nothing left to do so exit early.
83
- let mut flasher = connect ( & matches. connect_args , & config) ?;
84
- flasher. board_info ( ) ?;
122
+ let mut flasher = connect ( & opts. connect_opts , & config) ?;
85
123
86
- if matches. flash_args . board_info {
87
- return Ok ( ( ) ) ;
88
- }
89
-
90
- let path = build ( & matches. build_args , & cargo_config, Some ( flasher. chip ( ) ) )
124
+ let artifact_path = build ( & opts. build_opts , & cargo_config, Some ( flasher. chip ( ) ) )
91
125
. wrap_err ( "Failed to build project" ) ?;
92
126
93
- // If the '--bootloader' option is provided, load the binary file at the
94
- // specified path.
95
- let bootloader = if let Some ( path) = matches
96
- . flash_args
97
- . bootloader
98
- . as_deref ( )
99
- . or_else ( || metadata. bootloader . as_deref ( ) )
100
- {
101
- let path = fs:: canonicalize ( path) . into_diagnostic ( ) ?;
102
- let data = fs:: read ( path) . into_diagnostic ( ) ?;
103
- Some ( data)
104
- } else {
105
- None
106
- } ;
107
-
108
- // If the '--partition-table' option is provided, load the partition table from
109
- // the CSV at the specified path.
110
- let partition_table = if let Some ( path) = matches
111
- . flash_args
112
- . partition_table
113
- . as_deref ( )
114
- . or_else ( || metadata. partition_table . as_deref ( ) )
115
- {
116
- let path = fs:: canonicalize ( path) . into_diagnostic ( ) ?;
117
- let data = fs:: read_to_string ( path)
118
- . into_diagnostic ( )
119
- . wrap_err ( "Failed to open partition table" ) ?;
120
- let table =
121
- PartitionTable :: try_from_str ( data) . wrap_err ( "Failed to parse partition table" ) ?;
122
- Some ( table)
123
- } else {
124
- None
125
- } ;
126
-
127
- let image_format = matches
128
- . build_args
129
- . format
130
- . as_deref ( )
131
- . map ( ImageFormatId :: from_str)
132
- . transpose ( ) ?
133
- . or ( metadata. format ) ;
127
+ // Print the board information once the project has successfully built. We do
128
+ // here rather than upon connection to show the Cargo output prior to the board
129
+ // information, rather than breaking up cargo-espflash's output.
130
+ flasher. board_info ( ) ?;
134
131
135
132
// Read the ELF data from the build path and load it to the target.
136
- let elf_data = fs:: read ( path) . into_diagnostic ( ) ?;
137
- if matches. flash_args . ram {
133
+ let elf_data = fs:: read ( artifact_path) . into_diagnostic ( ) ?;
134
+
135
+ if opts. flash_opts . ram {
138
136
flasher. load_elf_to_ram ( & elf_data) ?;
139
137
} else {
140
- flasher. load_elf_to_flash_with_format (
138
+ let bootloader = opts
139
+ . flash_opts
140
+ . bootloader
141
+ . as_deref ( )
142
+ . or ( metadata. bootloader . as_deref ( ) ) ;
143
+
144
+ let partition_table = opts
145
+ . flash_opts
146
+ . partition_table
147
+ . as_deref ( )
148
+ . or ( metadata. partition_table . as_deref ( ) ) ;
149
+
150
+ let image_format = opts
151
+ . build_opts
152
+ . format
153
+ . as_deref ( )
154
+ . map ( ImageFormatId :: from_str)
155
+ . transpose ( ) ?
156
+ . or ( metadata. format ) ;
157
+
158
+ flash_elf_image (
159
+ & mut flasher,
141
160
& elf_data,
142
161
bootloader,
143
162
partition_table,
144
163
image_format,
145
164
) ?;
146
165
}
147
- println ! ( "\n Flashing has completed!" ) ;
148
166
149
- if matches . flash_args . monitor {
167
+ if opts . flash_opts . monitor {
150
168
monitor ( flasher. into_serial ( ) ) . into_diagnostic ( ) ?;
151
169
}
152
170
153
- // We're all done!
154
171
Ok ( ( ) )
155
172
}
156
173
157
174
fn build (
158
- build_options : & BuildArgs ,
175
+ build_options : & BuildOpts ,
159
176
cargo_config : & CargoConfig ,
160
177
chip : Option < Chip > ,
161
178
) -> Result < PathBuf > {
@@ -273,12 +290,11 @@ fn build(
273
290
}
274
291
275
292
fn save_image (
276
- matches : SaveImageOpts ,
277
- _config : Config ,
293
+ opts : SaveImageOpts ,
278
294
metadata : CargoEspFlashMeta ,
279
295
cargo_config : CargoConfig ,
280
296
) -> Result < ( ) > {
281
- let target = matches
297
+ let target = opts
282
298
. build_args
283
299
. target
284
300
. as_deref ( )
@@ -288,45 +304,19 @@ fn save_image(
288
304
289
305
let chip = Chip :: from_target ( target) . ok_or_else ( || Error :: UnknownTarget ( target. into ( ) ) ) ?;
290
306
291
- let path = build ( & matches . build_args , & cargo_config, Some ( chip) ) ?;
307
+ let path = build ( & opts . build_args , & cargo_config, Some ( chip) ) ?;
292
308
let elf_data = fs:: read ( path) . into_diagnostic ( ) ?;
293
309
294
- let image = FirmwareImage :: from_data ( & elf_data) ?;
295
-
296
- let image_format = matches
310
+ let image_format = opts
297
311
. build_args
298
312
. format
299
313
. as_deref ( )
300
314
. map ( ImageFormatId :: from_str)
301
315
. transpose ( ) ?
302
316
. or ( metadata. format ) ;
303
317
304
- let flash_image = chip. get_flash_image ( & image, None , None , image_format, None ) ?;
305
- let parts: Vec < _ > = flash_image. ota_segments ( ) . collect ( ) ;
306
-
307
- let out_path = matches. file ;
318
+ save_elf_as_image ( chip, & elf_data, opts. file , image_format) ?;
308
319
309
- match parts. as_slice ( ) {
310
- [ single] => fs:: write ( out_path, & single. data ) . into_diagnostic ( ) ?,
311
- parts => {
312
- for part in parts {
313
- let part_path = format ! ( "{:#x}_{}" , part. addr, out_path) ;
314
- fs:: write ( part_path, & part. data ) . into_diagnostic ( ) ?
315
- }
316
- }
317
- }
318
-
319
- Ok ( ( ) )
320
- }
321
-
322
- fn board_info (
323
- matches : BoardInfoOpts ,
324
- config : Config ,
325
- _metadata : CargoEspFlashMeta ,
326
- _cargo_config : CargoConfig ,
327
- ) -> Result < ( ) > {
328
- let mut flasher = connect ( & matches. connect_args , & config) ?;
329
- flasher. board_info ( ) ?;
330
320
Ok ( ( ) )
331
321
}
332
322
0 commit comments