quick_flash/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use anyhow::{self, Context};
use etcetera::{self, AppStrategy, AppStrategyArgs};
use probe_rs::{
    flashing::{download_file_with_options, DownloadOptions, FlashProgress, Format, ProgressEvent},
    probe::{list::Lister, DebugProbeInfo, Probe},
    Permissions,
};
use std::{fs, path::PathBuf};
use storage::Firmware;

pub mod credentials;
pub mod credentials_manager;
pub mod storage;
mod utils;

pub struct BaseDirs {
    pub creds_dir: PathBuf,
    pub firmware_cache_dir: PathBuf,
}

impl BaseDirs {
    pub fn new() -> anyhow::Result<Self> {
        let strategy = etcetera::choose_app_strategy(AppStrategyArgs {
            top_level_domain: "cz".to_string(),
            author: "manakjiri".to_string(),
            app_name: "quick-flash".to_string(),
        })
        .context("Failed to resolve application directories")?;

        let creds_dir = strategy.config_dir().join("credentials");
        let firmware_cache_dir = strategy.cache_dir().join("firmware");

        fs::create_dir_all(&creds_dir).context("Failed to create config directory")?;
        fs::create_dir_all(&firmware_cache_dir)
            .context("Failed to create firmware cache directory")?;

        Ok(BaseDirs {
            creds_dir,
            firmware_cache_dir,
        })
    }

    pub fn clear_firmware_cache(&self) -> anyhow::Result<()> {
        fs::remove_dir_all(&self.firmware_cache_dir).context("Failed to clear cache directory")?;
        fs::create_dir_all(&self.firmware_cache_dir)
            .context("Failed to create firmware cache directory")?;
        Ok(())
    }
}

pub fn get_probes() -> anyhow::Result<Vec<DebugProbeInfo>> {
    let lister = Lister::new();
    let probes = lister.list_all();
    if probes.is_empty() {
        anyhow::bail!("No debug probes found")
    }
    Ok(probes)
}

pub fn flash_firmware(
    probe: Probe,
    firmware: Firmware,
    connect_under_reset: bool,
    progress_callback: &'static dyn Fn(String),
) -> anyhow::Result<()> {
    // Attach to a chip.
    progress_callback("Attaching to target...".to_string());
    let mut session = match connect_under_reset {
        true => probe.attach_under_reset(&firmware.chip, Permissions::default()),
        false => probe.attach(&firmware.chip, Permissions::default()),
    }
    .context("Failed to attach probe")?;

    // Download the firmware binary.
    progress_callback(format!(
        "Downloading {}/{} to target chip {}...",
        firmware.name, firmware.version, firmware.chip
    ));
    let mut options = DownloadOptions::default();
    options.progress = Some(FlashProgress::new(|e| match e {
        ProgressEvent::StartedErasing => progress_callback("Flash erasing...".to_string()),
        ProgressEvent::FinishedErasing => progress_callback("Flash programming...".to_string()),
        _ => {}
    }));
    options.verify = true;
    options.do_chip_erase = true;
    download_file_with_options(&mut session, firmware.path, Format::Elf, options)
        .context("Failed to flash firmware")?;

    progress_callback("Resetting target...".to_string());
    session.core(0)?.reset()?;

    Ok(())
}