mirror of
https://github.com/spacemeowx2/blflash.git
synced 2024-10-02 21:02:11 +00:00
feat: flash eflash_loader
This commit is contained in:
parent
5ddac977a9
commit
79cdf21fa9
@ -1 +1,11 @@
|
||||
pub const _EFLASH_LOADER: &'static [u8] = include_bytes!("eflash_loader_40m.bin");
|
||||
use super::Chip;
|
||||
|
||||
pub const EFLASH_LOADER: &'static [u8] = include_bytes!("eflash_loader_40m.bin");
|
||||
|
||||
pub struct Bl602;
|
||||
|
||||
impl Chip for Bl602 {
|
||||
fn get_eflash_loader(&self) -> &[u8] {
|
||||
EFLASH_LOADER
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,6 @@
|
||||
mod bl602;
|
||||
pub use bl602::Bl602;
|
||||
|
||||
pub trait Chip {
|
||||
fn get_eflash_loader(&self) -> &[u8];
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ impl Connection {
|
||||
|
||||
pub fn read_response(&mut self, len: usize) -> Result<Vec<u8>, Error> {
|
||||
let resp = self.read_exact(2)?;
|
||||
log::trace!("read_response {}", String::from_utf8_lossy(&resp).to_string());
|
||||
match &resp[0..2] {
|
||||
// OK
|
||||
[0x4f, 0x4b] => {
|
||||
@ -83,7 +82,10 @@ impl Connection {
|
||||
let code = reader.read_u16::<LittleEndian>()?;
|
||||
Err(Error::RomError(RomError::from(code)))
|
||||
},
|
||||
_ => Err(Error::RespError)
|
||||
e => {
|
||||
log::trace!("read_response err: {:x?}", e);
|
||||
Err(Error::RespError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
use crate::connection::{Connection, DEFAULT_BAUDRATE};
|
||||
use crate::Error;
|
||||
use crate::chip::{Chip, Bl602};
|
||||
use crate::image::BinReader;
|
||||
use serial::{BaudRate, SerialPort};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{time::{Duration, Instant}, io::{Cursor, Read}};
|
||||
use deku::prelude::*;
|
||||
use indicatif::{HumanBytes};
|
||||
|
||||
pub struct Flasher {
|
||||
connection: Connection,
|
||||
bootrom_info: protocol::BootInfo,
|
||||
boot_info: protocol::BootInfo,
|
||||
chip: Box<dyn Chip>,
|
||||
}
|
||||
|
||||
impl Flasher {
|
||||
@ -16,19 +20,121 @@ impl Flasher {
|
||||
) -> Result<Self, Error> {
|
||||
let mut flasher = Flasher {
|
||||
connection: Connection::new(serial),
|
||||
bootrom_info: protocol::BootInfo::default(),
|
||||
boot_info: protocol::BootInfo::default(),
|
||||
chip: Box::new(Bl602),
|
||||
};
|
||||
flasher.connection.set_baud(speed.unwrap_or(DEFAULT_BAUDRATE))?;
|
||||
flasher.start_connection()?;
|
||||
flasher.connection.set_timeout(Duration::from_secs(3))?;
|
||||
flasher.bootrom_info = flasher.get_boot_info()?;
|
||||
flasher.boot_info = flasher.get_boot_info()?;
|
||||
|
||||
Ok(flasher)
|
||||
}
|
||||
|
||||
pub fn boot_info(&self) -> &protocol::BootInfo {
|
||||
&self.boot_info
|
||||
}
|
||||
|
||||
pub fn load_elf_to_flash(&mut self, _input: &[u8]) -> Result<(), Error> {
|
||||
let loader = self.chip.get_eflash_loader().to_vec();
|
||||
self.load_bin(&loader)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_bin(&mut self, input: &[u8]) -> Result<(), Error> {
|
||||
let len = input.len();
|
||||
let mut reader = Cursor::new(input);
|
||||
self.load_boot_header(&mut reader)?;
|
||||
self.load_segment_header(&mut reader)?;
|
||||
|
||||
let start = Instant::now();
|
||||
log::info!("Sending eflash_loader...");
|
||||
loop {
|
||||
let size = self.load_segment_data(&mut reader)?;
|
||||
if size == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
let elapsed = start.elapsed();
|
||||
log::info!("Finished {:?} {}/s", elapsed, HumanBytes((len as f64 / elapsed.as_millis() as f64 * 1000.0) as u64));
|
||||
|
||||
self.check_image()?;
|
||||
self.run_image()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_image(&mut self) -> Result<(), Error> {
|
||||
self.connection.write_all(protocol::RUN_IMAGE)?;
|
||||
self.connection.flush()?;
|
||||
self.connection.read_response(0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_image(&mut self) -> Result<(), Error> {
|
||||
self.connection.write_all(protocol::CHECK_IMAGE)?;
|
||||
self.connection.flush()?;
|
||||
self.connection.read_response(0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_boot_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
|
||||
let mut boot_header = vec![0u8; protocol::LOAD_BOOT_HEADER_LEN];
|
||||
reader.read_exact(&mut boot_header)?;
|
||||
let mut req = protocol::LoadBootHeader {
|
||||
boot_header,
|
||||
..Default::default()
|
||||
};
|
||||
req.update()?;
|
||||
self.connection.write_all(&req.to_bytes()?)?;
|
||||
self.connection.flush()?;
|
||||
self.connection.read_response(0)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_segment_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
|
||||
let mut segment_header = vec![0u8; protocol::LOAD_SEGMENT_HEADER_LEN];
|
||||
reader.read_exact(&mut segment_header)?;
|
||||
let mut req = protocol::LoadSegmentHeader {
|
||||
segment_header,
|
||||
..Default::default()
|
||||
};
|
||||
req.update()?;
|
||||
self.connection.write_all(&req.to_bytes()?)?;
|
||||
self.connection.flush()?;
|
||||
let resp = self.connection.read_response(18)?;
|
||||
|
||||
if &resp[2..] != req.segment_header {
|
||||
log::warn!("Segment header not match req:{:x?} != resp:{:x?}", req.segment_header, &resp[2..])
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_segment_data(&mut self, reader: &mut impl Read) -> Result<usize, Error> {
|
||||
let mut segment_data = vec![0u8; 4000];
|
||||
let size = reader.read(&mut segment_data)?;
|
||||
if size == 0 {
|
||||
return Ok(0)
|
||||
}
|
||||
segment_data.truncate(size);
|
||||
let mut req = protocol::LoadSegmentData {
|
||||
segment_data,
|
||||
..Default::default()
|
||||
};
|
||||
req.update()?;
|
||||
self.connection.write_all(&req.to_bytes()?)?;
|
||||
self.connection.flush()?;
|
||||
self.connection.read_response(0)?;
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
|
||||
fn get_boot_info(&mut self) -> Result<protocol::BootInfo, Error> {
|
||||
self.connection.write_all(protocol::GET_BOOT_INFO)?;
|
||||
let data = self.connection.read_response(1 + 1 + 4 + 16)?;
|
||||
self.connection.flush()?;
|
||||
let data = self.connection.read_response(22)?;
|
||||
let (_, data) = protocol::BootInfo::from_bytes((&data, 0))?;
|
||||
Ok(data)
|
||||
}
|
||||
@ -74,11 +180,41 @@ mod protocol {
|
||||
use deku::prelude::*;
|
||||
|
||||
pub const GET_BOOT_INFO: &[u8] = &[0x10, 0x00, 0x00, 0x00];
|
||||
pub const CHECK_IMAGE: &[u8] = &[0x19, 0x00, 0x00, 0x00];
|
||||
pub const RUN_IMAGE: &[u8] = &[0x1a, 0x00, 0x00, 0x00];
|
||||
pub const LOAD_BOOT_HEADER_LEN: usize = 176;
|
||||
pub const LOAD_SEGMENT_HEADER_LEN: usize = 16;
|
||||
|
||||
#[derive(Debug, DekuRead, Default)]
|
||||
#[deku(magic = b"\x14\x00")]
|
||||
pub struct BootInfo {
|
||||
bootrom_version: u32,
|
||||
otp_info: [u8; 16],
|
||||
pub bootrom_version: u32,
|
||||
pub otp_info: [u8; 16],
|
||||
}
|
||||
|
||||
#[derive(Debug, DekuWrite, Default)]
|
||||
#[deku(magic = b"\x11\x00", endian = "little")]
|
||||
pub struct LoadBootHeader {
|
||||
#[deku(update = "self.boot_header.len()")]
|
||||
pub boot_header_len: u16,
|
||||
// length must be 176
|
||||
pub boot_header: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, DekuWrite, Default)]
|
||||
#[deku(magic = b"\x17\x00", endian = "little")]
|
||||
pub struct LoadSegmentHeader {
|
||||
#[deku(update = "self.segment_header.len()")]
|
||||
pub segment_header_len: u16,
|
||||
// length must be 16
|
||||
pub segment_header: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, DekuWrite, Default)]
|
||||
#[deku(magic = b"\x18\x00", endian = "little")]
|
||||
pub struct LoadSegmentData {
|
||||
#[deku(update = "self.segment_data.len()")]
|
||||
pub segment_data_len: u16,
|
||||
pub segment_data: Vec<u8>,
|
||||
}
|
||||
}
|
||||
|
16
blflash/src/image.rs
Normal file
16
blflash/src/image.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use std::io::Read;
|
||||
|
||||
pub struct BinReader<R> {
|
||||
reader: R,
|
||||
}
|
||||
|
||||
impl<R> BinReader<R>
|
||||
where
|
||||
R: Read,
|
||||
{
|
||||
pub fn new(reader: R) -> BinReader<R> {
|
||||
BinReader {
|
||||
reader,
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ mod flasher;
|
||||
mod connection;
|
||||
mod chip;
|
||||
mod error;
|
||||
mod image;
|
||||
|
||||
pub use config::Config;
|
||||
pub use flasher::Flasher;
|
||||
|
@ -38,13 +38,16 @@ fn main() -> Result<(), MainError> {
|
||||
};
|
||||
|
||||
let serial = serial::open(&serial)?;
|
||||
let _flasher = Flasher::connect(serial, Some(BaudRate::BaudOther(500_000)))?;
|
||||
let mut flasher = Flasher::connect(serial, Some(BaudRate::BaudOther(500_000)))?;
|
||||
|
||||
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
|
||||
|
||||
let input: String = match elf {
|
||||
Some(input) => input,
|
||||
_ => return help(),
|
||||
};
|
||||
let _input_bytes = read(&input)?;
|
||||
let input_bytes = read(&input)?;
|
||||
flasher.load_elf_to_flash(&input_bytes)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user