feat: add dump command and baudrate settings

This commit is contained in:
spacemeowx2 2020-12-05 18:40:40 +08:00
parent b56d4215f4
commit 3dc63d2114
3 changed files with 164 additions and 35 deletions

View File

@ -1,5 +1,5 @@
use crate::{Error, RomError};
use byteorder::{LittleEndian, ReadBytesExt};
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use std::io::{Cursor, Read, Write};
use std::thread::sleep;
use std::time::Duration;
@ -10,17 +10,21 @@ pub const DEFAULT_BAUDRATE: BaudRate = BaudRate::Baud115200;
pub struct Connection {
serial: Box<dyn SerialPort>,
baud_rate: BaudRate,
baud_rate: Option<BaudRate>,
}
impl Connection {
pub fn new(serial: impl SerialPort + 'static) -> Self {
Connection {
serial: Box::new(serial),
baud_rate: DEFAULT_BAUDRATE,
baud_rate: None,
}
}
pub fn into_inner(self) -> Box<dyn SerialPort> {
self.serial
}
pub fn reset(&mut self) -> Result<(), Error> {
self.serial.set_rts(false)?;
sleep(Duration::from_millis(50));
@ -51,7 +55,7 @@ impl Connection {
}
pub fn set_baud(&mut self, speed: BaudRate) -> Result<(), Error> {
self.baud_rate = speed;
self.baud_rate = Some(speed);
self.serial
.reconfigure(&|setup: &mut dyn SerialPortSettings| setup.set_baud_rate(speed))?;
Ok(())
@ -75,6 +79,11 @@ impl Connection {
Ok(buf)
}
pub fn read_response_with_payload(&mut self) -> Result<Vec<u8>, Error> {
let len = LittleEndian::read_u16(&self.read_response(2)?);
self.read_exact(len as usize)
}
pub fn read_response(&mut self, len: usize) -> Result<Vec<u8>, Error> {
let resp = self.read_exact(2)?;
match &resp[0..2] {
@ -101,7 +110,8 @@ impl Connection {
}
pub fn calc_duration_length(&mut self, duration: Duration) -> usize {
self.baud_rate.speed() / 10 / 1000 * (duration.as_millis() as usize)
self.baud_rate.unwrap_or(DEFAULT_BAUDRATE).speed() / 10 / 1000
* (duration.as_millis() as usize)
}
pub fn write_all(&mut self, buf: &[u8]) -> Result<(), Error> {

View File

@ -1,40 +1,48 @@
use crate::chip::Chip;
use crate::elf::FirmwareImage;
use crate::Error;
use crate::{
connection::{Connection, DEFAULT_BAUDRATE},
elf::RomSegment,
};
use crate::{connection::Connection, elf::RomSegment};
use deku::prelude::*;
use indicatif::HumanBytes;
use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
use serial::{BaudRate, SerialPort};
use sha2::{Digest, Sha256};
use std::thread::sleep;
use std::{
io::{Cursor, Read},
io::{Cursor, Read, Write},
time::{Duration, Instant},
};
use std::{ops::Range, thread::sleep};
fn get_bar(len: u64) -> ProgressBar {
let bar = ProgressBar::new(len);
bar.set_style(
ProgressStyle::default_bar()
.template(" {wide_bar} {bytes}/{total_bytes} {bytes_per_sec} {eta} ")
.progress_chars("#>-"),
);
bar
}
pub struct Flasher {
connection: Connection,
boot_info: protocol::BootInfo,
chip: Box<dyn Chip>,
flash_speed: BaudRate,
}
impl Flasher {
pub fn connect(
chip: impl Chip + 'static,
serial: impl SerialPort + 'static,
speed: Option<BaudRate>,
initial_speed: BaudRate,
flash_speed: BaudRate,
) -> Result<Self, Error> {
let mut flasher = Flasher {
connection: Connection::new(serial),
boot_info: protocol::BootInfo::default(),
chip: Box::new(chip),
flash_speed,
};
flasher
.connection
.set_baud(speed.unwrap_or(DEFAULT_BAUDRATE))?;
flasher.connection.set_baud(initial_speed)?;
flasher.start_connection()?;
flasher.connection.set_timeout(Duration::from_secs(10))?;
flasher.boot_info = flasher.get_boot_info()?;
@ -42,6 +50,10 @@ impl Flasher {
Ok(flasher)
}
pub fn into_inner(self) -> Connection {
self.connection
}
pub fn boot_info(&self) -> &protocol::BootInfo {
&self.boot_info
}
@ -52,8 +64,6 @@ impl Flasher {
segments: impl Iterator<Item = RomSegment<'a>>,
) -> Result<(), Error> {
self.load_eflash_loader()?;
self.connection.set_baud(BaudRate::BaudOther(2_000_000))?;
self.handshake()?;
for segment in segments {
let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]);
@ -83,14 +93,17 @@ impl Flasher {
let start = Instant::now();
log::info!("Program flash... {:x}", local_hash);
let pb = get_bar(segment.size() as u64);
loop {
let size = self.flash_program(cur, &mut reader)?;
// log::trace!("program {:x} {:x}", cur, size);
cur += size;
pb.inc(size as u64);
if size == 0 {
break;
}
}
pb.finish_and_clear();
let elapsed = start.elapsed();
log::info!(
"Program done {:?} {}/s",
@ -111,8 +124,6 @@ impl Flasher {
segments: impl Iterator<Item = RomSegment<'a>>,
) -> Result<(), Error> {
self.load_eflash_loader()?;
self.connection.set_baud(BaudRate::BaudOther(2_000_000))?;
self.handshake()?;
for segment in segments {
let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]);
@ -154,6 +165,23 @@ impl Flasher {
Ok(())
}
pub fn dump_flash(&mut self, range: Range<u32>, mut writer: impl Write) -> Result<(), Error> {
self.load_eflash_loader()?;
const BLOCK_SIZE: usize = 4096;
let mut cur = range.start;
let pb = get_bar(range.len() as u64);
while cur < range.end {
let data = self.flash_read(cur, (range.end - cur).min(BLOCK_SIZE as u32))?;
writer.write_all(&data)?;
cur += data.len() as u32;
pb.inc(data.len() as u64);
}
pb.finish_and_clear();
Ok(())
}
pub fn load_eflash_loader(&mut self) -> Result<(), Error> {
let input = self.chip.get_eflash_loader().to_vec();
let len = input.len();
@ -163,12 +191,15 @@ impl Flasher {
let start = Instant::now();
log::info!("Sending eflash_loader...");
let pb = get_bar(len as u64);
loop {
let size = self.load_segment_data(&mut reader)?;
pb.inc(size as u64);
if size == 0 {
break;
}
}
pb.finish_and_clear();
let elapsed = start.elapsed();
log::info!(
"Finished {:?} {}/s",
@ -179,6 +210,9 @@ impl Flasher {
self.check_image()?;
self.run_image()?;
sleep(Duration::from_millis(200));
// TODO configurable
self.connection.set_baud(self.flash_speed)?;
self.handshake()?;
Ok(())
}
@ -199,6 +233,16 @@ impl Flasher {
Ok(data.digest)
}
fn flash_read(&mut self, addr: u32, size: u32) -> Result<Vec<u8>, Error> {
let mut req = protocol::FlashRead { addr, size };
req.update()?;
self.connection.write_all(&req.to_bytes()?)?;
self.connection.flush()?;
let data = self.connection.read_response_with_payload()?;
Ok(data)
}
fn flash_program(&mut self, addr: u32, reader: &mut impl Read) -> Result<u32, Error> {
let mut data = vec![0u8; 4000];
let size = reader.read(&mut data)?;
@ -407,6 +451,21 @@ mod protocol {
}
}
#[derive(Debug, DekuWrite, Default)]
#[deku(magic = b"\x32\x00\x08\x00", endian = "little")]
pub struct FlashRead {
pub addr: u32,
pub size: u32,
}
#[derive(Debug, DekuRead)]
#[deku(magic = b"\x32\x00\x08\x00", endian = "little")]
pub struct FlashReadResp {
pub len: u16,
#[deku(count = "len")]
pub data: Vec<u8>,
}
#[derive(Debug, DekuWrite, Default)]
#[deku(magic = b"\x3d\x00\x08\x00", endian = "little")]
pub struct Sha256Read {

View File

@ -1,21 +1,35 @@
use std::fs::read;
use blflash::{
chip::bl602::{self, Bl602},
chip::{
bl602::{self, Bl602},
Chip,
},
image::BootHeaderCfgFile,
Config, Error, Flasher,
};
use env_logger::Env;
use main_error::MainError;
use serial::BaudRate;
use serial::{BaudRate, SerialPort};
use std::fs::{read, File};
use std::path::PathBuf;
use structopt::StructOpt;
#[derive(StructOpt)]
struct FlashOpt {
struct Connection {
/// Serial port
#[structopt(short, long)]
port: String,
/// Flash baud rate
#[structopt(short, long, default_value = "115200")]
baud_rate: usize,
/// Initial baud rate
#[structopt(long, default_value = "115200")]
initial_baud_rate: usize,
}
#[derive(StructOpt)]
struct FlashOpt {
#[structopt(flatten)]
conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
image: PathBuf,
@ -35,25 +49,57 @@ struct FlashOpt {
#[derive(StructOpt)]
struct CheckOpt {
/// Serial port
#[structopt(short, long)]
port: String,
#[structopt(flatten)]
conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
image: PathBuf,
}
#[derive(StructOpt)]
struct DumpOpt {
#[structopt(flatten)]
conn: Connection,
/// Output file
#[structopt(parse(from_os_str))]
output: PathBuf,
/// start address
#[structopt(default_value = "0")]
start: u32,
/// end address
#[structopt(default_value = "1048576")]
end: u32,
}
#[derive(StructOpt)]
enum Opt {
/// Flash image to serial
Flash(FlashOpt),
/// Check if the device's flash matches the image
Check(CheckOpt),
/// Dump the whole flash to a file
Dump(DumpOpt),
}
impl Connection {
fn open_serial(&self) -> Result<impl SerialPort, Error> {
let serial = serial::open(&self.port)?;
Ok(serial)
}
fn create_flasher(&self, chip: impl Chip + 'static) -> Result<Flasher, Error> {
let serial = self.open_serial()?;
Flasher::connect(
chip,
serial,
BaudRate::from_speed(self.initial_baud_rate),
BaudRate::from_speed(self.baud_rate),
)
}
}
fn flash(opt: FlashOpt) -> Result<(), Error> {
let serial = serial::open(&opt.port)?;
let chip = Bl602;
let mut flasher = opt.conn.create_flasher(chip)?;
if !opt.without_boot2 {
let partition_cfg = opt
@ -69,7 +115,6 @@ fn flash(opt: FlashOpt) -> Result<(), Error> {
let bin = read(&opt.image)?;
let segments = chip.with_boot2(partition_cfg, boot_header_cfg, &bin)?;
let mut flasher = Flasher::connect(chip, serial, Some(BaudRate::Baud115200))?;
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
log::trace!("Boot info: {:x?}", flasher.boot_info());
@ -78,8 +123,6 @@ fn flash(opt: FlashOpt) -> Result<(), Error> {
flasher.reset()?;
} else {
let mut flasher = Flasher::connect(chip, serial, Some(BaudRate::Baud115200))?;
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
log::trace!("Boot info: {:x?}", flasher.boot_info());
@ -90,12 +133,12 @@ fn flash(opt: FlashOpt) -> Result<(), Error> {
}
log::info!("Success");
Ok(())
}
fn check(opt: CheckOpt) -> Result<(), Error> {
let serial = serial::open(&opt.port)?;
let mut flasher = Flasher::connect(Bl602, serial, Some(BaudRate::Baud115200))?;
let mut flasher = opt.conn.create_flasher(Bl602)?;
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
log::trace!("Boot info: {:x?}", flasher.boot_info());
@ -106,14 +149,31 @@ fn check(opt: CheckOpt) -> Result<(), Error> {
Ok(())
}
fn dump(opt: DumpOpt) -> Result<(), Error> {
let mut flasher = opt.conn.create_flasher(Bl602)?;
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
log::trace!("Boot info: {:x?}", flasher.boot_info());
let mut output = File::create(opt.output)?;
flasher.dump_flash(opt.start..opt.end, &mut output)?;
log::info!("Success");
Ok(())
}
#[paw::main]
fn main(args: Opt) -> Result<(), MainError> {
env_logger::Builder::from_env(Env::default().default_filter_or("blflash=trace")).init();
env_logger::Builder::from_env(Env::default().default_filter_or("blflash=trace"))
.format_timestamp(None)
.init();
let _config = Config::load();
match args {
Opt::Flash(opt) => flash(opt)?,
Opt::Check(opt) => check(opt)?,
Opt::Dump(opt) => dump(opt)?,
};
Ok(())