1use anyhow::{self, Context};
2use etcetera::{self, AppStrategy, AppStrategyArgs};
3use probe_rs::{
4 flashing::{download_file_with_options, DownloadOptions, FlashProgress, Format, ProgressEvent},
5 probe::{list::Lister, DebugProbeInfo, Probe},
6 Permissions,
7};
8use std::{fs, path::PathBuf};
9use storage::Firmware;
10
11pub mod credentials;
12pub mod credentials_manager;
13pub mod storage;
14mod utils;
15
16pub struct BaseDirs {
17 pub creds_dir: PathBuf,
18 pub firmware_cache_dir: PathBuf,
19}
20
21impl BaseDirs {
22 pub fn new() -> anyhow::Result<Self> {
23 let strategy = etcetera::choose_app_strategy(AppStrategyArgs {
24 top_level_domain: "cz".to_string(),
25 author: "manakjiri".to_string(),
26 app_name: "quick-flash".to_string(),
27 })
28 .context("Failed to resolve application directories")?;
29
30 let creds_dir = strategy.config_dir().join("credentials");
31 let firmware_cache_dir = strategy.cache_dir().join("firmware");
32
33 fs::create_dir_all(&creds_dir).context("Failed to create config directory")?;
34 fs::create_dir_all(&firmware_cache_dir)
35 .context("Failed to create firmware cache directory")?;
36
37 Ok(BaseDirs {
38 creds_dir,
39 firmware_cache_dir,
40 })
41 }
42
43 pub fn clear_firmware_cache(&self) -> anyhow::Result<()> {
44 fs::remove_dir_all(&self.firmware_cache_dir).context("Failed to clear cache directory")?;
45 fs::create_dir_all(&self.firmware_cache_dir)
46 .context("Failed to create firmware cache directory")?;
47 Ok(())
48 }
49}
50
51pub fn get_probes() -> anyhow::Result<Vec<DebugProbeInfo>> {
52 let lister = Lister::new();
53 let probes = lister.list_all();
54 if probes.is_empty() {
55 anyhow::bail!("No debug probes found")
56 }
57 Ok(probes)
58}
59
60pub fn flash_firmware(
61 probe: Probe,
62 firmware: Firmware,
63 connect_under_reset: bool,
64 progress_callback: &'static dyn Fn(String),
65) -> anyhow::Result<()> {
66 progress_callback("Attaching to target...".to_string());
68 let mut session = match connect_under_reset {
69 true => probe.attach_under_reset(&firmware.chip, Permissions::default()),
70 false => probe.attach(&firmware.chip, Permissions::default()),
71 }
72 .context("Failed to attach probe")?;
73
74 progress_callback(format!(
76 "Downloading {}/{} to target chip {}...",
77 firmware.name, firmware.version, firmware.chip
78 ));
79 let mut options = DownloadOptions::default();
80 options.progress = Some(FlashProgress::new(|e| match e {
81 ProgressEvent::StartedErasing => progress_callback("Flash erasing...".to_string()),
82 ProgressEvent::FinishedErasing => progress_callback("Flash programming...".to_string()),
83 _ => {}
84 }));
85 options.verify = true;
86 options.do_chip_erase = true;
87 download_file_with_options(&mut session, firmware.path, Format::Elf, options)
88 .context("Failed to flash firmware")?;
89
90 progress_callback("Resetting target...".to_string());
91 session.core(0)?.reset()?;
92
93 Ok(())
94}