You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cargo-dfu/src/utils.rs

87 lines
2.6 KiB

use goblin::elf::program_header::PT_LOAD;
use rusb::GlobalContext;
use std::path::PathBuf;
use std::{fs::File, io::Read};
#[derive(Debug)]
pub enum UtilError {
Elf(goblin::error::Error),
Dfu(dfu_libusb::Error),
File(std::io::Error),
}
/// Returns a contiguous bin with 0s between non-contiguous sections and starting address from an elf.
pub fn elf_to_bin(path: PathBuf) -> Result<(Vec<u8>, u32), UtilError> {
let mut file = File::open(path).map_err(|e| UtilError::File(e))?;
let mut buffer = vec![];
file.read_to_end(&mut buffer)
.map_err(|e| UtilError::File(e))?;
let binary = goblin::elf::Elf::parse(buffer.as_slice()).map_err(|e| UtilError::Elf(e))?;
let mut start_address: u64 = 0;
let mut last_address: u64 = 0;
let mut data = vec![];
for (i, ph) in binary
.program_headers
.iter()
.filter(|ph| {
ph.p_type == PT_LOAD
&& ph.p_filesz > 0
&& ph.p_offset >= binary.header.e_ehsize as u64
&& ph.is_read()
})
.enumerate()
{
// first time through grab the starting physical address
if i == 0 {
start_address = ph.p_paddr;
}
// on subsequent passes, if there's a gap between this section and the
// previous one, fill it with zeros
else {
let difference = (ph.p_paddr - last_address) as usize;
data.resize(data.len() + difference, 0x0);
}
data.extend_from_slice(&buffer[ph.p_offset as usize..][..ph.p_filesz as usize]);
last_address = ph.p_paddr + ph.p_filesz;
}
Ok((data, start_address as u32))
}
pub fn flash_bin(binary: &[u8], d: &rusb::Device<GlobalContext>) -> Result<(), UtilError> {
let mut dfu = dfu_libusb::DfuLibusb::open(
&rusb::Context::new().unwrap(),
d.device_descriptor().unwrap().vendor_id(),
d.device_descriptor().unwrap().product_id(),
0,
0,
)
.map_err(|e| UtilError::Dfu(e))?;
std::fs::write("target/out.bin", binary).map_err(|e| UtilError::File(e))?;
dfu.download(
&mut std::fs::OpenOptions::new()
.read(true)
.open("target/out.bin")
.map_err(|e| UtilError::File(e))?,
std::fs::metadata("target/out.bin")
.map_err(|e| UtilError::File(e))?
.len() as u32,
)
.unwrap();
Ok(())
}
pub fn vendor_map() -> std::collections::HashMap<String, Vec<(u16, u16)>> {
maplit::hashmap! {
"stm32".to_string() => vec![(0x0483, 0xdf11)],
"gd32vf103".to_string() => vec![(0x28e9, 0x0189)],
}
}