mod diagnostics;
use clap::Parser;
use colored::Colorize;
use diagnostics::render_diagnostics;
use probe_rs::config::Registry;
use probe_rs::probe::list::Lister;
use std::ffi::OsString;
use std::{path::PathBuf, process};
use crate::util::cargo::target_instruction_set;
use crate::util::common_options::{
BinaryDownloadOptions, CargoOptions, OperationError, ProbeOptions,
};
use crate::util::flash;
use crate::util::logging::{LevelFilter, setup_logging};
use crate::util::{cargo::build_artifact, logging};
#[derive(Debug, clap::Parser)]
#[clap(
name = "cargo flash",
bin_name = "cargo flash",
version = env!("PROBE_RS_VERSION"),
long_version = env!("PROBE_RS_LONG_VERSION"),
after_long_help = CargoOptions::help_message("cargo flash")
)]
struct CliOptions {
#[arg(long)]
pub reset_halt: bool,
#[arg(value_name = "level", long)]
pub log: Option<LevelFilter>,
#[arg(value_name = "path", long)]
pub path: Option<PathBuf>,
#[arg(value_name = "directory", long)]
pub work_dir: Option<PathBuf>,
#[command(flatten)]
pub cargo_options: CargoOptions,
#[command(flatten)]
pub probe_options: ProbeOptions,
#[command(flatten)]
pub download_options: BinaryDownloadOptions,
#[command(flatten)]
pub format_options: crate::FormatOptions,
}
pub fn main(args: &[OsString]) {
let mut registry = Registry::from_builtin_families();
match main_try(&mut registry, args) {
Ok(_) => (),
Err(e) => {
render_diagnostics(®istry, e);
process::exit(1);
}
}
}
fn main_try(registry: &mut Registry, args: &[OsString]) -> Result<(), OperationError> {
let opt = CliOptions::parse_from(args);
let _log_guard = setup_logging(None, opt.log);
if let Some(ref work_dir) = opt.work_dir {
std::env::set_current_dir(work_dir).map_err(|error| {
OperationError::FailedToChangeWorkingDirectory {
source: error,
path: work_dir.clone(),
}
})?;
}
let work_dir = std::env::current_dir()?;
let image_instr_set;
let path = if let Some(path_buf) = &opt.path {
image_instr_set = None;
path_buf.clone()
} else {
let cargo_options = opt.cargo_options.to_cargo_options();
image_instr_set = target_instruction_set(opt.cargo_options.target.as_deref());
build_artifact(&work_dir, &cargo_options)
.map_err(|error| {
if let Some(ref work_dir) = opt.work_dir {
OperationError::FailedToBuildExternalCargoProject {
source: error,
path: work_dir.canonicalize().unwrap(),
}
} else {
OperationError::FailedToBuildCargoProject(error)
}
})?
.path()
.into()
};
logging::eprintln(format!(
" {} {}",
"Flashing".green().bold(),
path.display()
));
let lister = Lister::new();
let (mut session, probe_options) = opt.probe_options.simple_attach(registry, &lister)?;
let loader =
flash::build_loader(&mut session, &path, opt.format_options, image_instr_set).unwrap();
flash::run_flash_download(
&mut session,
&path,
&opt.download_options,
&probe_options,
loader,
false,
)?;
{
let mut core = session
.core(0)
.map_err(OperationError::AttachingToCoreFailed)?;
if opt.reset_halt {
core.reset_and_halt(std::time::Duration::from_millis(500))
.map_err(OperationError::TargetResetHaltFailed)?;
} else {
core.reset().map_err(OperationError::TargetResetFailed)?;
}
}
Ok(())
}