use std::path::PathBuf;
use clap::{ArgAction, Parser};
use defmt_decoder::DEFMT_VERSION;
use git_version::git_version;
use log::Level;
use probe_rs::Probe;
use crate::probe;
const EXIT_SUCCESS: i32 = 0;
#[derive(Parser)]
#[command()]
pub struct Opts {
#[arg(long, default_value = "auto")]
pub backtrace: String,
#[arg(long, default_value = "50")]
pub backtrace_limit: u32,
#[arg(long, required = true, conflicts_with_all = HELPER_CMDS, env = "PROBE_RUN_CHIP")]
chip: Option<String>,
#[arg(long)]
pub chip_description_path: Option<PathBuf>,
#[arg(long)]
pub connect_under_reset: bool,
#[arg(long)]
pub disable_double_buffering: bool,
#[arg(required = true, conflicts_with_all = HELPER_CMDS)]
elf: Option<PathBuf>,
#[arg(long)]
pub json: bool,
#[arg(long)]
list_chips: bool,
#[arg(long)]
list_probes: bool,
#[arg(long)]
pub measure_stack: bool,
#[arg(
long,
conflicts_with = "disable_double_buffering",
conflicts_with = "verify"
)]
pub no_flash: bool,
#[arg(long, env = "PROBE_RUN_PROBE")]
pub probe: Option<String>,
#[arg(long)]
pub shorten_paths: bool,
#[arg(long, env = "PROBE_RUN_SPEED")]
pub speed: Option<u32>,
#[arg(short, long, action = ArgAction::Count)]
pub verbose: u8,
#[arg(long)]
pub verify: bool,
#[arg(short = 'V', long)]
version: bool,
#[arg(allow_hyphen_values = true, hide = true, trailing_var_arg = true)]
_rest: Vec<String>,
}
const HELPER_CMDS: [&str; 3] = ["list_chips", "list_probes", "version"];
pub fn handle_arguments() -> anyhow::Result<i32> {
let opts = Opts::parse();
let verbose = opts.verbose;
defmt_decoder::log::init_logger(verbose >= 1, opts.json, move |metadata| {
if defmt_decoder::log::is_defmt_frame(metadata) {
true } else {
match verbose {
0 => metadata.target().starts_with("probe_run") && metadata.level() <= Level::Info,
1 => metadata.target().starts_with("probe_run"),
_ => true,
}
}
});
if opts.version {
print_version();
Ok(EXIT_SUCCESS)
} else if opts.list_probes {
probe::print(&Probe::list_all());
Ok(EXIT_SUCCESS)
} else if opts.list_chips {
print_chips();
Ok(EXIT_SUCCESS)
} else if let (Some(elf), Some(chip)) = (opts.elf.as_deref(), opts.chip.as_deref()) {
crate::run_target_program(elf, chip, &opts)
} else {
unreachable!("due to `StructOpt` constraints")
}
}
fn print_chips() {
let registry = probe_rs::config::families().expect("Could not retrieve chip family registry");
for chip_family in registry {
println!("{}\n Variants:", chip_family.name);
for variant in chip_family.variants.iter() {
println!(" {}", variant.name);
}
}
}
fn print_version() {
const VERSION: &str = env!("CARGO_PKG_VERSION");
const GIT_DESCRIBE: &str = git_version!(fallback = "--", args = ["--long"]);
let hash = extract_git_hash(GIT_DESCRIBE);
println!(
"{} {}\nsupported defmt version: {}",
VERSION, hash, DEFMT_VERSION
);
}
fn extract_git_hash(git_describe: &str) -> &str {
git_describe.split('-').nth(2).unwrap()
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case::normal("v0.2.3-12-g25c50d2", "g25c50d2")]
#[case::modified("v0.2.3-12-g25c50d2-modified", "g25c50d2")]
#[case::fallback("--", "")]
fn should_extract_hash_from_description(#[case] description: &str, #[case] expected: &str) {
let hash = extract_git_hash(description);
assert_eq!(hash, expected)
}
}