Skip to content

Commit dea11d0

Browse files
committed
feat: Add serial ports config file
1 parent d76820f commit dea11d0

File tree

5 files changed

+147
-64
lines changed

5 files changed

+147
-64
lines changed

cargo-espflash/src/main.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use espflash::{
1010
Error as EspflashError,
1111
cli::{
1212
self,
13-
config::Config,
13+
config::{Config, PortConfig},
1414
monitor::{check_monitor_args, monitor},
1515
*,
1616
},
@@ -231,24 +231,27 @@ fn main() -> Result<()> {
231231
// Load any user configuration, if present.
232232
let config = Config::load()?;
233233

234+
// Load any user ports configuration, if present.
235+
let ports_config = PortConfig::load()?;
236+
234237
// Execute the correct action based on the provided subcommand and its
235238
// associated arguments.
236239
match args {
237-
Commands::BoardInfo(args) => board_info(&args, &config),
238-
Commands::ChecksumMd5(args) => checksum_md5(&args, &config),
240+
Commands::BoardInfo(args) => board_info(&args, &config, &ports_config),
241+
Commands::ChecksumMd5(args) => checksum_md5(&args, &config, &ports_config),
239242
Commands::Completions(args) => completions(&args, &mut Cli::command(), "cargo"),
240-
Commands::EraseFlash(args) => erase_flash(args, &config),
241-
Commands::EraseParts(args) => erase_parts(args, &config),
242-
Commands::EraseRegion(args) => erase_region(args, &config),
243-
Commands::Flash(args) => flash(args, &config),
244-
Commands::HoldInReset(args) => hold_in_reset(args, &config),
245-
Commands::ListPorts(args) => list_ports(&args, &config),
246-
Commands::Monitor(args) => serial_monitor(args, &config),
243+
Commands::EraseFlash(args) => erase_flash(args, &config, &ports_config),
244+
Commands::EraseParts(args) => erase_parts(args, &config, &ports_config),
245+
Commands::EraseRegion(args) => erase_region(args, &config, &ports_config),
246+
Commands::Flash(args) => flash(args, &config, &ports_config),
247+
Commands::HoldInReset(args) => hold_in_reset(args, &config, &ports_config),
248+
Commands::ListPorts(args) => list_ports(&args, &ports_config),
249+
Commands::Monitor(args) => serial_monitor(args, &config, &ports_config),
247250
Commands::PartitionTable(args) => partition_table(args),
248-
Commands::ReadFlash(args) => read_flash(args, &config),
249-
Commands::Reset(args) => reset(args, &config),
251+
Commands::ReadFlash(args) => read_flash(args, &config, &ports_config),
252+
Commands::Reset(args) => reset(args, &config, &ports_config),
250253
Commands::SaveImage(args) => save_image(args, &config),
251-
Commands::WriteBin(args) => write_bin(args, &config),
254+
Commands::WriteBin(args) => write_bin(args, &config, &ports_config),
252255
}
253256
}
254257

@@ -259,7 +262,7 @@ struct BuildContext {
259262
pub partition_table_path: Option<PathBuf>,
260263
}
261264

262-
pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
265+
pub fn erase_parts(args: ErasePartsArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
263266
if args.connect_args.no_stub {
264267
return Err(EspflashError::StubRequired).into_diagnostic();
265268
}
@@ -269,7 +272,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
269272
.as_deref()
270273
.or(config.partition_table.as_deref());
271274

272-
let mut flasher = connect(&args.connect_args, config, false, false)?;
275+
let mut flasher = connect(&args.connect_args, config, ports_config, false, false)?;
273276
let chip = flasher.chip();
274277
let partition_table = match partition_table {
275278
Some(path) => Some(parse_partition_table(path)?),
@@ -286,13 +289,14 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
286289
Ok(())
287290
}
288291

289-
fn flash(args: FlashArgs, config: &Config) -> Result<()> {
292+
fn flash(args: FlashArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
290293
let metadata = PackageMetadata::load(&args.build_args.package)?;
291294
let cargo_config = CargoConfig::load(&metadata.workspace_root, &metadata.package_root);
292295

293296
let mut flasher = connect(
294297
&args.connect_args,
295298
config,
299+
ports_config,
296300
args.flash_args.no_verify,
297301
args.flash_args.no_skip,
298302
)?;

espflash/src/bin/espflash.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use espflash::{
55
Error,
66
cli::{
77
self,
8-
config::Config,
8+
config::{Config, PortConfig},
99
monitor::{check_monitor_args, monitor},
1010
*,
1111
},
@@ -162,33 +162,36 @@ fn main() -> Result<()> {
162162
// Load any user configuration, if present.
163163
let config = Config::load()?;
164164

165+
// Load any user ports configuration, if present.
166+
let ports_config = PortConfig::load()?;
167+
165168
// Execute the correct action based on the provided subcommand and its
166169
// associated arguments.
167170
match args {
168-
Commands::BoardInfo(args) => board_info(&args, &config),
169-
Commands::ChecksumMd5(args) => checksum_md5(&args, &config),
171+
Commands::BoardInfo(args) => board_info(&args, &config, &ports_config),
172+
Commands::ChecksumMd5(args) => checksum_md5(&args, &config, &ports_config),
170173
Commands::Completions(args) => completions(&args, &mut Cli::command(), "espflash"),
171-
Commands::EraseFlash(args) => erase_flash(args, &config),
172-
Commands::EraseParts(args) => erase_parts(args, &config),
173-
Commands::EraseRegion(args) => erase_region(args, &config),
174-
Commands::Flash(args) => flash(args, &config),
175-
Commands::HoldInReset(args) => hold_in_reset(args, &config),
176-
Commands::ListPorts(args) => list_ports(&args, &config),
177-
Commands::Monitor(args) => serial_monitor(args, &config),
174+
Commands::EraseFlash(args) => erase_flash(args, &config, &ports_config),
175+
Commands::EraseParts(args) => erase_parts(args, &config, &ports_config),
176+
Commands::EraseRegion(args) => erase_region(args, &config, &ports_config),
177+
Commands::Flash(args) => flash(args, &config, &ports_config),
178+
Commands::HoldInReset(args) => hold_in_reset(args, &config, &ports_config),
179+
Commands::ListPorts(args) => list_ports(&args, &ports_config),
180+
Commands::Monitor(args) => serial_monitor(args, &config, &ports_config),
178181
Commands::PartitionTable(args) => partition_table(args),
179-
Commands::ReadFlash(args) => read_flash(args, &config),
180-
Commands::Reset(args) => reset(args, &config),
182+
Commands::ReadFlash(args) => read_flash(args, &config, &ports_config),
183+
Commands::Reset(args) => reset(args, &config, &ports_config),
181184
Commands::SaveImage(args) => save_image(args, &config),
182-
Commands::WriteBin(args) => write_bin(args, &config),
185+
Commands::WriteBin(args) => write_bin(args, &config, &ports_config),
183186
}
184187
}
185188

186-
pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
189+
pub fn erase_parts(args: ErasePartsArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
187190
if args.connect_args.no_stub {
188191
return Err(Error::StubRequired.into());
189192
}
190193

191-
let mut flasher = connect(&args.connect_args, config, false, false)?;
194+
let mut flasher = connect(&args.connect_args, config, ports_config, false, false)?;
192195
let chip = flasher.chip();
193196
let partition_table = match args.partition_table {
194197
Some(path) => Some(parse_partition_table(&path)?),
@@ -207,14 +210,15 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
207210
Ok(())
208211
}
209212

210-
fn flash(args: FlashArgs, config: &Config) -> Result<()> {
213+
fn flash(args: FlashArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
211214
let mut monitor_args = args.flash_args.monitor_args;
212215
monitor_args.elf = Some(args.image.clone());
213216
check_monitor_args(&args.flash_args.monitor, &monitor_args)?;
214217

215218
let mut flasher = connect(
216219
&args.connect_args,
217220
config,
221+
ports_config,
218222
args.flash_args.no_verify,
219223
args.flash_args.no_skip,
220224
)?;

espflash/src/cli/config.rs

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,12 @@ pub struct Config {
8181
/// Bootloader path
8282
#[serde(default)]
8383
pub bootloader: Option<PathBuf>,
84-
/// Preferred serial port connection information
85-
#[serde(default)]
86-
pub connection: Connection,
8784
/// Partition table path
8885
#[serde(default)]
8986
pub partition_table: Option<PathBuf>,
9087
/// Partition table offset
9188
#[serde(default)]
9289
pub partition_table_offset: Option<u32>,
93-
/// Preferred USB devices
94-
#[serde(default)]
95-
pub usb_device: Vec<UsbDevice>,
9690
/// Flash settings
9791
#[serde(default)]
9892
pub flash: FlashSettings,
@@ -164,6 +158,72 @@ impl Config {
164158
}
165159
}
166160

161+
/// Deserialized contents of a serial port configuration file
162+
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
163+
pub struct PortConfig {
164+
/// Preferred serial port connection information
165+
#[serde(default)]
166+
pub connection: Connection,
167+
/// Partition table path
168+
/// Preferred USB devices
169+
#[serde(default)]
170+
pub usb_device: Vec<UsbDevice>,
171+
/// Path of the file to save the configuration to
172+
#[serde(skip)]
173+
save_path: PathBuf,
174+
}
175+
176+
impl PortConfig {
177+
/// Gets the path to the configuration file.
178+
pub fn get_config_path() -> Result<PathBuf, Error> {
179+
let local_config = std::env::current_dir()?.join("espflash_ports.toml");
180+
if local_config.exists() {
181+
return Ok(local_config);
182+
}
183+
if let Some(parent_folder) = std::env::current_dir()?.parent() {
184+
let workspace_config = parent_folder.join("espflash_ports.toml");
185+
if workspace_config.exists() {
186+
return Ok(workspace_config);
187+
}
188+
}
189+
190+
let project_dirs = ProjectDirs::from("rs", "esp", "espflash").unwrap();
191+
let global_config = project_dirs.config_dir().join("espflash_ports.toml");
192+
Ok(global_config)
193+
}
194+
195+
/// Load configuration from the configuration file
196+
pub fn load() -> Result<Self> {
197+
let file = Self::get_config_path()?;
198+
199+
let mut config = if let Ok(data) = read_to_string(&file) {
200+
toml::from_str(&data).into_diagnostic()?
201+
} else {
202+
Self::default()
203+
};
204+
205+
config.save_path = file;
206+
debug!("Config: {:#?}", &config);
207+
Ok(config)
208+
}
209+
210+
/// Save configuration to the configuration file
211+
pub fn save_with<F: Fn(&mut Self)>(&self, modify_fn: F) -> Result<()> {
212+
let mut copy = self.clone();
213+
modify_fn(&mut copy);
214+
215+
let serialized = toml::to_string(&copy)
216+
.into_diagnostic()
217+
.wrap_err("Failed to serialize config")?;
218+
create_dir_all(self.save_path.parent().unwrap())
219+
.into_diagnostic()
220+
.wrap_err("Failed to create config directory")?;
221+
write(&self.save_path, serialized)
222+
.into_diagnostic()
223+
.wrap_err_with(|| format!("Failed to write config to {}", self.save_path.display()))
224+
}
225+
}
226+
167227
#[cfg(test)]
168228
mod tests {
169229
use serde::Deserialize;

0 commit comments

Comments
 (0)