Initial commit

This commit is contained in:
2025-09-18 13:17:47 +02:00
commit 8f6b7fbc1f
9 changed files with 1063 additions and 0 deletions

225
src/main.rs Normal file
View 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());
}