-
Notifications
You must be signed in to change notification settings - Fork 238
/
Copy pathmod.rs
131 lines (112 loc) · 4.41 KB
/
mod.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use anyhow::Context as _;
use std::path;
use std::process;
#[derive(Debug)]
pub struct AvrdudeOptions<'a> {
pub programmer: &'a str,
pub partno: &'a str,
pub baudrate: Option<u32>,
pub do_chip_erase: bool,
}
#[derive(Debug)]
pub struct Avrdude {
#[allow(dead_code)]
config: tempfile::NamedTempFile,
process: process::Child,
}
impl Avrdude {
fn get_avrdude_version() -> anyhow::Result<(u8, u8)> {
let output = process::Command::new("avrdude").arg("-?").output()?;
let stderr: &str = std::str::from_utf8(&output.stderr)?;
let err = || anyhow::anyhow!("failed to derive version number from avrdude");
let version: &str = stderr.split("version").last().ok_or_else(err)?.trim();
let version: String = version
.chars()
.take_while(|c| c.is_ascii_digit() || *c == '.')
.collect();
let mut version_splits = version.split('.');
let major = version_splits.next().ok_or_else(err)?.parse::<u8>()?;
let minor = version_splits.next().ok_or_else(err)?.parse::<u8>()?;
Ok((major, minor))
}
pub fn require_min_ver((req_major, req_minor): (u8, u8)) -> anyhow::Result<()> {
let (major, minor) =
Self::get_avrdude_version().context("Failed reading avrdude version information.")?;
if (major, minor) < (req_major, req_minor) {
anyhow::bail!(
"Avrdude does not meet minimum version requirements. v{}.{} was found while v{}.{} or greater is required.\n\
You may find a more suitable version here: https://download.savannah.gnu.org/releases/avrdude/",
major, minor,
req_major, req_minor,
);
}
Ok(())
}
pub fn run(
options: &AvrdudeOptions,
do_eeprom: bool,
port: Option<impl AsRef<path::Path>>,
bin: &path::Path,
) -> anyhow::Result<Self> {
let config = tempfile::Builder::new()
.prefix(".avrdude-")
.suffix(".conf")
.tempfile()
.unwrap();
{
use std::io::Write;
let mut f = std::fs::File::create(&config).context("could not create avrdude.conf")?;
f.write_all(include_bytes!("avrdude.conf"))
.context("could not write avrdude.conf")?;
f.flush().unwrap();
}
let mut command = process::Command::new("avrdude");
let mut command = command
.arg("-C")
.arg(&config.as_ref())
.arg("-c")
.arg(options.programmer)
.arg("-p")
.arg(options.partno);
if let Some(port) = port {
command = command.arg("-P").arg(port.as_ref());
}
if let Some(baudrate) = options.baudrate {
command = command.arg("-b").arg(baudrate.to_string());
}
// TODO: Check that `bin` does not contain :
let mut flash_instruction: std::ffi::OsString = "flash:w:".into();
flash_instruction.push(bin);
flash_instruction.push(":e");
if options.do_chip_erase {
command = command.arg("-e");
}
command = command.arg("-D").arg("-U").arg(flash_instruction);
// Check whether we should program the EEPROM. The command can be
// appended to the command-line, but avrdude will return with a
// nonzero error code if the ELF file didn't have an `.eeprom` section.
// So we conditionally add it.
if do_eeprom {
let fp = std::fs::File::open(bin).context("could not read ELF file")?;
let mut elf = elf::ElfStream::<elf::endian::LittleEndian, _>::open_stream(fp).context("parsing ELF file failed")?;
if elf.section_header_by_name(".eeprom")
.context("error parsing ELF section headers")?
.is_some()
{
let mut eeprom_instruction: std::ffi::OsString = "eeprom:w:".into();
eeprom_instruction.push(bin);
eeprom_instruction.push(":e");
command = command.arg("-U").arg(eeprom_instruction);
}
}
let process = command.spawn().context("failed starting avrdude")?;
Ok(Self { config, process })
}
pub fn wait(&mut self) -> anyhow::Result<()> {
let ret = self.process.wait()?;
if !ret.success() {
anyhow::bail!("avrdude failed");
}
Ok(())
}
}