feat: implement cargo-blflash

This commit is contained in:
spacemeowx2 2021-01-02 00:23:52 +08:00
parent 23742b5c98
commit c2d38374e9
8 changed files with 597 additions and 275 deletions

214
Cargo.lock generated
View File

@ -133,9 +133,12 @@ version = "0.1.0"
dependencies = [
"blflash",
"cargo-project",
"color-eyre",
"env_logger",
"main_error",
"pico-args",
"paw",
"serial",
"structopt",
]
[[package]]
@ -153,6 +156,12 @@ dependencies = [
"toml 0.4.10",
]
[[package]]
name = "cc"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
version = "0.1.10"
@ -180,6 +189,33 @@ dependencies = [
"vec_map",
]
[[package]]
name = "color-eyre"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b29030875fd8376e4a28ef497790d5b4a7843d8d1396bf08ce46f5eec562c5c"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors",
"tracing-error",
]
[[package]]
name = "color-spantrace"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6eee477a4a8a72f4addd4de416eb56d54bc307b284d6601bafdee1f4ea462d1"
dependencies = [
"once_cell",
"owo-colors",
"tracing-core",
"tracing-error",
]
[[package]]
name = "console"
version = "0.13.0"
@ -317,6 +353,16 @@ dependencies = [
"termcolor",
]
[[package]]
name = "eyre"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f29abf4740a4778632fe27a4f681ef5b7a6f659aeba3330ac66f48e20cfa3b7"
dependencies = [
"indenter",
"once_cell",
]
[[package]]
name = "failure"
version = "0.1.8"
@ -351,6 +397,19 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ba62103ce691c2fd80fbae2213dfdda9ce60804973ac6b6e97de818ea7f52c8"
[[package]]
name = "generator"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc"
dependencies = [
"cc",
"libc",
"log",
"rustc_version",
"winapi",
]
[[package]]
name = "generic-array"
version = "0.14.4"
@ -420,6 +479,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indenter"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b772bb6a163b53b7e02b2d4735e0b399df6fc68e74374dbea85cd22a36e9db"
[[package]]
name = "indicatif"
version = "0.15.0"
@ -441,6 +506,12 @@ dependencies = [
"libc",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -462,6 +533,19 @@ dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "loom"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed"
dependencies = [
"cfg-if 0.1.10",
"generator",
"scoped-tls",
"serde",
"serde_json",
]
[[package]]
name = "main_error"
version = "0.1.1"
@ -505,12 +589,24 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
[[package]]
name = "once_cell"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "owo-colors"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13370dae44474229701bb69b90b4f4dca6404cb0357a2d50d635f1171dc3aa7b"
[[package]]
name = "parse_int"
version = "0.4.0"
@ -548,10 +644,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2"
[[package]]
name = "pico-args"
version = "0.3.4"
name = "pin-project-lite"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1"
checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c"
[[package]]
name = "proc-macro-error"
@ -650,6 +746,42 @@ version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.117"
@ -670,6 +802,17 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serial"
version = "0.4.0"
@ -725,6 +868,16 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "sharded-slab"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127"
dependencies = [
"lazy_static",
"loom",
]
[[package]]
name = "strsim"
version = "0.8.0"
@ -875,6 +1028,59 @@ dependencies = [
"serde",
]
[[package]]
name = "tracing"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
dependencies = [
"lazy_static",
]
[[package]]
name = "tracing-error"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24"
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-subscriber"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa8f0c8f4c594e4fc9debc1990deab13238077271ba84dd853d54902ee3401"
dependencies = [
"sharded-slab",
"thread_local",
"tracing-core",
]
[[package]]
name = "typenum"
version = "1.12.0"

View File

@ -24,6 +24,10 @@ impl Bl602 {
}
impl Chip for Bl602 {
fn target(&self) -> &'static str {
"riscv32imac-unknown-none-elf"
}
fn get_eflash_loader(&self) -> &[u8] {
EFLASH_LOADER
}

View File

@ -5,6 +5,7 @@ use crate::Error;
pub use bl602::Bl602;
pub trait Chip {
fn target(&self) -> &'static str;
fn get_eflash_loader(&self) -> &[u8];
fn get_flash_segment<'a>(&self, code_segment: CodeSegment<'a>) -> Option<RomSegment<'a>>;
fn with_boot2(

View File

@ -1,34 +0,0 @@
use directories_next::ProjectDirs;
use serde::Deserialize;
use std::fs::read;
#[derive(Debug, Deserialize, Default)]
pub struct Config {
#[serde(default)]
pub connection: Connection,
#[serde(default)]
pub build: Build,
}
#[derive(Debug, Deserialize, Default)]
pub struct Connection {
pub serial: Option<String>,
}
#[derive(Debug, Deserialize, Default)]
pub struct Build {
pub tool: Option<String>,
}
impl Config {
/// Load the config from config file
pub fn load() -> Self {
let dirs = ProjectDirs::from("rs", "bl", "blflash").unwrap();
let file = dirs.config_dir().join("blflash.toml");
if let Ok(data) = read(&file) {
toml::from_slice(&data).unwrap()
} else {
Self::default()
}
}
}

View File

@ -1,11 +1,240 @@
pub mod chip;
mod config;
mod connection;
pub mod elf;
mod error;
mod flasher;
pub mod image;
pub use config::Config;
pub use error::{Error, RomError};
pub use flasher::Flasher;
use crate::{
chip::{
bl602::{self, Bl602},
Chip,
},
elf::{FirmwareImage, RomSegment},
image::BootHeaderCfgFile,
};
use serial::{BaudRate, CharSize, FlowControl, Parity, SerialPort, SerialPortSettings, StopBits};
use std::{
borrow::Cow,
fs::{read, File},
path::PathBuf,
};
use structopt::StructOpt;
#[derive(StructOpt)]
pub struct Connection {
/// Serial port
#[structopt(short, long)]
pub port: String,
/// Flash baud rate
#[structopt(short, long, default_value = "1000000")]
pub baud_rate: usize,
/// Initial baud rate
#[structopt(long, default_value = "115200")]
pub initial_baud_rate: usize,
}
#[derive(StructOpt)]
pub struct Boot2Opt {
/// Path to partition_cfg.toml, default to be partition/partition_cfg_2M.toml
#[structopt(long, parse(from_os_str))]
pub partition_cfg: Option<PathBuf>,
/// Path to efuse_bootheader_cfg.conf
#[structopt(long, parse(from_os_str))]
pub boot_header_cfg: Option<PathBuf>,
/// Path to ro_params.dtb
#[structopt(long, parse(from_os_str))]
pub dtb: Option<PathBuf>,
/// Without boot2
#[structopt(short, long)]
pub without_boot2: bool,
}
#[derive(StructOpt)]
pub struct FlashOpt {
#[structopt(flatten)]
pub conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
pub image: PathBuf,
/// Don't skip if hash matches
#[structopt(short, long)]
pub force: bool,
#[structopt(flatten)]
pub boot: Boot2Opt,
}
#[derive(StructOpt)]
pub struct CheckOpt {
#[structopt(flatten)]
pub conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
pub image: PathBuf,
#[structopt(flatten)]
pub boot: Boot2Opt,
}
#[derive(StructOpt)]
pub struct DumpOpt {
#[structopt(flatten)]
pub conn: Connection,
/// Output file
#[structopt(parse(from_os_str))]
pub output: PathBuf,
/// start address
#[structopt(parse(try_from_str = parse_int::parse), default_value = "0")]
pub start: u32,
/// end address
#[structopt(parse(try_from_str = parse_int::parse), default_value = "0x100000")]
pub end: u32,
}
#[derive(StructOpt)]
pub 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 {
pub fn open_serial(&self) -> Result<impl SerialPort, Error> {
let mut serial = serial::open(&self.port)?;
serial.reconfigure(&|setup: &mut dyn SerialPortSettings| {
setup.set_char_size(CharSize::Bits8);
setup.set_stop_bits(StopBits::Stop1);
setup.set_parity(Parity::ParityNone);
setup.set_flow_control(FlowControl::FlowNone);
Ok(())
})?;
Ok(serial)
}
pub 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),
)
}
}
impl Boot2Opt {
pub fn with_boot2<'a>(
self,
chip: &'a dyn Chip,
image: &[u8],
) -> Result<Vec<RomSegment<'a>>, Error> {
let partition_cfg = self
.partition_cfg
.map(read)
.unwrap_or_else(|| Ok(bl602::DEFAULT_PARTITION_CFG.to_vec()))?;
let boot_header_cfg = self
.boot_header_cfg
.map(read)
.unwrap_or_else(|| Ok(bl602::DEFAULT_BOOTHEADER_CFG.to_vec()))?;
let partition_cfg = toml::from_slice(&partition_cfg)?;
let BootHeaderCfgFile { boot_header_cfg } = toml::from_slice(&boot_header_cfg)?;
let ro_params = self
.dtb
.map(read)
.unwrap_or_else(|| Ok(bl602::RO_PARAMS.to_vec()))?;
let segments = chip.with_boot2(partition_cfg, boot_header_cfg, ro_params, image)?;
Ok(segments)
}
pub fn make_segment<'a>(
self,
_chip: &'a dyn Chip,
image: Vec<u8>,
) -> Result<RomSegment<'a>, Error> {
let boot_header_cfg = self
.boot_header_cfg
.map(read)
.unwrap_or_else(|| Ok(bl602::DEFAULT_BOOTHEADER_CFG.to_vec()))?;
let BootHeaderCfgFile {
mut boot_header_cfg,
} = toml::from_slice(&boot_header_cfg)?;
let img = boot_header_cfg.make_image(0x2000, image)?;
Ok(RomSegment::from_vec(0x0, img))
}
pub fn get_segments<'a>(
self,
chip: &'a dyn Chip,
image: Vec<u8>,
) -> Result<Vec<RomSegment<'a>>, Error> {
Ok(if self.without_boot2 {
vec![self.make_segment(chip, Vec::from(image))?]
} else {
self.with_boot2(chip, &image)?
})
}
}
pub fn read_image<'a>(chip: &dyn Chip, image: &'a [u8]) -> Result<Cow<'a, [u8]>, Error> {
Ok(if image[0..4] == [0x7f, 0x45, 0x4c, 0x46] {
log::trace!("Detect ELF");
// ELF
let firmware_image = FirmwareImage::from_data(image).map_err(|_| Error::InvalidElf)?;
Cow::Owned(firmware_image.to_flash_bin(chip))
} else {
// bin
Cow::Borrowed(image)
})
}
pub fn flash(opt: FlashOpt) -> Result<(), Error> {
let chip = Bl602;
let image = read(&opt.image)?;
let image = read_image(&chip, &image)?;
let mut flasher = opt.conn.create_flasher(chip)?;
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
log::trace!("Boot info: {:x?}", flasher.boot_info());
let segments = opt.boot.get_segments(&chip, Vec::from(image))?;
flasher.load_segments(opt.force, segments.into_iter())?;
flasher.reset()?;
log::info!("Success");
Ok(())
}
pub fn check(opt: CheckOpt) -> Result<(), Error> {
let chip = Bl602;
let image = read(&opt.image)?;
let image = read_image(&chip, &image)?;
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 segments = opt.boot.get_segments(&chip, Vec::from(image))?;
flasher.check_segments(segments.into_iter())?;
Ok(())
}
pub fn dump(opt: DumpOpt) -> Result<(), Error> {
let mut output = File::create(opt.output)?;
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());
flasher.dump_flash(opt.start..opt.end, &mut output)?;
log::info!("Success");
Ok(())
}

