Initial commit
This commit is contained in:
225
src/main.rs
Normal file
225
src/main.rs
Normal file
@@ -0,0 +1,225 @@
|
||||
use std::{io::{Cursor, Error, Write}, time::{Duration, SystemTime}};
|
||||
|
||||
use pbr::ProgressBar;
|
||||
|
||||
mod args;
|
||||
use args::*;
|
||||
|
||||
mod ihex;
|
||||
use ihex::{IntelHexWriter, IntelHexReader, DataRecord};
|
||||
|
||||
mod target;
|
||||
use target::{PhysicalTarget, Target};
|
||||
|
||||
mod utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn read_chip_into(writer: &mut impl Write, target: &mut impl Target, start: usize, end: usize) -> Result<(), Error> {
|
||||
let mut pb = ProgressBar::new((end - start) as u64 + 1);
|
||||
pb.message("reading chip flash ");
|
||||
pb.set_units(pbr::Units::Bytes);
|
||||
|
||||
let mut last = start;
|
||||
|
||||
for i in (start..=end).step_by(1024).chain(std::iter::once(end + 1)) {
|
||||
if i == last { continue }
|
||||
|
||||
let size = i - last;
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
target.read_flash(last as u16, &mut buf[..size])?;
|
||||
writer.write_all(&buf[..size])?;
|
||||
|
||||
pb.add(size as u64);
|
||||
|
||||
last = i;
|
||||
}
|
||||
|
||||
pb.finish_println("");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_chip(args: ArgRead, target: &mut impl Target) -> Result<(), Error> {
|
||||
let mut file = std::fs::File::create(args.path)?;
|
||||
|
||||
match args.bin {
|
||||
true => read_chip_into(&mut file, target, args.start, args.end)?,
|
||||
false => {
|
||||
let mut writer = IntelHexWriter::init(file, args.start as u16);
|
||||
|
||||
read_chip_into(&mut writer, target, args.start, args.end)?;
|
||||
|
||||
writer.finish()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_chip_chunk(data: &[u8], target: &mut impl Target, mut start: usize, verify: bool) -> Result<(), Error> {
|
||||
let mut head = Vec::new();
|
||||
|
||||
if start & 0x7F != 0 {
|
||||
head.resize(start & 0x7F, 0);
|
||||
|
||||
let mut pb = ProgressBar::new(head.len() as u64);
|
||||
pb.message("reading chip flash ");
|
||||
pb.set_units(pbr::Units::Bytes);
|
||||
|
||||
target.read_flash(start as u16 & !0x7F, &mut head)?;
|
||||
|
||||
pb.add(head.len() as u64);
|
||||
pb.finish_println("");
|
||||
}
|
||||
|
||||
let mut tail = Vec::new();
|
||||
|
||||
let end = start + data.len();
|
||||
|
||||
if end & 0x7F != 0 {
|
||||
tail.resize(128 - (end & 0x7F), 0);
|
||||
|
||||
let mut pb = ProgressBar::new(tail.len() as u64);
|
||||
pb.message("reading chip flash ");
|
||||
pb.set_units(pbr::Units::Bytes);
|
||||
|
||||
target.read_flash(end as u16, &mut tail)?;
|
||||
|
||||
pb.add(tail.len() as u64);
|
||||
pb.finish_println("");
|
||||
}
|
||||
|
||||
let data = [ &head, data, &tail ].concat();
|
||||
assert_eq!(data.len() & 0x7F, 0);
|
||||
|
||||
start = start & !0x7F;
|
||||
|
||||
if start + data.len() > 0x10000 {
|
||||
Err(Error::other("Data does not fit into memory"))?
|
||||
}
|
||||
|
||||
let mut page = start / 128;
|
||||
|
||||
let mut pb = ProgressBar::new(data.len() as u64);
|
||||
pb.message("writing chip flash ");
|
||||
pb.set_units(pbr::Units::Bytes);
|
||||
|
||||
for chunk in data.as_chunks::<128>().0.iter() {
|
||||
target.write_flash(page as u16, chunk)?;
|
||||
|
||||
pb.add(chunk.len() as u64);
|
||||
page += 1;
|
||||
}
|
||||
|
||||
pb.finish_println("");
|
||||
|
||||
if verify {
|
||||
let mut verify: Cursor<Vec<u8>> = Cursor::new(Vec::new());
|
||||
read_chip_into(&mut verify, target, start, start + data.len() - 1)?;
|
||||
|
||||
if verify.get_ref() != &data {
|
||||
Err(Error::other("Write mismatch"))?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_chip(args: ArgWrite, target: &mut impl Target) -> Result<(), Error> {
|
||||
if args.bin {
|
||||
let mut file = std::fs::read(args.path)?;
|
||||
|
||||
let size = args.end - args.start + 1;
|
||||
|
||||
if size < file.len() {
|
||||
file.resize(size, 0);
|
||||
}
|
||||
|
||||
return write_chip_chunk(&file, target, args.start, !args.skip_verify)
|
||||
}
|
||||
|
||||
let hexreader = IntelHexReader::init(std::fs::File::open(args.path)?);
|
||||
|
||||
if args.write_individual {
|
||||
let mut last_addr = 0;
|
||||
let mut next_expected_addr = 0;
|
||||
let mut last_data = Vec::new();
|
||||
|
||||
for record in hexreader {
|
||||
let DataRecord { addr, mut data } = record?;
|
||||
|
||||
if addr != next_expected_addr {
|
||||
if !last_data.is_empty() {
|
||||
write_chip_chunk(&last_data, target, last_addr, !args.skip_verify)?;
|
||||
last_data.clear();
|
||||
}
|
||||
|
||||
last_addr = addr;
|
||||
next_expected_addr = addr;
|
||||
}
|
||||
|
||||
next_expected_addr += data.len();
|
||||
last_data.append(&mut data);
|
||||
}
|
||||
|
||||
if !last_data.is_empty() {
|
||||
write_chip_chunk(&last_data, target, last_addr, !args.skip_verify)?;
|
||||
}
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let mut first_addr = 0xFFFF;
|
||||
let mut last_addr = 0;
|
||||
|
||||
let mut buf = vec![0u8; 0x10000];
|
||||
|
||||
for record in hexreader {
|
||||
let DataRecord { addr, data } = record?;
|
||||
|
||||
if addr < first_addr {
|
||||
first_addr = addr;
|
||||
}
|
||||
|
||||
if data.len() + addr - 1 > last_addr {
|
||||
last_addr = addr + data.len() - 1;
|
||||
}
|
||||
|
||||
buf[addr..addr + data.len()].copy_from_slice(&data);
|
||||
}
|
||||
|
||||
write_chip_chunk(&buf[first_addr..=last_addr], target, first_addr, !args.skip_verify)
|
||||
}
|
||||
|
||||
pub fn erase_chip(_args: ArgErase, target: &mut impl Target) -> Result<(), Error> {
|
||||
target.erase()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = args::parse();
|
||||
|
||||
let start = SystemTime::now();
|
||||
|
||||
let mut target = PhysicalTarget::init(args.port, if args.slow { 57600 } else { 312500 }).unwrap();
|
||||
|
||||
let res = match args.command {
|
||||
ArgCommand::Read(args) => read_chip(args, &mut target),
|
||||
ArgCommand::Write(args) => write_chip(args, &mut target),
|
||||
ArgCommand::Erase(args) => erase_chip(args, &mut target)
|
||||
};
|
||||
|
||||
if let Err(err) = res {
|
||||
println!("An error occured during the operation: {}", err);
|
||||
}
|
||||
|
||||
let end = SystemTime::now();
|
||||
let dur = end.duration_since(start).unwrap_or(Duration::ZERO);
|
||||
|
||||
println!("Finished operation in {} ms.", dur.as_millis());
|
||||
}
|
||||
|
Reference in New Issue
Block a user