Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add serial ports config file #777

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions cargo-espflash/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ use std::{
use cargo_metadata::{Message, MetadataCommand};
use clap::{Args, CommandFactory, Parser, Subcommand};
use espflash::{
cli::{self, config::Config, monitor::monitor, *},
cli::{
self,
config::{Config, PortConfig},
monitor::monitor,
*,
},
flasher::parse_partition_table,
logging::initialize_logger,
targets::{Chip, XtalFrequency},
Expand Down Expand Up @@ -223,22 +228,25 @@ fn main() -> Result<()> {
// Load any user configuration, if present.
let config = Config::load()?;

// Load any user ports configuration, if present.
let ports_config = PortConfig::load()?;

// Execute the correct action based on the provided subcommand and its
// associated arguments.
match args {
Commands::BoardInfo(args) => board_info(&args, &config),
Commands::ChecksumMd5(args) => checksum_md5(&args, &config),
Commands::BoardInfo(args) => board_info(&args, &config, &ports_config),
Commands::ChecksumMd5(args) => checksum_md5(&args, &config, &ports_config),
Commands::Completions(args) => completions(&args, &mut Cli::command(), "cargo"),
Commands::EraseFlash(args) => erase_flash(args, &config),
Commands::EraseParts(args) => erase_parts(args, &config),
Commands::EraseRegion(args) => erase_region(args, &config),
Commands::Flash(args) => flash(args, &config),
Commands::HoldInReset(args) => hold_in_reset(args, &config),
Commands::ListPorts(args) => list_ports(&args, &config),
Commands::Monitor(args) => serial_monitor(args, &config),
Commands::EraseFlash(args) => erase_flash(args, &config, &ports_config),
Commands::EraseParts(args) => erase_parts(args, &config, &ports_config),
Commands::EraseRegion(args) => erase_region(args, &config, &ports_config),
Commands::Flash(args) => flash(args, &config, &ports_config),
Commands::HoldInReset(args) => hold_in_reset(args, &config, &ports_config),
Commands::ListPorts(args) => list_ports(&args, &ports_config),
Commands::Monitor(args) => serial_monitor(args, &config, &ports_config),
Commands::PartitionTable(args) => partition_table(args),
Commands::ReadFlash(args) => read_flash(args, &config),
Commands::Reset(args) => reset(args, &config),
Commands::ReadFlash(args) => read_flash(args, &config, &ports_config),
Commands::Reset(args) => reset(args, &config, &ports_config),
Commands::SaveImage(args) => save_image(args, &config),
}
}
Expand All @@ -250,7 +258,7 @@ struct BuildContext {
pub partition_table_path: Option<PathBuf>,
}

pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
pub fn erase_parts(args: ErasePartsArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
if args.connect_args.no_stub {
return Err(EspflashError::StubRequired).into_diagnostic();
}
Expand All @@ -260,7 +268,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
.as_deref()
.or(config.partition_table.as_deref());

let mut flasher = connect(&args.connect_args, config, false, false)?;
let mut flasher = connect(&args.connect_args, config, ports_config, false, false)?;
let partition_table = match partition_table {
Some(path) => Some(parse_partition_table(path)?),
None => None,
Expand All @@ -276,30 +284,31 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
Ok(())
}

fn reset(args: ConnectArgs, config: &Config) -> Result<()> {
fn reset(args: ConnectArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
let mut args = args.clone();
args.no_stub = true;
let mut flash = connect(&args, config, true, true)?;
let mut flash = connect(&args, config, ports_config, true, true)?;
info!("Resetting target device");
flash.connection().reset()?;

Ok(())
}

fn hold_in_reset(args: ConnectArgs, config: &Config) -> Result<()> {
connect(&args, config, true, true)?;
fn hold_in_reset(args: ConnectArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
connect(&args, config, ports_config, true, true)?;
info!("Holding target device in reset");

Ok(())
}

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

let mut flasher = connect(
&args.connect_args,
config,
ports_config,
args.flash_args.no_verify,
args.flash_args.no_skip,
)?;
Expand Down
53 changes: 31 additions & 22 deletions espflash/src/bin/espflash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ use std::{

use clap::{Args, CommandFactory, Parser, Subcommand};
use espflash::{
cli::{self, config::Config, monitor::monitor, *},
cli::{
self,
config::{Config, PortConfig},
monitor::monitor,
*,
},
flasher::parse_partition_table,
logging::initialize_logger,
targets::{Chip, XtalFrequency},
Expand Down Expand Up @@ -174,33 +179,36 @@ fn main() -> Result<()> {
// Load any user configuration, if present.
let config = Config::load()?;

// Load any user ports configuration, if present.
let ports_config = PortConfig::load()?;

// Execute the correct action based on the provided subcommand and its
// associated arguments.
match args {
Commands::BoardInfo(args) => board_info(&args, &config),
Commands::ChecksumMd5(args) => checksum_md5(&args, &config),
Commands::BoardInfo(args) => board_info(&args, &config, &ports_config),
Commands::ChecksumMd5(args) => checksum_md5(&args, &config, &ports_config),
Commands::Completions(args) => completions(&args, &mut Cli::command(), "espflash"),
Commands::EraseFlash(args) => erase_flash(args, &config),
Commands::EraseParts(args) => erase_parts(args, &config),
Commands::EraseRegion(args) => erase_region(args, &config),
Commands::Flash(args) => flash(args, &config),
Commands::HoldInReset(args) => hold_in_reset(args, &config),
Commands::ListPorts(args) => list_ports(&args, &config),
Commands::Monitor(args) => serial_monitor(args, &config),
Commands::EraseFlash(args) => erase_flash(args, &config, &ports_config),
Commands::EraseParts(args) => erase_parts(args, &config, &ports_config),
Commands::EraseRegion(args) => erase_region(args, &config, &ports_config),
Commands::Flash(args) => flash(args, &config, &ports_config),
Commands::HoldInReset(args) => hold_in_reset(args, &config, &ports_config),
Commands::ListPorts(args) => list_ports(&args, &ports_config),
Commands::Monitor(args) => serial_monitor(args, &config, &ports_config),
Commands::PartitionTable(args) => partition_table(args),
Commands::ReadFlash(args) => read_flash(args, &config),
Commands::Reset(args) => reset(args, &config),
Commands::ReadFlash(args) => read_flash(args, &config, &ports_config),
Commands::Reset(args) => reset(args, &config, &ports_config),
Commands::SaveImage(args) => save_image(args, &config),
Commands::WriteBin(args) => write_bin(args, &config),
Commands::WriteBin(args) => write_bin(args, &config, &ports_config),
}
}

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

let mut flasher = connect(&args.connect_args, config, false, false)?;
let mut flasher = connect(&args.connect_args, config, ports_config, false, false)?;
let partition_table = match args.partition_table {
Some(path) => Some(parse_partition_table(&path)?),
None => None,
Expand All @@ -218,27 +226,28 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
Ok(())
}

fn reset(args: ConnectArgs, config: &Config) -> Result<()> {
fn reset(args: ConnectArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
let mut args = args.clone();
args.no_stub = true;
let mut flash = connect(&args, config, true, true)?;
let mut flash = connect(&args, config, ports_config, true, true)?;
info!("Resetting target device");
flash.connection().reset()?;

Ok(())
}

fn hold_in_reset(args: ConnectArgs, config: &Config) -> Result<()> {
connect(&args, config, true, true)?;
fn hold_in_reset(args: ConnectArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
connect(&args, config, ports_config, true, true)?;
info!("Holding target device in reset");

Ok(())
}

fn flash(args: FlashArgs, config: &Config) -> Result<()> {
fn flash(args: FlashArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
let mut flasher = connect(
&args.connect_args,
config,
ports_config,
args.flash_args.no_verify,
args.flash_args.no_skip,
)?;
Expand Down Expand Up @@ -342,8 +351,8 @@ fn save_image(args: SaveImageArgs, config: &Config) -> Result<()> {
Ok(())
}

fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
let mut flasher = connect(&args.connect_args, config, false, false)?;
fn write_bin(args: WriteBinArgs, config: &Config, ports_config: &PortConfig) -> Result<()> {
let mut flasher = connect(&args.connect_args, config, ports_config, false, false)?;
print_board_info(&mut flasher)?;

let mut f = File::open(&args.file).into_diagnostic()?;
Expand Down
71 changes: 65 additions & 6 deletions espflash/src/cli/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,12 @@ pub struct Config {
/// Bootloader path
#[serde(default)]
pub bootloader: Option<PathBuf>,
/// Preferred serial port connection information
#[serde(default)]
pub connection: Connection,
/// Partition table path
#[serde(default)]
pub partition_table: Option<PathBuf>,
/// Partition table offset
#[serde(default)]
pub partition_table_offset: Option<u32>,
/// Preferred USB devices
#[serde(default)]
pub usb_device: Vec<UsbDevice>,
/// Flash settings
#[serde(default)]
pub flash: FlashSettings,
Expand Down Expand Up @@ -164,6 +158,71 @@ impl Config {
}
}

/// Deserialized contents of a serial port configuration file
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
pub struct PortConfig {
/// Preferred serial port connection information
#[serde(default)]
pub connection: Connection,
/// Preferred USB devices
#[serde(default)]
pub usb_device: Vec<UsbDevice>,
/// Path of the file to save the configuration to
#[serde(skip)]
save_path: PathBuf,
}

impl PortConfig {
/// Gets the path to the configuration file.
pub fn get_config_path() -> Result<PathBuf, Error> {
let local_config = std::env::current_dir()?.join("espflash_ports.toml");
if local_config.exists() {
return Ok(local_config);
}
if let Some(parent_folder) = std::env::current_dir()?.parent() {
let workspace_config = parent_folder.join("espflash_ports.toml");
if workspace_config.exists() {
return Ok(workspace_config);
}
}

let project_dirs = ProjectDirs::from("rs", "esp", "espflash").unwrap();
let global_config = project_dirs.config_dir().join("espflash_ports.toml");
Ok(global_config)
}

/// Load configuration from the configuration file
pub fn load() -> Result<Self> {
let file = Self::get_config_path()?;

let mut config = if let Ok(data) = read_to_string(&file) {
toml::from_str(&data).into_diagnostic()?
} else {
Self::default()
};

config.save_path = file;
debug!("Config: {:#?}", &config);
Ok(config)
}

/// Save configuration to the configuration file
pub fn save_with<F: Fn(&mut Self)>(&self, modify_fn: F) -> Result<()> {
let mut copy = self.clone();
modify_fn(&mut copy);

let serialized = toml::to_string(&copy)
.into_diagnostic()
.wrap_err("Failed to serialize config")?;
create_dir_all(self.save_path.parent().unwrap())
.into_diagnostic()
.wrap_err("Failed to create config directory")?;
write(&self.save_path, serialized)
.into_diagnostic()
.wrap_err_with(|| format!("Failed to write config to {}", self.save_path.display()))
}
}

#[cfg(test)]
mod tests {
use serde::Deserialize;
Expand Down
Loading
Loading