View File

@ -1,243 +1,12 @@
use blflash::{
chip::{
bl602::{self, Bl602},
Chip,
},
elf::{FirmwareImage, RomSegment},
image::BootHeaderCfgFile,
Config, Error, Flasher,
};
use blflash::{check, dump, flash, Opt};
use env_logger::Env;
use main_error::MainError;
use serial::{BaudRate, CharSize, FlowControl, Parity, SerialPort, SerialPortSettings, StopBits};
use std::path::PathBuf;
use std::{
borrow::Cow,
fs::{read, File},
};
use structopt::StructOpt;
#[derive(StructOpt)]
struct Connection {
/// Serial port
#[structopt(short, long)]
port: String,
/// Flash baud rate
#[structopt(short, long, default_value = "1000000")]
baud_rate: usize,
/// Initial baud rate
#[structopt(long, default_value = "115200")]
initial_baud_rate: usize,
}
#[derive(StructOpt)]
struct Boot2Opt {
/// Path to partition_cfg.toml, default to be partition/partition_cfg_2M.toml
#[structopt(long, parse(from_os_str))]
partition_cfg: Option<PathBuf>,
/// Path to efuse_bootheader_cfg.conf
#[structopt(long, parse(from_os_str))]
boot_header_cfg: Option<PathBuf>,
/// Path to ro_params.dtb
#[structopt(long, parse(from_os_str))]
dtb: Option<PathBuf>,
/// Without boot2
#[structopt(short, long)]
without_boot2: bool,
}
#[derive(StructOpt)]
struct FlashOpt {
#[structopt(flatten)]
conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
image: PathBuf,
/// Don't skip if hash matches
#[structopt(short, long)]
force: bool,
#[structopt(flatten)]
boot: Boot2Opt,
}
#[derive(StructOpt)]
struct CheckOpt {
#[structopt(flatten)]
conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
image: PathBuf,
#[structopt(flatten)]
boot: Boot2Opt,
}
#[derive(StructOpt)]
struct DumpOpt {
#[structopt(flatten)]
conn: Connection,
/// Output file
#[structopt(parse(from_os_str))]
output: PathBuf,
/// start address
#[structopt(parse(try_from_str = parse_int::parse), default_value = "0")]
start: u32,
/// end address
#[structopt(parse(try_from_str = parse_int::parse), default_value = "0x100000")]
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 mut serial = serial::open(&self.port)?;
serial.reconfigure(&|setup: &mut dyn SerialPortSettings| {
setup.set_char_size(CharSize::Bits8);
setup.set_stop_bits(StopBits::Stop1);
setup.set_parity(Parity::ParityNone);
setup.set_flow_control(FlowControl::FlowNone);
Ok(())
})?;
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),
)
}
}
impl Boot2Opt {
fn with_boot2<'a>(
self,
chip: &'a dyn Chip,
image: &[u8],
) -> Result<Vec<RomSegment<'a>>, Error> {
let partition_cfg = self
.partition_cfg
.map(read)
.unwrap_or_else(|| Ok(bl602::DEFAULT_PARTITION_CFG.to_vec()))?;
let boot_header_cfg = self
.boot_header_cfg
.map(read)
.unwrap_or_else(|| Ok(bl602::DEFAULT_BOOTHEADER_CFG.to_vec()))?;
let partition_cfg = toml::from_slice(&partition_cfg)?;
let BootHeaderCfgFile { boot_header_cfg } = toml::from_slice(&boot_header_cfg)?;
let ro_params = self
.dtb
.map(read)
.unwrap_or_else(|| Ok(bl602::RO_PARAMS.to_vec()))?;
let segments = chip.with_boot2(partition_cfg, boot_header_cfg, ro_params, image)?;
Ok(segments)
}
fn make_segment<'a>(
self,
_chip: &'a dyn Chip,
image: Vec<u8>,
) -> Result<RomSegment<'a>, Error> {
let boot_header_cfg = self
.boot_header_cfg
.map(read)
.unwrap_or_else(|| Ok(bl602::DEFAULT_BOOTHEADER_CFG.to_vec()))?;
let BootHeaderCfgFile {
mut boot_header_cfg,
} = toml::from_slice(&boot_header_cfg)?;
let img = boot_header_cfg.make_image(0x2000, image)?;
Ok(RomSegment::from_vec(0x0, img))
}
fn get_segments<'a>(
self,
chip: &'a dyn Chip,
image: Vec<u8>,
) -> Result<Vec<RomSegment<'a>>, Error> {
Ok(if self.without_boot2 {
vec![self.make_segment(chip, Vec::from(image))?]
} else {
self.with_boot2(chip, &image)?
})
}
}
fn read_image<'a>(chip: &dyn Chip, image: &'a [u8]) -> Result<Cow<'a, [u8]>, Error> {
Ok(if image[0..4] == [0x7f, 0x45, 0x4c, 0x46] {
log::trace!("Detect ELF");
// ELF
let firmware_image = FirmwareImage::from_data(image).map_err(|_| Error::InvalidElf)?;
Cow::Owned(firmware_image.to_flash_bin(chip))
} else {
// bin
Cow::Borrowed(image)
})
}
fn flash(opt: FlashOpt) -> Result<(), Error> {
let chip = Bl602;
let image = read(&opt.image)?;
let image = read_image(&chip, &image)?;
let mut flasher = opt.conn.create_flasher(chip)?;
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
log::trace!("Boot info: {:x?}", flasher.boot_info());
let segments = opt.boot.get_segments(&chip, Vec::from(image))?;
flasher.load_segments(opt.force, segments.into_iter())?;
flasher.reset()?;
log::info!("Success");
Ok(())
}
fn check(opt: CheckOpt) -> Result<(), Error> {
let chip = Bl602;
let image = read(&opt.image)?;
let image = read_image(&chip, &image)?;
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 segments = opt.boot.get_segments(&chip, Vec::from(image))?;
flasher.check_segments(segments.into_iter())?;
Ok(())
}
fn dump(opt: DumpOpt) -> Result<(), Error> {
let mut output = File::create(opt.output)?;
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());
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"))
.format_timestamp(None)
.init();
let _config = Config::load();
match args {
Opt::Flash(opt) => flash(opt)?,

View File

@ -12,5 +12,8 @@ repository = "https://github.com/spacemeowx2/blflash"
cargo-project = "0.2.4"
blflash = { version = "*", path = "../blflash" }
main_error = "0.1.1"
pico-args = "0.3.4"
serial = "0.4"
color-eyre = "0.5.10"
structopt = "0.3.21"
paw = "1.0.0"
env_logger = "0.8.2"

View File

@ -1,3 +1,147 @@
fn main() {
println!("Hello, world!");
use std::path::PathBuf;
use std::process::{exit, Command, ExitStatus, Stdio};
use blflash::{
chip::{Bl602, Chip},
flash, Boot2Opt, Connection, FlashOpt,
};
use cargo_project::{Artifact, Profile, Project};
use color_eyre::{Report, Result};
use env_logger::Env;
use structopt::StructOpt;
#[derive(StructOpt)]
struct BlflashOpt {
#[structopt(flatten)]
conn: Connection,
/// Don't skip if hash matches
#[structopt(short, long)]
force: bool,
#[structopt(flatten)]
boot: Boot2Opt,
#[structopt(long)]
release: bool,
#[structopt(long)]
example: Option<String>,
#[structopt(long)]
features: Option<String>,
}
#[derive(StructOpt)]
enum Opt {
Blflash(BlflashOpt),
}
fn blflash_main(args: BlflashOpt) -> Result<()> {
let chip = Bl602;
let target = chip.target();
let status = build(args.release, &args.example, &args.features, target);
if !status.success() {
exit_with_process_status(status)
}
let path = get_artifact_path(target, args.release, &args.example)
.expect("Could not find the build artifact path");
let flash_opt = FlashOpt {
conn: args.conn,
image: path,
force: args.force,
boot: args.boot,
};
flash(flash_opt)?;
Ok(())
}
#[paw::main]
fn main(args: Opt) -> Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("blflash=trace"))
.format_timestamp(None)
.init();
match args {
Opt::Blflash(opt) => blflash_main(opt),
}
}
fn get_artifact_path(target: &str, release: bool, example: &Option<String>) -> Result<PathBuf> {
let project = Project::query(".").unwrap();
let artifact = match example {
Some(example) => Artifact::Example(example.as_str()),
None => Artifact::Bin(project.name()),
};
let profile = if release {
Profile::Release
} else {
Profile::Dev
};
let host = "x86_64-unknown-linux-gnu";
project
.path(artifact, profile, Some(target), host)
.map_err(Report::msg)
}
fn build(
release: bool,
example: &Option<String>,
features: &Option<String>,
target: &str,
) -> ExitStatus {
let mut args: Vec<String> = vec![];
if release {
args.push("--release".to_string());
}
match example {
Some(example) => {
args.push("--example".to_string());
args.push(example.to_string());
}
None => {}
}
match features {
Some(features) => {
args.push("--features".to_string());
args.push(features.to_string());
}
None => {}
}
let mut command = Command::new("cargo");
args.push("--target".to_string());
args.push(target.to_string());
command
.arg("build")
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.unwrap()
.wait()
.unwrap()
}
#[cfg(unix)]
fn exit_with_process_status(status: ExitStatus) -> ! {
use std::os::unix::process::ExitStatusExt;
let code = status.code().or_else(|| status.signal()).unwrap_or(1);
exit(code)
}
#[cfg(not(unix))]
fn exit_with_process_status(status: ExitStatus) -> ! {
let code = status.code().unwrap_or(1);
exit(code)
}