├── .gitignore ├── docs └── blash.gif ├── bin └── eflash_loader_40m.bin ├── src ├── blflash │ ├── chip │ │ ├── bl602 │ │ │ ├── cfg │ │ │ │ ├── ro_params.dtb │ │ │ │ ├── partition_cfg_2M.toml │ │ │ │ └── efuse_bootheader_cfg.conf │ │ │ ├── image │ │ │ │ ├── blsp_boot2.bin │ │ │ │ └── eflash_loader_40m.bin │ │ │ └── mod.rs │ │ └── mod.rs │ ├── image │ │ ├── mod.rs │ │ ├── partition.rs │ │ └── bootheader.rs │ ├── error.rs │ ├── elf.rs │ ├── mod.rs │ ├── connection.rs │ └── flasher.rs └── main.rs ├── Cargo.toml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /docs/blash.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/blash/main/docs/blash.gif -------------------------------------------------------------------------------- /bin/eflash_loader_40m.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/blash/main/bin/eflash_loader_40m.bin -------------------------------------------------------------------------------- /src/blflash/chip/bl602/cfg/ro_params.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/blash/main/src/blflash/chip/bl602/cfg/ro_params.dtb -------------------------------------------------------------------------------- /src/blflash/chip/bl602/image/blsp_boot2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/blash/main/src/blflash/chip/bl602/image/blsp_boot2.bin -------------------------------------------------------------------------------- /src/blflash/chip/bl602/image/eflash_loader_40m.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/blash/main/src/blflash/chip/bl602/image/eflash_loader_40m.bin -------------------------------------------------------------------------------- /src/blflash/image/mod.rs: -------------------------------------------------------------------------------- 1 | mod bootheader; 2 | mod partition; 3 | 4 | pub use bootheader::{BootHeaderCfg, BootHeaderCfgFile}; 5 | pub use partition::PartitionCfg; 6 | -------------------------------------------------------------------------------- /src/blflash/chip/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bl602; 2 | pub use crate::blflash::elf::{CodeSegment, FirmwareImage, RomSegment}; 3 | use crate::blflash::image::{BootHeaderCfg, PartitionCfg}; 4 | use crate::blflash::Error; 5 | pub use bl602::Bl602; 6 | 7 | pub trait Chip { 8 | fn target(&self) -> &'static str; 9 | fn get_eflash_loader(&self) -> &[u8]; 10 | fn get_flash_segment<'a>(&self, code_segment: CodeSegment<'a>) -> Option>; 11 | fn with_boot2( 12 | &self, 13 | partition_cfg: PartitionCfg, 14 | bootheader_cfg: BootHeaderCfg, 15 | ro_params: Vec, 16 | bin: &[u8], 17 | ) -> Result, Error>; 18 | } 19 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blash" 3 | version = "0.1.2" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | probe-rs = { git = "https://github.com/probe-rs/probe-rs/", package="probe-rs", features = ["ftdi"], rev="9100410735b27b4050c744445e8b347c2a894ab1" } 8 | xmas-elf = "0.8.0" 9 | main_error = "0.1.1" 10 | serde = { version = "1.0", features = ["derive"] } 11 | toml = "0.5" 12 | thiserror = "1.0.22" 13 | indicatif = "0.16.0" 14 | log = "0.4.11" 15 | env_logger = "0.9.0" 16 | byteorder = "1.3.4" 17 | sha2 = "0.9.2" 18 | structopt = { version = "0.3.21", features = ["paw"] } 19 | paw = "1.0.0" 20 | crc = "2.0.0" 21 | hex = "0.4.2" 22 | parse_int = "0.6.0" 23 | funty="=1.2.0" 24 | bitvec = "0.22.3" 25 | deku = "0.12.3" 26 | clap = "2.33.3" 27 | ctrlc = "3.1.9" 28 | serialport = "4.0.1" 29 | -------------------------------------------------------------------------------- /src/blflash/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | #[non_exhaustive] 5 | pub enum Error { 6 | #[error("IO error while using serial port: {0}")] 7 | Serial(#[from] serialport::Error), 8 | #[error("IO error: {0}")] 9 | IO(#[from] std::io::Error), 10 | #[error("Failed to connect to the device")] 11 | ConnectionFailed, 12 | #[error("Timeout while running command")] 13 | Timeout, 14 | #[error("Invalid response header")] 15 | RespError, 16 | #[error("Packet to large for buffer")] 17 | OverSizedPacket, 18 | #[error("elf image is not valid")] 19 | InvalidElf, 20 | #[error("elf image can not be ran from ram")] 21 | ElfNotRamLoadable, 22 | #[error("chip not recognized")] 23 | UnrecognizedChip, 24 | #[error("flash chip not supported, flash id: {0:#x}")] 25 | UnsupportedFlash(u8), 26 | #[error("ROM error {0:?}")] 27 | RomError(RomError), 28 | #[error("Parse error")] 29 | ParseError(#[from] deku::error::DekuError), 30 | #[error("Parse toml error")] 31 | TomlError(#[from] toml::de::Error), 32 | } 33 | 34 | #[derive(Copy, Clone, Debug)] 35 | #[allow(dead_code)] 36 | pub enum RomError { 37 | Success, 38 | Other(u16), 39 | } 40 | 41 | impl From for RomError { 42 | fn from(raw: u16) -> Self { 43 | match raw { 44 | 0x00 => RomError::Success, 45 | _ => RomError::Other(raw), 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BLASH - Zero Touch BL602 Flasher 2 | 3 | A tool to flash BL602 via JTAG + serial without pressing buttons / setting jumpers. 4 | 5 | Additionally it provides a simple serial monitor to show serial output from your application. 6 | 7 | ![alt text](docs/blash.gif "Recording") 8 | 9 | ## How it works 10 | 11 | It downloads the eflasher binary to RAM via JTAG. Then it starts the elfasher and transfers the binary 12 | you want to flash via serial. 13 | 14 | The serial flashing is done by code from @Spacemeowx2's wonderful BLFLASH. Basically everything in the `blflash` module is copied from https://github.com/spacemeowx2/blflash 15 | 16 | Unfortunately I had to copy the code since BLFLASH and probe-rs use clashing dependencies. 17 | 18 | ## Command Line 19 | 20 | ``` 21 | USAGE: 22 | blash.exe [FLAGS] [OPTIONS] [--] 23 | 24 | FLAGS: 25 | -h, --help Prints help information 26 | --no-monitor 27 | -V, --version Prints version information 28 | 29 | OPTIONS: 30 | --baud [default: 2000000] 31 | --monitor-baud [default: 115200] 32 | --port 33 | 34 | ARGS: 35 | 36 | ``` 37 | 38 | This way you can just use it in `.cargo/config` like this: 39 | ``` 40 | ... 41 | runner = "blash --" 42 | ... 43 | ``` 44 | 45 | The _port_ argument is optional if only one serial port is found. Otherwise it's mandatory. 46 | 47 | ## Installation 48 | 49 | For now clone this repository and run: 50 | 51 | ``` 52 | cargo install --path . 53 | ``` 54 | 55 | ## Good to Know 56 | 57 | This is hopefully just a temporary solution and we get https://github.com/9names/bl602-loader working someday. 58 | 59 | If something is not working or can get improved create an issue or send an PR. 60 | 61 | I only tested this on Windows with an Sipeed JTAG adapter. 62 | 63 | If you get an error regarding communicating to the debug probe - just try again. Hope to get this fixed. 64 | -------------------------------------------------------------------------------- /src/blflash/chip/bl602/cfg/partition_cfg_2M.toml: -------------------------------------------------------------------------------- 1 | [pt_table] 2 | #partition table is 4K in size 3 | address0 = 0xE000 4 | address1 = 0xF000 5 | 6 | [[pt_entry]] 7 | type = 0 8 | name = "FW" 9 | device = 0 10 | address0 = 0x10000 11 | size0 = 0xC8000 12 | address1 = 0xD8000 13 | size1 = 0x88000 14 | # compressed image must set len,normal image can left it to 0 15 | len = 0 16 | 17 | [[pt_entry]] 18 | type = 2 19 | name = "mfg" 20 | device = 0 21 | address0 = 0x160000 22 | size0 = 0x32000 23 | address1 = 0 24 | size1 = 0 25 | # compressed image must set len,normal image can left it to 0 26 | len = 0 27 | 28 | [[pt_entry]] 29 | type = 3 30 | name = "media" 31 | device = 0 32 | address0 = 0x192000 33 | size0 = 0x57000 34 | address1 = 0 35 | size1 = 0 36 | # compressed image must set len,normal image can left it to 0 37 | len = 0 38 | 39 | [[pt_entry]] 40 | type = 4 41 | name = "PSM" 42 | device = 0 43 | address0 = 0x1E9000 44 | size0 = 0x8000 45 | address1 = 0 46 | size1 = 0 47 | # compressed image must set len,normal image can left it to 0 48 | len = 0 49 | 50 | [[pt_entry]] 51 | type = 5 52 | name = "KEY" 53 | device = 0 54 | address0 = 0x1F1000 55 | size0 = 0x2000 56 | address1 = 0 57 | size1 = 0 58 | # compressed image must set len,normal image can left it to 0 59 | len = 0 60 | 61 | [[pt_entry]] 62 | type = 6 63 | name = "DATA" 64 | device = 0 65 | address0 = 0x1F3000 66 | size0 = 0x5000 67 | address1 = 0 68 | size1 = 0 69 | # compressed image must set len,normal image can left it to 0 70 | len = 0 71 | 72 | 73 | [[pt_entry]] 74 | type = 7 75 | name = "factory" 76 | device = 0 77 | address0 = 0x1F8000 78 | size0 = 0x7000 79 | address1 = 0 80 | size1 = 0 81 | # compressed image must set len,normal image can left it to 0 82 | len = 0 83 | 84 | #if user want to put RF calibration data on flash, uncomment following pt entry 85 | #[[pt_entry]] 86 | #type = 8 87 | #name = "rf_para" 88 | #device = 0 89 | #address0 = 0x1FF000 90 | #size0 = 0x1000 91 | #address1 = 0 92 | #size1 = 0 93 | ## compressed image must set len,normal image can left it to 0 94 | #len = 0 95 | -------------------------------------------------------------------------------- /src/blflash/image/partition.rs: -------------------------------------------------------------------------------- 1 | use deku::prelude::*; 2 | use deku::DekuWrite; 3 | use serde::Deserialize; 4 | use std::io::Write; 5 | use std::iter; 6 | 7 | #[derive(Debug, Deserialize, DekuWrite, Default)] 8 | #[deku(magic = b"\x42\x46\x50\x54\x00\x00")] 9 | pub struct PartitionCfg { 10 | #[serde(skip)] 11 | #[deku(update = "self.pt_entry.len()")] 12 | pub entry_len: u32, 13 | #[serde(skip)] 14 | #[deku(update = "0")] 15 | _unused1: u16, 16 | #[serde(skip)] 17 | #[deku(update = "self.header_checksum()")] 18 | pub checksum: u32, 19 | #[deku(skip)] 20 | pub pt_table: Table, 21 | pub pt_entry: Vec, 22 | #[serde(skip)] 23 | #[deku(update = "self.checksum()")] 24 | pub file_checksum: u32, 25 | } 26 | 27 | #[derive(Debug, Deserialize, DekuWrite, Default)] 28 | pub struct Table { 29 | pub address0: u32, 30 | pub address1: u32, 31 | } 32 | 33 | #[derive(Debug, Deserialize, DekuWrite, Default)] 34 | pub struct Entry { 35 | #[deku(bytes = "3")] 36 | pub r#type: u32, 37 | #[deku(writer = "Entry::write_name(name, deku::output)")] 38 | pub name: String, 39 | pub address0: u32, 40 | pub address1: u32, 41 | pub size0: u32, 42 | pub size1: u32, 43 | pub len: u32, 44 | #[serde(skip)] 45 | pub _unused1: u32, 46 | } 47 | 48 | impl PartitionCfg { 49 | fn header_checksum(&self) -> u32 { 50 | let data = self.to_bytes().unwrap(); 51 | crc::Crc::::new(&crc::CRC_32_ISO_HDLC).checksum(&data[0..12]) 52 | } 53 | fn checksum(&self) -> u32 { 54 | let data = self.to_bytes().unwrap(); 55 | crc::Crc::::new(&crc::CRC_32_ISO_HDLC) 56 | .checksum(&data[16..16 + 36 * self.pt_entry.len()]) 57 | } 58 | } 59 | 60 | impl Entry { 61 | fn write_name( 62 | name: &str, 63 | output: &mut bitvec::prelude::BitVec, 64 | ) -> Result<(), DekuError> { 65 | if name.len() > 8 { 66 | return Err(DekuError::Unexpected("name too long".to_string())); 67 | } 68 | let bytes = name 69 | .bytes() 70 | .chain(iter::repeat(0)) 71 | .take(8 + 1) // last is null? 72 | .collect::>(); 73 | output.write_all(&bytes).unwrap(); 74 | Ok(()) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/blflash/chip/bl602/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::blflash::elf::CodeSegment; 2 | use crate::blflash::elf::RomSegment; 3 | use crate::blflash::image::{BootHeaderCfg, PartitionCfg}; 4 | use crate::blflash::Error; 5 | use deku::prelude::*; 6 | 7 | pub const DEFAULT_PARTITION_CFG: &'static [u8] = include_bytes!("cfg/partition_cfg_2M.toml"); 8 | pub const DEFAULT_BOOTHEADER_CFG: &'static [u8] = include_bytes!("cfg/efuse_bootheader_cfg.conf"); 9 | pub const RO_PARAMS: &'static [u8] = include_bytes!("cfg/ro_params.dtb"); 10 | pub const BLSP_BOOT2: &'static [u8] = include_bytes!("image/blsp_boot2.bin"); 11 | pub const EFLASH_LOADER: &'static [u8] = include_bytes!("image/eflash_loader_40m.bin"); 12 | const ROM_START: u32 = 0x23000000; 13 | // 16MB 14 | const ROM_END: u32 = 0x23000000 + 0x1000000; 15 | 16 | #[derive(Copy, Clone)] 17 | pub struct Bl602; 18 | 19 | impl Bl602 { 20 | fn addr_is_flash(&self, addr: u32) -> bool { 21 | addr >= ROM_START && addr < ROM_END 22 | } 23 | } 24 | 25 | impl crate::blflash::Chip for Bl602 { 26 | fn target(&self) -> &'static str { 27 | "riscv32imac-unknown-none-elf" 28 | } 29 | 30 | fn get_eflash_loader(&self) -> &[u8] { 31 | EFLASH_LOADER 32 | } 33 | 34 | fn get_flash_segment<'a>(&self, code_segment: CodeSegment<'a>) -> Option> { 35 | if self.addr_is_flash(code_segment.addr) { 36 | Some(RomSegment::from_code_segment( 37 | code_segment.addr - ROM_START, 38 | code_segment, 39 | )) 40 | } else { 41 | None 42 | } 43 | } 44 | 45 | fn with_boot2( 46 | &self, 47 | mut partition_cfg: PartitionCfg, 48 | mut bootheader_cfg: BootHeaderCfg, 49 | ro_params: Vec, 50 | bin: &[u8], 51 | ) -> Result, Error> { 52 | partition_cfg.update()?; 53 | let partition_cfg = partition_cfg.to_bytes()?; 54 | 55 | let boot2image = bootheader_cfg.make_image(0x2000, Vec::from(BLSP_BOOT2))?; 56 | let fw_image = bootheader_cfg.make_image(0x1000, Vec::from(bin))?; 57 | 58 | let segments = vec![ 59 | RomSegment::from_vec(0x0, boot2image), 60 | RomSegment::from_vec(0xe000, partition_cfg.clone()), 61 | RomSegment::from_vec(0xf000, partition_cfg), 62 | RomSegment::from_vec(0x10000, fw_image), 63 | // TODO: generate from dts 64 | RomSegment::from_vec(0x1f8000, ro_params), 65 | ]; 66 | 67 | Ok(segments) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/blflash/elf.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::cmp::Ordering; 3 | 4 | use xmas_elf::program::{SegmentData, Type}; 5 | use xmas_elf::ElfFile; 6 | 7 | use crate::blflash::chip::Chip; 8 | 9 | pub struct FirmwareImage<'a> { 10 | pub entry: u32, 11 | pub elf: ElfFile<'a>, 12 | } 13 | 14 | impl<'a> FirmwareImage<'a> { 15 | pub fn from_data(data: &'a [u8]) -> Result { 16 | Ok(Self::from_elf(ElfFile::new(data)?)) 17 | } 18 | 19 | pub fn from_elf(elf: ElfFile<'a>) -> Self { 20 | FirmwareImage { 21 | entry: elf.header.pt2.entry_point() as u32, 22 | elf, 23 | } 24 | } 25 | 26 | pub fn segments(&'a self) -> impl Iterator> + 'a { 27 | self.elf 28 | .program_iter() 29 | .filter(|header| { 30 | header.file_size() > 0 && header.get_type() == Ok(Type::Load) && header.offset() > 0 31 | }) 32 | .flat_map(move |header| { 33 | let addr = header.physical_addr() as u32; 34 | let size = header.file_size() as u32; 35 | let data = match header.get_data(&self.elf) { 36 | Ok(SegmentData::Undefined(data)) => data, 37 | _ => return None, 38 | }; 39 | Some(CodeSegment { addr, data, size }) 40 | }) 41 | } 42 | pub fn to_flash_bin(&self, chip: &dyn Chip) -> Vec { 43 | let segs = self 44 | .segments() 45 | .filter_map(|segment| chip.get_flash_segment(segment)) 46 | .collect::>(); 47 | let size = segs 48 | .iter() 49 | .fold(0, |len, i| len.max(i.addr + i.data.len() as u32)); 50 | 51 | let mut bin = Vec::new(); 52 | bin.resize(size as usize, 0xFF); 53 | for s in segs { 54 | bin[s.addr as usize..s.addr as usize + s.data.len()].copy_from_slice(&s.data); 55 | } 56 | bin 57 | } 58 | } 59 | 60 | #[derive(Debug, Ord, Eq)] 61 | /// A segment of code from the source elf 62 | pub struct CodeSegment<'a> { 63 | pub addr: u32, 64 | pub size: u32, 65 | pub data: &'a [u8], 66 | } 67 | 68 | impl<'a> AsRef<[u8]> for CodeSegment<'a> { 69 | fn as_ref(&self) -> &[u8] { 70 | self.data 71 | } 72 | } 73 | 74 | impl PartialEq for CodeSegment<'_> { 75 | fn eq(&self, other: &Self) -> bool { 76 | self.addr.eq(&other.addr) 77 | } 78 | } 79 | 80 | impl PartialOrd for CodeSegment<'_> { 81 | fn partial_cmp(&self, other: &Self) -> Option { 82 | self.addr.partial_cmp(&other.addr) 83 | } 84 | } 85 | 86 | /// A segment of data to write to the flash 87 | pub struct RomSegment<'a> { 88 | pub addr: u32, 89 | pub data: Cow<'a, [u8]>, 90 | } 91 | 92 | impl<'a> RomSegment<'a> { 93 | pub fn size(&self) -> u32 { 94 | self.data.len() as u32 95 | } 96 | pub fn from_vec(addr: u32, data: Vec) -> Self { 97 | RomSegment { 98 | addr, 99 | data: Cow::Owned(data), 100 | } 101 | } 102 | pub fn from_code_segment(addr: u32, code_segment: CodeSegment<'a>) -> RomSegment<'a> { 103 | Self { 104 | addr, 105 | data: Cow::Borrowed(code_segment.data), 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/blflash/chip/bl602/cfg/efuse_bootheader_cfg.conf: -------------------------------------------------------------------------------- 1 | [EFUSE_CFG] 2 | ######################################################################## 3 | #2bits 4 | ef_sf_aes_mode = 0 5 | #2bits 6 | ef_sboot_sign_mode = 0 7 | #2bits 8 | ef_sboot_en = 0 9 | #2bits 10 | ef_dbg_jtag_dis = 0 11 | #4bits 12 | ef_dbg_mode = 0 13 | #32bits 14 | ef_dbg_pwd_low = 0 15 | #32bits 16 | ef_dbg_pwd_high = 0 17 | ################################################################### 18 | ef_key_slot_2_w0 = 0 19 | ef_key_slot_2_w1 = 0 20 | ef_key_slot_2_w2 = 0 21 | ef_key_slot_2_w3 = 0 22 | ef_key_slot_3_w0 = 0 23 | ef_key_slot_3_w1 = 0 24 | ef_key_slot_3_w2 = 0 25 | ef_key_slot_3_w3 = 0 26 | ef_key_slot_4_w0 = 0 27 | ef_key_slot_4_w1 = 0 28 | ef_key_slot_4_w2 = 0 29 | ef_key_slot_4_w3 = 0 30 | 31 | wr_lock_key_slot_4_l = 0 32 | wr_lock_dbg_pwd = 0 33 | wr_lock_key_slot_2 = 0 34 | wr_lock_key_slot_3 = 0 35 | wr_lock_key_slot_4_h = 0 36 | rd_lock_dbg_pwd = 0 37 | rd_lock_key_slot_2 = 0 38 | rd_lock_key_slot_3 = 0 39 | rd_lock_key_slot_4 = 0 40 | 41 | [BOOTHEADER_CFG] 42 | magic_code = 0x504e4642 43 | revision = 0x01 44 | #########################flash cfg############################# 45 | flashcfg_magic_code = 0x47464346 46 | #flashcfg_magic_code=0 47 | io_mode = 4 48 | cont_read_support = 1 49 | #0.5T sfctrl_clk_delay=0 sfctrl_clk_invert=3 50 | #1 T sfctrl_clk_delay=1 sfctrl_clk_invert=1 51 | #1.5T sfctrl_clk_delay=1 sfctrl_clk_invert=3 52 | sfctrl_clk_delay = 1 53 | sfctrl_clk_invert = 0x01 54 | 55 | reset_en_cmd = 0x66 56 | reset_cmd = 0x99 57 | exit_contread_cmd = 0xff 58 | exit_contread_cmd_size = 3 59 | 60 | jedecid_cmd = 0x9f 61 | jedecid_cmd_dmy_clk = 0 62 | qpi_jedecid_cmd = 0x9f 63 | qpi_jedecid_dmy_clk = 0 64 | 65 | sector_size = 4 66 | mfg_id = 0xef 67 | page_size = 256 68 | 69 | chip_erase_cmd = 0xc7 70 | sector_erase_cmd = 0x20 71 | blk32k_erase_cmd = 0x52 72 | blk64k_erase_cmd = 0xd8 73 | 74 | write_enable_cmd = 0x06 75 | page_prog_cmd = 0x02 76 | qpage_prog_cmd = 0x32 77 | qual_page_prog_addr_mode = 0 78 | 79 | fast_read_cmd = 0x0b 80 | fast_read_dmy_clk = 1 81 | qpi_fast_read_cmd = 0x0b 82 | qpi_fast_read_dmy_clk = 1 83 | 84 | fast_read_do_cmd = 0x3b 85 | fast_read_do_dmy_clk = 1 86 | fast_read_dio_cmd = 0xbb 87 | fast_read_dio_dmy_clk = 0 88 | 89 | fast_read_qo_cmd = 0x6b 90 | fast_read_qo_dmy_clk = 1 91 | fast_read_qio_cmd = 0xeb 92 | fast_read_qio_dmy_clk = 2 93 | 94 | qpi_fast_read_qio_cmd = 0xeb 95 | qpi_fast_read_qio_dmy_clk = 2 96 | qpi_page_prog_cmd = 0x02 97 | write_vreg_enable_cmd = 0x50 98 | 99 | wel_reg_index = 0 100 | qe_reg_index = 1 101 | busy_reg_index = 0 102 | wel_bit_pos = 1 103 | 104 | qe_bit_pos = 1 105 | busy_bit_pos = 0 106 | wel_reg_write_len = 2 107 | wel_reg_read_len = 1 108 | 109 | qe_reg_write_len = 1 110 | qe_reg_read_len = 1 111 | release_power_down = 0xab 112 | busy_reg_read_len = 1 113 | 114 | reg_read_cmd0 = 0x05 115 | reg_read_cmd1 = 0x35 116 | 117 | reg_write_cmd0 = 0x01 118 | reg_write_cmd1 = 0x31 119 | 120 | enter_qpi_cmd = 0x38 121 | exit_qpi_cmd = 0xff 122 | cont_read_code = 0x20 123 | cont_read_exit_code = 0xff 124 | 125 | burst_wrap_cmd = 0x77 126 | burst_wrap_dmy_clk = 0x03 127 | burst_wrap_data_mode = 2 128 | burst_wrap_code = 0x40 129 | 130 | de_burst_wrap_cmd = 0x77 131 | de_burst_wrap_cmd_dmy_clk = 0x03 132 | de_burst_wrap_code_mode = 2 133 | de_burst_wrap_code = 0xF0 134 | 135 | sector_erase_time = 300 136 | blk32k_erase_time = 1200 137 | 138 | blk64k_erase_time = 1200 139 | page_prog_time = 5 140 | 141 | chip_erase_time = 20000 142 | power_down_delay = 3 143 | qe_data = 0 144 | 145 | flashcfg_crc32 = 0 146 | 147 | #########################clk cfg#################################### 148 | clkcfg_magic_code = 0x47464350 149 | #clkcfg_magic_code=0 150 | 151 | #0:Not use XTAL to set PLL,1:XTAL is 24M ,2:XTAL is 32M ,3:XTAL is 38.4M 152 | #4:XTAL is 40M,5:XTAL is 26M,6:XTAL is RC32M 153 | xtal_type = 4 154 | #0:RC32M,1:XTAL,2:PLL 48M,3:PLL 120M,4:PLL 160M,5:PLL 192M 155 | pll_clk = 4 156 | hclk_div = 0 157 | bclk_div = 1 158 | #0:120M,1:XCLK(RC32M or XTAL),2:48M,3:80M,4:BCLK,5:96M 159 | flash_clk_type = 3 160 | flash_clk_div = 1 161 | clkcfg_crc32 = 0 162 | 163 | ########################boot cfg#################################### 164 | #1:ECC 165 | sign = 0 166 | #1:AES128,2:AES256,3:AES192 167 | encrypt_type = 0 168 | key_sel = 0 169 | no_segment = 1 170 | cache_enable = 1 171 | notload_in_bootrom = 0 172 | aes_region_lock = 0 173 | cache_way_disable = 0x03 174 | crc_ignore = 0 175 | hash_ignore = 0 176 | 177 | ########################image cfg#################################### 178 | #total image len or segment count 179 | img_len = 0x100 180 | bootentry = 0 181 | #img RAM address or flash offset 182 | img_start = 0x2000 183 | 184 | #img hash 185 | hash_0 = 0xdeadbeef 186 | hash_1 = 0 187 | hash_2 = 0 188 | hash_3 = 0 189 | hash_4 = 0 190 | hash_5 = 0 191 | hash_6 = 0 192 | hash_7 = 0 193 | 194 | crc32 = 0xdeadbeef 195 | -------------------------------------------------------------------------------- /src/blflash/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod chip; 2 | mod connection; 3 | pub mod elf; 4 | mod error; 5 | mod flasher; 6 | pub mod image; 7 | 8 | pub use crate::blflash::error::{Error, RomError}; 9 | pub use flasher::Flasher; 10 | use serialport::SerialPort; 11 | 12 | use crate::blflash::{ 13 | chip::{ 14 | bl602::{self, Bl602}, 15 | Chip, 16 | }, 17 | elf::{FirmwareImage, RomSegment}, 18 | image::BootHeaderCfgFile, 19 | }; 20 | use std::{borrow::Cow, fs::read, path::PathBuf}; 21 | use structopt::StructOpt; 22 | 23 | #[derive(StructOpt)] 24 | pub struct Connection { 25 | /// Serial port 26 | #[structopt(short, long)] 27 | pub port: String, 28 | /// Baud rate 29 | #[structopt(long, default_value = "115200")] 30 | pub baud_rate: u32, 31 | } 32 | 33 | #[derive(StructOpt)] 34 | pub struct Boot2Opt { 35 | /// Path to partition_cfg.toml, default to be partition/partition_cfg_2M.toml 36 | #[structopt(long, parse(from_os_str))] 37 | pub partition_cfg: Option, 38 | /// Path to efuse_bootheader_cfg.conf 39 | #[structopt(long, parse(from_os_str))] 40 | pub boot_header_cfg: Option, 41 | /// Path to ro_params.dtb 42 | #[structopt(long, parse(from_os_str))] 43 | pub dtb: Option, 44 | /// Without boot2 45 | #[structopt(short, long)] 46 | pub without_boot2: bool, 47 | } 48 | 49 | #[derive(StructOpt)] 50 | pub struct FlashOpt { 51 | #[structopt(flatten)] 52 | pub conn: Connection, 53 | /// Bin file 54 | #[structopt(parse(from_os_str))] 55 | pub image: PathBuf, 56 | /// Don't skip if hash matches 57 | #[structopt(short, long)] 58 | pub force: bool, 59 | #[structopt(flatten)] 60 | pub boot: Boot2Opt, 61 | } 62 | 63 | #[derive(StructOpt)] 64 | pub struct CheckOpt { 65 | #[structopt(flatten)] 66 | pub conn: Connection, 67 | /// Bin file 68 | #[structopt(parse(from_os_str))] 69 | pub image: PathBuf, 70 | #[structopt(flatten)] 71 | pub boot: Boot2Opt, 72 | } 73 | 74 | #[derive(StructOpt)] 75 | pub struct DumpOpt { 76 | #[structopt(flatten)] 77 | pub conn: Connection, 78 | /// Output file 79 | #[structopt(parse(from_os_str))] 80 | pub output: PathBuf, 81 | /// start address 82 | #[structopt(parse(try_from_str = parse_int::parse), default_value = "0")] 83 | pub start: u32, 84 | /// end address 85 | #[structopt(parse(try_from_str = parse_int::parse), default_value = "0x100000")] 86 | pub end: u32, 87 | } 88 | 89 | #[derive(StructOpt)] 90 | pub enum Opt { 91 | /// Flash image to serial 92 | Flash(FlashOpt), 93 | /// Check if the device's flash matches the image 94 | Check(CheckOpt), 95 | /// Dump the whole flash to a file 96 | Dump(DumpOpt), 97 | } 98 | 99 | impl Connection { 100 | pub fn open_serial(&self) -> Result, Error> { 101 | let port = serialport::new(&self.port, self.baud_rate) 102 | .data_bits(serialport::DataBits::Eight) 103 | .parity(serialport::Parity::None) 104 | .stop_bits(serialport::StopBits::One) 105 | .flow_control(serialport::FlowControl::None) 106 | .open()?; 107 | 108 | Ok(port) 109 | } 110 | pub fn create_flasher(&self) -> Result { 111 | let serial = self.open_serial()?; 112 | crate::blflash::Flasher::connect(serial, self.baud_rate) 113 | } 114 | } 115 | 116 | impl Boot2Opt { 117 | pub fn with_boot2<'a>( 118 | self, 119 | chip: &'a dyn Chip, 120 | image: &[u8], 121 | ) -> Result>, Error> { 122 | let partition_cfg = self 123 | .partition_cfg 124 | .map(read) 125 | .unwrap_or_else(|| Ok(bl602::DEFAULT_PARTITION_CFG.to_vec()))?; 126 | let boot_header_cfg = self 127 | .boot_header_cfg 128 | .map(read) 129 | .unwrap_or_else(|| Ok(bl602::DEFAULT_BOOTHEADER_CFG.to_vec()))?; 130 | let partition_cfg = toml::from_slice(&partition_cfg)?; 131 | let BootHeaderCfgFile { boot_header_cfg } = toml::from_slice(&boot_header_cfg)?; 132 | let ro_params = self 133 | .dtb 134 | .map(read) 135 | .unwrap_or_else(|| Ok(bl602::RO_PARAMS.to_vec()))?; 136 | 137 | let segments = chip.with_boot2(partition_cfg, boot_header_cfg, ro_params, image)?; 138 | 139 | Ok(segments) 140 | } 141 | pub fn make_segment<'a>( 142 | self, 143 | _chip: &'a dyn Chip, 144 | image: Vec, 145 | ) -> Result, Error> { 146 | let boot_header_cfg = self 147 | .boot_header_cfg 148 | .map(read) 149 | .unwrap_or_else(|| Ok(bl602::DEFAULT_BOOTHEADER_CFG.to_vec()))?; 150 | let BootHeaderCfgFile { 151 | mut boot_header_cfg, 152 | } = toml::from_slice(&boot_header_cfg)?; 153 | let img = boot_header_cfg.make_image(0x2000, image)?; 154 | 155 | Ok(RomSegment::from_vec(0x0, img)) 156 | } 157 | pub fn get_segments<'a>( 158 | self, 159 | chip: &'a dyn Chip, 160 | image: Vec, 161 | ) -> Result>, Error> { 162 | Ok(if self.without_boot2 { 163 | vec![self.make_segment(chip, Vec::from(image))?] 164 | } else { 165 | self.with_boot2(chip, &image)? 166 | }) 167 | } 168 | } 169 | 170 | pub fn read_image<'a>(chip: &dyn Chip, image: &'a [u8]) -> Result, Error> { 171 | Ok(if image[0..4] == [0x7f, 0x45, 0x4c, 0x46] { 172 | log::trace!("Detect ELF"); 173 | // ELF 174 | let firmware_image = FirmwareImage::from_data(image).map_err(|_| Error::InvalidElf)?; 175 | Cow::Owned(firmware_image.to_flash_bin(chip)) 176 | } else { 177 | // bin 178 | Cow::Borrowed(image) 179 | }) 180 | } 181 | 182 | pub fn flash(opt: FlashOpt) -> Result<(), Error> { 183 | let chip = Bl602; 184 | let image = read(&opt.image)?; 185 | let image = read_image(&chip, &image)?; 186 | 187 | let mut flasher = opt.conn.create_flasher()?; 188 | log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version); 189 | log::trace!("Boot info: {:x?}", flasher.boot_info()); 190 | 191 | let segments = opt.boot.get_segments(&chip, Vec::from(image))?; 192 | flasher.load_segments(opt.force, segments.into_iter())?; 193 | flasher.reset()?; 194 | 195 | log::info!("Success"); 196 | 197 | Ok(()) 198 | } 199 | -------------------------------------------------------------------------------- /src/blflash/connection.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | 3 | use crate::{blflash::Error, blflash::RomError}; 4 | use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; 5 | use deku::prelude::*; 6 | use serialport::SerialPort; 7 | use std::io::{Cursor, Read, Write}; 8 | use std::thread::sleep; 9 | use std::time::Duration; 10 | 11 | pub const DEFAULT_BAUDRATE: u32 = 115200; 12 | 13 | macro_rules! impl_command( 14 | ($id: expr, $t:ty, $r:ty) => ( 15 | impl Command for $t { 16 | type Response = $r; 17 | 18 | const CMD_ID: u8 = $id; 19 | } 20 | impl Response for $r {} 21 | ); 22 | ($id: expr, $t:ty) => ( 23 | impl Command for $t { 24 | type Response = crate::blflash::connection::NoResponsePayload; 25 | 26 | const CMD_ID: u8 = $id; 27 | } 28 | ); 29 | ); 30 | 31 | #[derive(DekuRead)] 32 | pub struct NoResponsePayload {} 33 | 34 | impl Response for NoResponsePayload { 35 | fn no_response_payload() -> Option { 36 | Some(Self {}) 37 | } 38 | } 39 | 40 | pub trait Response: for<'a> DekuContainerRead<'a> + Sized { 41 | // <'a> 42 | fn from_payload(input: &[u8]) -> Result { 43 | // We don't care about the lifetime 'a, as we only check the bit offset, 44 | // and don't hold onto the borrow on `input`. 45 | let (_, r) = DekuContainerRead::from_bytes((input, 0))?; 46 | Ok(r) 47 | } 48 | fn no_response_payload() -> Option { 49 | None 50 | } 51 | } 52 | 53 | pub trait Command: DekuContainerWrite { 54 | type Response: Response; 55 | const CMD_ID: u8; 56 | fn checksum(&self) -> u8 { 57 | 0 58 | } 59 | } 60 | 61 | pub struct Connection { 62 | serial: Box, 63 | baud_rate: Option, 64 | } 65 | 66 | impl Connection { 67 | pub fn new(serial: Box) -> Self { 68 | Connection { 69 | serial, 70 | baud_rate: None, 71 | } 72 | } 73 | 74 | pub fn reset(&mut self) -> Result<(), Error> { 75 | self.serial.write_request_to_send(false)?; 76 | sleep(Duration::from_millis(50)); 77 | self.serial.write_data_terminal_ready(true)?; 78 | sleep(Duration::from_millis(50)); 79 | self.serial.write_data_terminal_ready(false)?; 80 | sleep(Duration::from_millis(50)); 81 | 82 | Ok(()) 83 | } 84 | 85 | pub fn reset_to_flash(&mut self) -> Result<(), Error> { 86 | self.serial.write_request_to_send(true)?; 87 | sleep(Duration::from_millis(50)); 88 | self.serial.write_data_terminal_ready(true)?; 89 | sleep(Duration::from_millis(50)); 90 | self.serial.write_data_terminal_ready(false)?; 91 | sleep(Duration::from_millis(50)); 92 | self.serial.write_request_to_send(false)?; 93 | sleep(Duration::from_millis(50)); 94 | 95 | Ok(()) 96 | } 97 | 98 | pub fn set_timeout(&mut self, timeout: Duration) -> Result<(), Error> { 99 | self.serial.set_timeout(timeout)?; 100 | Ok(()) 101 | } 102 | 103 | pub fn set_baud(&mut self, speed: u32) -> Result<(), Error> { 104 | self.baud_rate = Some(speed); 105 | self.serial.set_baud_rate(speed)?; 106 | Ok(()) 107 | } 108 | 109 | pub fn with_timeout Result>( 110 | &mut self, 111 | timeout: Duration, 112 | mut f: F, 113 | ) -> Result { 114 | let old_timeout = self.serial.timeout(); 115 | self.serial.set_timeout(timeout)?; 116 | let result = f(self); 117 | self.serial.set_timeout(old_timeout)?; 118 | result 119 | } 120 | 121 | fn read_exact(&mut self, len: usize) -> Result, Error> { 122 | let mut buf = vec![0u8; len]; 123 | self.serial.read_exact(&mut buf)?; 124 | Ok(buf) 125 | } 126 | 127 | pub fn read_response(&mut self, len: usize) -> Result, Error> { 128 | let resp = self.read_exact(2)?; 129 | match &resp[0..2] { 130 | // OK 131 | [0x4f, 0x4b] => { 132 | if len > 0 { 133 | self.read_exact(len) 134 | } else { 135 | Ok(vec![]) 136 | } 137 | } 138 | // FL 139 | [0x46, 0x4c] => { 140 | let code = self.read_exact(2)?; 141 | let mut reader = Cursor::new(code); 142 | let code = reader.read_u16::()?; 143 | Err(Error::RomError(RomError::from(code))) 144 | } 145 | e => { 146 | log::trace!("read_response err: {:x?}", e); 147 | Err(Error::RespError) 148 | } 149 | } 150 | } 151 | 152 | pub fn calc_duration_length(&mut self, duration: Duration) -> usize { 153 | (self.baud_rate.unwrap_or(DEFAULT_BAUDRATE) / 10 / 1000) as usize 154 | * (duration.as_millis() as usize) 155 | } 156 | 157 | pub fn write_all(&mut self, buf: &[u8]) -> Result<(), Error> { 158 | Ok(self.serial.write_all(buf)?) 159 | } 160 | 161 | pub fn flush(&mut self) -> Result<(), Error> { 162 | Ok(self.serial.flush()?) 163 | } 164 | 165 | pub fn command(&mut self, command: C) -> Result { 166 | let req = self.to_cmd(command)?; 167 | self.write_all(&req)?; 168 | self.flush()?; 169 | 170 | Ok(if let Some(resp) = C::Response::no_response_payload() { 171 | self.read_response(0)?; 172 | resp 173 | } else { 174 | let len = LittleEndian::read_u16(&self.read_response(2)?); 175 | let buf = Vec::new(); 176 | let mut writer = Cursor::new(buf); 177 | writer.write_u16::(len)?; 178 | writer.write_all(&self.read_exact(len as usize)?)?; 179 | C::Response::from_payload(&writer.into_inner())? 180 | }) 181 | } 182 | 183 | fn to_cmd(&self, command: C) -> Result, Error> { 184 | let data = Vec::new(); 185 | let mut writer = Cursor::new(data); 186 | let body = command.to_bytes()?; 187 | let len = body.len() as u16; 188 | 189 | writer.write_u8(C::CMD_ID)?; 190 | writer.write_u8(command.checksum())?; 191 | writer.write_u16::(len)?; 192 | writer.write_all(&body)?; 193 | 194 | Ok(writer.into_inner()) 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | io::BufReader, 3 | thread::sleep, 4 | time::{Duration, Instant}, 5 | }; 6 | 7 | use byteorder::ReadBytesExt; 8 | use clap::{App, Arg}; 9 | use env_logger::Env; 10 | use probe_rs::{Error, MemoryInterface, Probe}; 11 | 12 | use crate::blflash::{Boot2Opt, Connection, FlashOpt}; 13 | 14 | mod blflash; 15 | 16 | fn main() { 17 | env_logger::Builder::from_env(Env::default().default_filter_or("blash=trace")) 18 | .format_timestamp(None) 19 | .init(); 20 | 21 | match run() { 22 | Ok(_) => (), 23 | Err(err) => { 24 | log::error!("Error: {}", err); 25 | } 26 | } 27 | } 28 | 29 | fn run() -> Result<(), Box> { 30 | let matches = App::new("blash") 31 | .version("1.0.2") 32 | .author("Bjoern Quentin") 33 | .about("Zero Touch BL602 Flasher") 34 | .arg( 35 | Arg::with_name("port") 36 | .long("port") 37 | .takes_value(true) 38 | .required(false), 39 | ) 40 | .arg( 41 | Arg::with_name("baud") 42 | .long("baud") 43 | .default_value("2000000") 44 | .takes_value(true) 45 | .required(false), 46 | ) 47 | .arg( 48 | Arg::with_name("monitor-baud") 49 | .long("monitor-baud") 50 | .default_value("115200") 51 | .takes_value(true) 52 | .required(false), 53 | ) 54 | .arg( 55 | Arg::with_name("no-monitor") 56 | .long("no-monitor") 57 | .required(false), 58 | ) 59 | .arg(Arg::with_name("file").last(true).required(true)) 60 | .get_matches(); 61 | 62 | let ports = serialport::available_ports().expect("No ports found!"); 63 | 64 | let port_from_env = std::env::var("BLASH_PORT").ok(); 65 | let port = if ports.len() == 1 && !matches.is_present("port") && port_from_env.is_none() { 66 | ports[0].port_name.to_string() 67 | } else { 68 | match matches.value_of("port") { 69 | Some(port) => port.to_string(), 70 | None => { 71 | if port_from_env.is_some() { 72 | port_from_env.unwrap() 73 | } else { 74 | return Err("No port specified or found".into()); 75 | } 76 | } 77 | } 78 | }; 79 | 80 | let baud = matches.value_of("baud").unwrap().parse().unwrap(); 81 | let monitor_baud = matches.value_of("monitor-baud").unwrap().parse().unwrap(); 82 | 83 | let no_monitor = matches.is_present("no-monitor"); 84 | 85 | let file = matches.value_of("file").unwrap(); 86 | 87 | // Get a list of all available debug probes. 88 | let probes = Probe::list_all(); 89 | 90 | // Use the first probe found. 91 | let probe = probes 92 | .get(0) 93 | .ok_or(Error::UnableToOpenProbe("No probe was found"))? 94 | .open()?; 95 | 96 | let mut session = probe.attach("Riscv")?; 97 | 98 | // Select a core. 99 | let mut core = session.core(0)?; 100 | 101 | let regs = core.registers(); 102 | let pc = regs.program_counter(); 103 | 104 | // Halt the attached core. 105 | core.halt(std::time::Duration::from_millis(10))?; 106 | 107 | core.reset().ok(); 108 | let t1 = core 109 | .registers() 110 | .registers() 111 | .find(|r| r.name() == "x6") 112 | .unwrap(); 113 | // set MSTATUS = 0x80000000 114 | // 0: 30001373 csrrw t1,mstatus,zero 115 | core.write_8(0x22010000, &[0x73, 0x13, 0x00, 0x30])?; 116 | core.write_core_reg(t1.into(), 0x80000000)?; 117 | core.write_core_reg(pc.into(), 0x22010000)?; 118 | core.step()?; 119 | 120 | let mut eflash_loader = [0u32; 29072 / 4]; 121 | let loader = &LOADER[(176 + 16)..]; 122 | for (index, word) in eflash_loader.iter_mut().enumerate() { 123 | let index = index * 4; 124 | *word = loader[index] as u32 125 | + ((loader[index + 1] as u32) << 8) 126 | + ((loader[index + 2] as u32) << 16) 127 | + ((loader[index + 3] as u32) << 24); 128 | } 129 | 130 | log::trace!("Downloading eflasher"); 131 | let t1 = Instant::now(); 132 | core.write_32(0x22010000, &eflash_loader).unwrap(); // skip boot header + segment header 133 | let t2 = Instant::now(); 134 | log::trace!("Downloaded in {:?}", (t2 - t1)); 135 | 136 | // RESET THE CORE AND RUN 137 | core.reset().ok(); // this errors but we ignore it! 138 | core.write_core_reg(pc.into(), 0x22010000)?; 139 | core.run()?; 140 | sleep(Duration::from_millis(100)); 141 | 142 | let opt = FlashOpt { 143 | conn: Connection { 144 | port: port.clone(), 145 | baud_rate: baud, 146 | }, 147 | image: file.into(), 148 | force: false, 149 | boot: Boot2Opt { 150 | partition_cfg: None, 151 | boot_header_cfg: None, 152 | dtb: None, 153 | without_boot2: false, 154 | }, 155 | }; 156 | blflash::flash(opt).unwrap(); 157 | 158 | // done flashing ... 159 | 160 | // RESET 161 | core.halt(std::time::Duration::from_millis(100))?; 162 | core.reset().ok(); // this errors but we ignore it! 163 | core.write_core_reg(pc.into(), 0x21000000)?; 164 | core.run()?; 165 | 166 | if no_monitor { 167 | return Ok(()); 168 | } 169 | 170 | // connect serial port 171 | log::info!("start serial monitor"); 172 | let mut port = serialport::new(port, monitor_baud) 173 | .data_bits(serialport::DataBits::Eight) 174 | .parity(serialport::Parity::None) 175 | .stop_bits(serialport::StopBits::One) 176 | .flow_control(serialport::FlowControl::None) 177 | .open()?; 178 | port.set_timeout(Duration::from_millis(10)).unwrap(); 179 | 180 | let canceled = std::sync::Arc::new(std::sync::Mutex::new(false)); 181 | 182 | let canceled_clone = canceled.clone(); 183 | ctrlc::set_handler(move || { 184 | *canceled_clone.lock().unwrap() = true; 185 | }) 186 | .expect("Error setting Ctrl-C handler"); 187 | 188 | let mut br = BufReader::new(port); 189 | loop { 190 | if *canceled.lock().unwrap() { 191 | break; 192 | } 193 | 194 | let x = br.read_u8(); 195 | match x { 196 | Ok(x) => print!("{}", x as char), 197 | Err(e) => { 198 | if e.kind() != std::io::ErrorKind::TimedOut { 199 | println!("{:?}", e); 200 | break; 201 | } 202 | } 203 | } 204 | } 205 | 206 | Ok(()) 207 | } 208 | 209 | static LOADER: &[u8; 29264] = include_bytes!("../bin/eflash_loader_40m.bin"); 210 | -------------------------------------------------------------------------------- /src/blflash/image/bootheader.rs: -------------------------------------------------------------------------------- 1 | use crate::blflash::Error; 2 | use byteorder::{NativeEndian, ReadBytesExt}; 3 | use deku::prelude::*; 4 | use serde::Deserialize; 5 | use sha2::{Digest, Sha256}; 6 | use std::io::Cursor; 7 | 8 | #[derive(Debug, Deserialize, Default, Clone)] 9 | pub struct BootHeaderCfgFile { 10 | #[serde(rename = "BOOTHEADER_CFG")] 11 | pub boot_header_cfg: BootHeaderCfg, 12 | } 13 | 14 | #[derive(Debug, Deserialize, DekuWrite, Default, Clone)] 15 | pub struct FlashCfg { 16 | flashcfg_magic_code: u32, 17 | // 12 18 | io_mode: u8, 19 | cont_read_support: u8, 20 | sfctrl_clk_delay: u8, 21 | sfctrl_clk_invert: u8, 22 | // 16 23 | reset_en_cmd: u8, 24 | reset_cmd: u8, 25 | exit_contread_cmd: u8, 26 | exit_contread_cmd_size: u8, 27 | // 20 28 | jedecid_cmd: u8, 29 | jedecid_cmd_dmy_clk: u8, 30 | qpi_jedecid_cmd: u8, 31 | qpi_jedecid_dmy_clk: u8, 32 | // 24 33 | sector_size: u8, 34 | mfg_id: u8, 35 | page_size: u16, 36 | // 28 37 | chip_erase_cmd: u8, 38 | sector_erase_cmd: u8, 39 | blk32k_erase_cmd: u8, 40 | blk64k_erase_cmd: u8, 41 | // 32 42 | write_enable_cmd: u8, 43 | page_prog_cmd: u8, 44 | qpage_prog_cmd: u8, 45 | qual_page_prog_addr_mode: u8, 46 | // 36 47 | fast_read_cmd: u8, 48 | fast_read_dmy_clk: u8, 49 | qpi_fast_read_cmd: u8, 50 | qpi_fast_read_dmy_clk: u8, 51 | // 40 52 | fast_read_do_cmd: u8, 53 | fast_read_do_dmy_clk: u8, 54 | fast_read_dio_cmd: u8, 55 | fast_read_dio_dmy_clk: u8, 56 | // 44 57 | fast_read_qo_cmd: u8, 58 | fast_read_qo_dmy_clk: u8, 59 | fast_read_qio_cmd: u8, 60 | fast_read_qio_dmy_clk: u8, 61 | // 48 62 | qpi_fast_read_qio_cmd: u8, 63 | qpi_fast_read_qio_dmy_clk: u8, 64 | qpi_page_prog_cmd: u8, 65 | write_vreg_enable_cmd: u8, 66 | // 52 67 | wel_reg_index: u8, 68 | qe_reg_index: u8, 69 | busy_reg_index: u8, 70 | wel_bit_pos: u8, 71 | // 56 72 | qe_bit_pos: u8, 73 | busy_bit_pos: u8, 74 | wel_reg_write_len: u8, 75 | wel_reg_read_len: u8, 76 | // 60 77 | qe_reg_write_len: u8, 78 | qe_reg_read_len: u8, 79 | release_power_down: u8, 80 | busy_reg_read_len: u8, 81 | // 64 82 | reg_read_cmd0: u8, 83 | reg_read_cmd1: u8, 84 | #[serde(skip)] 85 | _unused1: u16, 86 | // 68 87 | reg_write_cmd0: u8, 88 | reg_write_cmd1: u8, 89 | #[serde(skip)] 90 | _unused2: u16, 91 | // 72 92 | enter_qpi_cmd: u8, 93 | exit_qpi_cmd: u8, 94 | cont_read_code: u8, 95 | cont_read_exit_code: u8, 96 | // 76 97 | burst_wrap_cmd: u8, 98 | burst_wrap_dmy_clk: u8, 99 | burst_wrap_data_mode: u8, 100 | burst_wrap_code: u8, 101 | // 80 102 | de_burst_wrap_cmd: u8, 103 | de_burst_wrap_cmd_dmy_clk: u8, 104 | de_burst_wrap_code_mode: u8, 105 | de_burst_wrap_code: u8, 106 | // 84 107 | sector_erase_time: u16, 108 | blk32k_erase_time: u16, 109 | // 88 110 | blk64k_erase_time: u16, 111 | page_prog_time: u16, 112 | // 92 113 | chip_erase_time: u16, 114 | power_down_delay: u8, 115 | qe_data: u8, 116 | // 96 117 | #[deku(update = "self.checksum()")] 118 | flashcfg_crc32: u32, 119 | } 120 | 121 | #[derive(Debug, Deserialize, DekuWrite, Default, Clone)] 122 | pub struct ClkCfg { 123 | // 100 124 | clkcfg_magic_code: u32, 125 | // 104 126 | xtal_type: u8, 127 | pll_clk: u8, 128 | hclk_div: u8, 129 | bclk_div: u8, 130 | // 108 131 | flash_clk_type: u8, 132 | flash_clk_div: u8, 133 | #[serde(skip)] 134 | _unused1: u16, 135 | // 112 136 | #[deku(update = "self.checksum()")] 137 | clkcfg_crc32: u32, 138 | } 139 | 140 | // NOTE: the order is reversed here 141 | // see: https://github.com/sharksforarms/deku/issues/134 142 | #[derive(Debug, Deserialize, DekuWrite, Default, Clone)] 143 | pub struct BootCfg { 144 | // 116 145 | #[deku(bits = 2)] 146 | #[serde(skip)] 147 | _unused1: u8, 148 | #[deku(bits = 2)] 149 | key_sel: u8, 150 | #[deku(bits = 2)] 151 | encrypt_type: u8, 152 | #[deku(bits = 2)] 153 | sign: u8, 154 | // 117 155 | #[deku(bits = 4)] 156 | cache_way_disable: u8, 157 | #[deku(bits = 1)] 158 | aes_region_lock: u8, 159 | #[deku(bits = 1)] 160 | notload_in_bootrom: u8, 161 | #[deku(bits = 1)] 162 | cache_enable: u8, 163 | #[deku(bits = 1)] 164 | no_segment: u8, 165 | // 118 166 | #[deku(bits = 14)] 167 | #[serde(skip)] 168 | _unused2: u32, 169 | #[deku(bits = 1)] 170 | hash_ignore: u8, 171 | #[deku(bits = 1)] 172 | crc_ignore: u8, 173 | 174 | // 120 175 | pub img_len: u32, 176 | // 124 177 | bootentry: u32, 178 | // 128 179 | img_start: u32, 180 | // 132 181 | hash_0: u32, 182 | hash_1: u32, 183 | hash_2: u32, 184 | hash_3: u32, 185 | hash_4: u32, 186 | hash_5: u32, 187 | hash_6: u32, 188 | hash_7: u32, 189 | 190 | #[serde(skip)] 191 | _unused3: [u8; 8], 192 | } 193 | 194 | #[derive(Debug, Deserialize, DekuWrite, Default, Clone)] 195 | pub struct BootHeaderCfg { 196 | magic_code: u32, 197 | revision: u32, 198 | 199 | #[serde(flatten)] 200 | pub flash_cfg: FlashCfg, 201 | 202 | #[serde(flatten)] 203 | pub clk_cfg: ClkCfg, 204 | 205 | #[serde(flatten)] 206 | pub boot_cfg: BootCfg, 207 | 208 | // 172 209 | #[deku(update = "self.checksum()")] 210 | crc32: u32, 211 | } 212 | 213 | impl FlashCfg { 214 | fn checksum(&self) -> u32 { 215 | let data = self.to_bytes().unwrap(); 216 | crc::Crc::::new(&crc::CRC_32_ISO_HDLC).checksum(&data[4..data.len() - 4]) 217 | } 218 | } 219 | 220 | impl ClkCfg { 221 | fn checksum(&self) -> u32 { 222 | let data = self.to_bytes().unwrap(); 223 | crc::Crc::::new(&crc::CRC_32_ISO_HDLC).checksum(&data[4..data.len() - 4]) 224 | } 225 | } 226 | 227 | impl BootHeaderCfg { 228 | fn checksum(&self) -> u32 { 229 | let data = self.to_bytes().unwrap(); 230 | crc::Crc::::new(&crc::CRC_32_ISO_HDLC).checksum(&data[0..data.len() - 4]) 231 | } 232 | fn update_sha256(&mut self, hash: &[u8]) -> Result<(), Error> { 233 | let mut reader = Cursor::new(hash); 234 | self.boot_cfg.hash_0 = reader.read_u32::()?; 235 | self.boot_cfg.hash_1 = reader.read_u32::()?; 236 | self.boot_cfg.hash_2 = reader.read_u32::()?; 237 | self.boot_cfg.hash_3 = reader.read_u32::()?; 238 | self.boot_cfg.hash_4 = reader.read_u32::()?; 239 | self.boot_cfg.hash_5 = reader.read_u32::()?; 240 | self.boot_cfg.hash_6 = reader.read_u32::()?; 241 | self.boot_cfg.hash_7 = reader.read_u32::()?; 242 | Ok(()) 243 | } 244 | pub fn make_image(&mut self, offset: usize, mut image: Vec) -> Result, Error> { 245 | let binlen = ((image.len() + 15) / 16) * 16; 246 | image.resize(binlen, 0xFF); 247 | let hash = Sha256::digest(&image); 248 | self.update_sha256(&hash[..])?; 249 | self.boot_cfg.img_len = image.len() as u32; 250 | self.flash_cfg.update()?; 251 | self.clk_cfg.update()?; 252 | self.update()?; 253 | 254 | let mut header = self.to_bytes()?; 255 | 256 | header.resize(offset, 0xff); 257 | header.append(&mut image); 258 | 259 | Ok(header) 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/blflash/flasher.rs: -------------------------------------------------------------------------------- 1 | use crate::blflash::Error; 2 | use crate::blflash::{connection::Connection, elf::RomSegment}; 3 | use indicatif::{HumanBytes, ProgressBar, ProgressStyle}; 4 | use serialport::SerialPort; 5 | use sha2::{Digest, Sha256}; 6 | use std::thread::sleep; 7 | use std::{ 8 | io::{Cursor, Read}, 9 | time::{Duration, Instant}, 10 | }; 11 | 12 | fn get_bar(len: u64) -> ProgressBar { 13 | let bar = ProgressBar::new(len); 14 | bar.set_style( 15 | ProgressStyle::default_bar() 16 | .template(" {wide_bar} {bytes}/{total_bytes} {bytes_per_sec} {eta} ") 17 | .progress_chars("#>-"), 18 | ); 19 | bar 20 | } 21 | 22 | pub struct Flasher { 23 | connection: Connection, 24 | boot_info: protocol::BootInfo, 25 | } 26 | 27 | impl Flasher { 28 | pub fn connect(serial: Box, initial_speed: u32) -> Result { 29 | let mut flasher = Flasher { 30 | connection: Connection::new(serial), 31 | boot_info: protocol::BootInfo::default(), 32 | }; 33 | flasher.connection.set_baud(initial_speed)?; 34 | flasher.start_connection()?; 35 | flasher.connection.set_timeout(Duration::from_secs(10))?; 36 | 37 | Ok(flasher) 38 | } 39 | 40 | pub fn boot_info(&self) -> &protocol::BootInfo { 41 | &self.boot_info 42 | } 43 | 44 | pub fn load_segments<'a>( 45 | &'a mut self, 46 | force: bool, 47 | segments: impl Iterator>, 48 | ) -> Result<(), Error> { 49 | // self.load_eflash_loader()?; 50 | 51 | for segment in segments { 52 | let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]); 53 | 54 | // skip segment if the contents are matched 55 | if !force { 56 | let sha256 = self 57 | .eflash_loader() 58 | .sha256_read(segment.addr, segment.size())?; 59 | if sha256 == &local_hash[..] { 60 | log::info!( 61 | "Skip segment addr: {:x} size: {} sha256 matches", 62 | segment.addr, 63 | segment.size() 64 | ); 65 | continue; 66 | } 67 | } 68 | 69 | log::info!( 70 | "Erase flash addr: {:x} size: {}", 71 | segment.addr, 72 | segment.size() 73 | ); 74 | self.eflash_loader() 75 | .flash_erase(segment.addr, segment.addr + segment.size())?; 76 | 77 | let mut reader = Cursor::new(&segment.data); 78 | let mut cur = segment.addr; 79 | 80 | let start = Instant::now(); 81 | log::info!("Program flash... {:x}", local_hash); 82 | let pb = get_bar(segment.size() as u64); 83 | loop { 84 | let size = self.eflash_loader().flash_program(cur, &mut reader)?; 85 | // log::trace!("program {:x} {:x}", cur, size); 86 | cur += size; 87 | pb.inc(size as u64); 88 | if size == 0 { 89 | break; 90 | } 91 | } 92 | pb.finish_and_clear(); 93 | let elapsed = start.elapsed(); 94 | log::info!( 95 | "Program done {:?} {}/s", 96 | elapsed, 97 | HumanBytes((segment.size() as f64 / elapsed.as_millis() as f64 * 1000.0) as u64) 98 | ); 99 | 100 | let sha256 = self 101 | .eflash_loader() 102 | .sha256_read(segment.addr, segment.size())?; 103 | if sha256 != &local_hash[..] { 104 | log::warn!( 105 | "sha256 not match: {} != {}", 106 | hex::encode(sha256), 107 | hex::encode(local_hash) 108 | ); 109 | } 110 | } 111 | Ok(()) 112 | } 113 | 114 | pub fn reset(&mut self) -> Result<(), Error> { 115 | Ok(self.connection.reset()?) 116 | } 117 | 118 | fn eflash_loader(&mut self) -> EflashLoader { 119 | EflashLoader(&mut self.connection) 120 | } 121 | 122 | fn handshake(&mut self) -> Result<(), Error> { 123 | self.connection 124 | .with_timeout(Duration::from_millis(200), |connection| { 125 | let len = connection.calc_duration_length(Duration::from_millis(5)); 126 | log::trace!("5ms send count {}", len); 127 | let data: Vec = std::iter::repeat(0x55u8).take(len).collect(); 128 | let start = Instant::now(); 129 | connection.write_all(&data)?; 130 | connection.flush()?; 131 | log::trace!("handshake sent elapsed {:?}", start.elapsed()); 132 | sleep(Duration::from_millis(200)); 133 | 134 | for _ in 0..5 { 135 | if connection.read_response(0).is_ok() { 136 | return Ok(()); 137 | } 138 | } 139 | 140 | Err(Error::Timeout) 141 | }) 142 | } 143 | 144 | fn start_connection(&mut self) -> Result<(), Error> { 145 | log::info!("Start connection..."); 146 | self.connection.reset_to_flash()?; 147 | for i in 1..=10 { 148 | self.connection.flush()?; 149 | if self.handshake().is_ok() { 150 | log::info!("Connection Succeed"); 151 | return Ok(()); 152 | } else { 153 | log::debug!("Retry {}", i); 154 | } 155 | } 156 | Err(Error::ConnectionFailed) 157 | } 158 | } 159 | 160 | pub struct EflashLoader<'a>(&'a mut Connection); 161 | 162 | impl<'a> EflashLoader<'a> { 163 | pub fn sha256_read(&mut self, addr: u32, len: u32) -> Result<[u8; 32], Error> { 164 | Ok(self.0.command(protocol::Sha256Read { addr, len })?.digest) 165 | } 166 | 167 | pub fn flash_program(&mut self, addr: u32, reader: &mut impl Read) -> Result { 168 | let mut data = vec![0u8; 4000]; 169 | let size = reader.read(&mut data)?; 170 | if size == 0 { 171 | return Ok(0); 172 | } 173 | data.truncate(size); 174 | 175 | self.0.command(protocol::FlashProgram { addr, data })?; 176 | 177 | Ok(size as u32) 178 | } 179 | 180 | pub fn flash_erase(&mut self, start: u32, end: u32) -> Result<(), Error> { 181 | self.0.command(protocol::FlashErase { start, end })?; 182 | 183 | Ok(()) 184 | } 185 | } 186 | 187 | mod protocol { 188 | use crate::blflash::connection::{Command, Response}; 189 | use deku::prelude::*; 190 | 191 | #[derive(Debug, DekuWrite, Default)] 192 | pub struct CheckImage {} 193 | impl_command!(0x19, CheckImage); 194 | 195 | #[derive(Debug, DekuWrite, Default)] 196 | pub struct RunImage {} 197 | impl_command!(0x1a, RunImage); 198 | 199 | #[derive(Debug, DekuWrite, Default)] 200 | pub struct BootInfoReq {} 201 | #[derive(Debug, DekuRead, Default)] 202 | pub struct BootInfo { 203 | pub len: u16, 204 | pub bootrom_version: u32, 205 | pub otp_info: [u8; 16], 206 | } 207 | impl_command!(0x10, BootInfoReq, BootInfo); 208 | 209 | #[derive(Debug, DekuWrite, Default)] 210 | pub struct LoadBootHeader { 211 | // length must be 176 212 | pub boot_header: Vec, 213 | } 214 | impl_command!(0x11, LoadBootHeader); 215 | 216 | #[derive(Debug, DekuWrite, Default)] 217 | pub struct LoadSegmentHeaderReq { 218 | // length must be 16 219 | pub segment_header: Vec, 220 | } 221 | #[derive(Debug, DekuRead)] 222 | pub struct LoadSegmentHeader { 223 | pub len: u16, 224 | #[deku(count = "len")] 225 | pub data: Vec, 226 | } 227 | impl_command!(0x17, LoadSegmentHeaderReq, LoadSegmentHeader); 228 | 229 | #[derive(Debug, DekuWrite, Default)] 230 | pub struct LoadSegmentData { 231 | pub segment_data: Vec, 232 | } 233 | impl_command!(0x18, LoadSegmentData); 234 | 235 | #[derive(Debug, DekuWrite, Default)] 236 | pub struct FlashErase { 237 | pub start: u32, 238 | pub end: u32, 239 | } 240 | impl_command!(0x30, FlashErase); 241 | 242 | #[derive(Debug, DekuWrite, Default)] 243 | pub struct FlashProgram { 244 | pub addr: u32, 245 | pub data: Vec, 246 | } 247 | impl_command!(0x31, FlashProgram); 248 | 249 | #[derive(Debug, DekuWrite, Default)] 250 | pub struct FlashRead { 251 | pub addr: u32, 252 | pub size: u32, 253 | } 254 | #[derive(Debug, DekuRead)] 255 | pub struct FlashReadResp { 256 | pub len: u16, 257 | #[deku(count = "len")] 258 | pub data: Vec, 259 | } 260 | impl_command!(0x32, FlashRead, FlashReadResp); 261 | 262 | #[derive(Debug, DekuWrite, Default)] 263 | pub struct Sha256Read { 264 | pub addr: u32, 265 | pub len: u32, 266 | } 267 | 268 | #[derive(Debug, DekuRead)] 269 | #[deku(magic = b"\x20\x00")] 270 | pub struct Sha256ReadResp { 271 | pub digest: [u8; 32], 272 | } 273 | impl_command!(0x3d, Sha256Read, Sha256ReadResp); 274 | } 275 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "CoreFoundation-sys" 7 | version = "0.1.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b" 10 | dependencies = [ 11 | "libc", 12 | "mach 0.1.2", 13 | ] 14 | 15 | [[package]] 16 | name = "IOKit-sys" 17 | version = "0.1.5" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a" 20 | dependencies = [ 21 | "CoreFoundation-sys", 22 | "libc", 23 | "mach 0.1.2", 24 | ] 25 | 26 | [[package]] 27 | name = "aho-corasick" 28 | version = "0.7.18" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 31 | dependencies = [ 32 | "memchr", 33 | ] 34 | 35 | [[package]] 36 | name = "ansi_term" 37 | version = "0.11.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 40 | dependencies = [ 41 | "winapi", 42 | ] 43 | 44 | [[package]] 45 | name = "anyhow" 46 | version = "1.0.44" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" 49 | 50 | [[package]] 51 | name = "atty" 52 | version = "0.2.14" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 55 | dependencies = [ 56 | "hermit-abi", 57 | "libc", 58 | "winapi", 59 | ] 60 | 61 | [[package]] 62 | name = "autocfg" 63 | version = "1.0.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 66 | 67 | [[package]] 68 | name = "base64" 69 | version = "0.13.0" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 72 | 73 | [[package]] 74 | name = "bincode" 75 | version = "1.3.3" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 78 | dependencies = [ 79 | "serde", 80 | ] 81 | 82 | [[package]] 83 | name = "bitfield" 84 | version = "0.13.2" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 87 | 88 | [[package]] 89 | name = "bitflags" 90 | version = "1.3.2" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 93 | 94 | [[package]] 95 | name = "bitvec" 96 | version = "0.22.3" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" 99 | dependencies = [ 100 | "funty", 101 | "radium", 102 | "tap", 103 | "wyz", 104 | ] 105 | 106 | [[package]] 107 | name = "blash" 108 | version = "0.1.2" 109 | dependencies = [ 110 | "bitvec", 111 | "byteorder", 112 | "clap", 113 | "crc", 114 | "ctrlc", 115 | "deku", 116 | "env_logger", 117 | "funty", 118 | "hex", 119 | "indicatif", 120 | "log", 121 | "main_error", 122 | "parse_int", 123 | "paw", 124 | "probe-rs", 125 | "serde", 126 | "serialport", 127 | "sha2", 128 | "structopt", 129 | "thiserror", 130 | "toml", 131 | "xmas-elf", 132 | ] 133 | 134 | [[package]] 135 | name = "block-buffer" 136 | version = "0.9.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 139 | dependencies = [ 140 | "generic-array", 141 | ] 142 | 143 | [[package]] 144 | name = "byteorder" 145 | version = "1.4.3" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 148 | 149 | [[package]] 150 | name = "cc" 151 | version = "1.0.70" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" 154 | 155 | [[package]] 156 | name = "cfg-if" 157 | version = "0.1.10" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 160 | 161 | [[package]] 162 | name = "cfg-if" 163 | version = "1.0.0" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 166 | 167 | [[package]] 168 | name = "clap" 169 | version = "2.33.3" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 172 | dependencies = [ 173 | "ansi_term", 174 | "atty", 175 | "bitflags", 176 | "strsim 0.8.0", 177 | "textwrap", 178 | "unicode-width", 179 | "vec_map", 180 | ] 181 | 182 | [[package]] 183 | name = "console" 184 | version = "0.14.1" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" 187 | dependencies = [ 188 | "encode_unicode", 189 | "lazy_static", 190 | "libc", 191 | "terminal_size", 192 | "winapi", 193 | ] 194 | 195 | [[package]] 196 | name = "cpufeatures" 197 | version = "0.2.1" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 200 | dependencies = [ 201 | "libc", 202 | ] 203 | 204 | [[package]] 205 | name = "crc" 206 | version = "2.0.0" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "10c2722795460108a7872e1cd933a85d6ec38abc4baecad51028f702da28889f" 209 | dependencies = [ 210 | "crc-catalog", 211 | ] 212 | 213 | [[package]] 214 | name = "crc-catalog" 215 | version = "1.1.1" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" 218 | 219 | [[package]] 220 | name = "ctrlc" 221 | version = "3.2.0" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "377c9b002a72a0b2c1a18c62e2f3864bdfea4a015e3683a96e24aa45dd6c02d1" 224 | dependencies = [ 225 | "nix 0.22.0", 226 | "winapi", 227 | ] 228 | 229 | [[package]] 230 | name = "darling" 231 | version = "0.13.0" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" 234 | dependencies = [ 235 | "darling_core", 236 | "darling_macro", 237 | ] 238 | 239 | [[package]] 240 | name = "darling_core" 241 | version = "0.13.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" 244 | dependencies = [ 245 | "fnv", 246 | "ident_case", 247 | "proc-macro2", 248 | "quote", 249 | "strsim 0.10.0", 250 | "syn", 251 | ] 252 | 253 | [[package]] 254 | name = "darling_macro" 255 | version = "0.13.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" 258 | dependencies = [ 259 | "darling_core", 260 | "quote", 261 | "syn", 262 | ] 263 | 264 | [[package]] 265 | name = "deku" 266 | version = "0.12.3" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "6335fcecd3d7e4296068dabfec4083f0f6f5388fbbe012f8a378b84f2f334e70" 269 | dependencies = [ 270 | "bitvec", 271 | "deku_derive", 272 | ] 273 | 274 | [[package]] 275 | name = "deku_derive" 276 | version = "0.12.3" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "66efa7166ef907b03add5db16ebb7bdb828dd31d016ec57d4455ef6489eba1f4" 279 | dependencies = [ 280 | "darling", 281 | "proc-macro-crate", 282 | "proc-macro2", 283 | "quote", 284 | "syn", 285 | ] 286 | 287 | [[package]] 288 | name = "digest" 289 | version = "0.9.0" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 292 | dependencies = [ 293 | "generic-array", 294 | ] 295 | 296 | [[package]] 297 | name = "dtoa" 298 | version = "0.4.8" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" 301 | 302 | [[package]] 303 | name = "encode_unicode" 304 | version = "0.3.6" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 307 | 308 | [[package]] 309 | name = "enum-primitive-derive" 310 | version = "0.2.1" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "5f52288f9a7ebb08959188872b58e7eaa12af9cb47da8e94158e16da7e143340" 313 | dependencies = [ 314 | "num-traits", 315 | "quote", 316 | "syn", 317 | ] 318 | 319 | [[package]] 320 | name = "env_logger" 321 | version = "0.9.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 324 | dependencies = [ 325 | "atty", 326 | "humantime", 327 | "log", 328 | "regex", 329 | "termcolor", 330 | ] 331 | 332 | [[package]] 333 | name = "fallible-iterator" 334 | version = "0.2.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 337 | 338 | [[package]] 339 | name = "fnv" 340 | version = "1.0.7" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 343 | 344 | [[package]] 345 | name = "funty" 346 | version = "1.2.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" 349 | 350 | [[package]] 351 | name = "generic-array" 352 | version = "0.14.4" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 355 | dependencies = [ 356 | "typenum", 357 | "version_check", 358 | ] 359 | 360 | [[package]] 361 | name = "gimli" 362 | version = "0.25.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" 365 | dependencies = [ 366 | "fallible-iterator", 367 | "stable_deref_trait", 368 | ] 369 | 370 | [[package]] 371 | name = "hashbrown" 372 | version = "0.11.2" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 375 | 376 | [[package]] 377 | name = "heck" 378 | version = "0.3.3" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 381 | dependencies = [ 382 | "unicode-segmentation", 383 | ] 384 | 385 | [[package]] 386 | name = "hermit-abi" 387 | version = "0.1.19" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 390 | dependencies = [ 391 | "libc", 392 | ] 393 | 394 | [[package]] 395 | name = "hex" 396 | version = "0.4.3" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 399 | 400 | [[package]] 401 | name = "hidapi" 402 | version = "1.2.6" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "81e07da7e8614133e88b3a93b7352eb3729e3ccd82d5ab661adf23bef1761bf8" 405 | dependencies = [ 406 | "cc", 407 | "libc", 408 | "pkg-config", 409 | ] 410 | 411 | [[package]] 412 | name = "humantime" 413 | version = "2.1.0" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 416 | 417 | [[package]] 418 | name = "ident_case" 419 | version = "1.0.1" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 422 | 423 | [[package]] 424 | name = "ihex" 425 | version = "3.0.0" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "365a784774bb381e8c19edb91190a90d7f2625e057b55de2bc0f6b57bc779ff2" 428 | 429 | [[package]] 430 | name = "indexmap" 431 | version = "1.7.0" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 434 | dependencies = [ 435 | "autocfg", 436 | "hashbrown", 437 | ] 438 | 439 | [[package]] 440 | name = "indicatif" 441 | version = "0.16.2" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" 444 | dependencies = [ 445 | "console", 446 | "lazy_static", 447 | "number_prefix", 448 | "regex", 449 | ] 450 | 451 | [[package]] 452 | name = "jaylink" 453 | version = "0.2.0" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "3f58b72b6aa9d25083b8c19d292fe015a936185fa200d15e225e1524a18222e9" 456 | dependencies = [ 457 | "bitflags", 458 | "byteorder", 459 | "log", 460 | "rusb", 461 | ] 462 | 463 | [[package]] 464 | name = "jep106" 465 | version = "0.2.5" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "939876d20519325db0883757e29e9858ee02919d0f03e43c74f69296caa314f4" 468 | dependencies = [ 469 | "serde", 470 | ] 471 | 472 | [[package]] 473 | name = "lazy_static" 474 | version = "1.4.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 477 | 478 | [[package]] 479 | name = "libc" 480 | version = "0.2.103" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" 483 | 484 | [[package]] 485 | name = "libftdi1-source-lgpl" 486 | version = "1.5.0" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "4412918d38c7b78f59c5b0cefec46e2099876dfd95f07f9bb2269d1d7b09fdb1" 489 | 490 | [[package]] 491 | name = "libftdi1-sys" 492 | version = "1.1.1" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "4f115599b5073d108edfcc32daa1a673193323fc10559c33bed6cc20f2f0bf4d" 495 | dependencies = [ 496 | "cc", 497 | "cfg-if 1.0.0", 498 | "libc", 499 | "libftdi1-source-lgpl", 500 | "libusb1-sys", 501 | "pkg-config", 502 | "vcpkg", 503 | ] 504 | 505 | [[package]] 506 | name = "libudev" 507 | version = "0.2.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe" 510 | dependencies = [ 511 | "libc", 512 | "libudev-sys", 513 | ] 514 | 515 | [[package]] 516 | name = "libudev-sys" 517 | version = "0.1.4" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" 520 | dependencies = [ 521 | "libc", 522 | "pkg-config", 523 | ] 524 | 525 | [[package]] 526 | name = "libusb1-sys" 527 | version = "0.5.0" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "e22e89d08bbe6816c6c5d446203b859eba35b8fa94bf1b7edb2f6d25d43f023f" 530 | dependencies = [ 531 | "cc", 532 | "libc", 533 | "pkg-config", 534 | "vcpkg", 535 | ] 536 | 537 | [[package]] 538 | name = "linked-hash-map" 539 | version = "0.5.4" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" 542 | 543 | [[package]] 544 | name = "log" 545 | version = "0.4.14" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 548 | dependencies = [ 549 | "cfg-if 1.0.0", 550 | ] 551 | 552 | [[package]] 553 | name = "mach" 554 | version = "0.1.2" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9" 557 | dependencies = [ 558 | "libc", 559 | ] 560 | 561 | [[package]] 562 | name = "mach" 563 | version = "0.2.3" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" 566 | dependencies = [ 567 | "libc", 568 | ] 569 | 570 | [[package]] 571 | name = "main_error" 572 | version = "0.1.2" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a" 575 | 576 | [[package]] 577 | name = "memchr" 578 | version = "2.4.1" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 581 | 582 | [[package]] 583 | name = "memoffset" 584 | version = "0.6.4" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" 587 | dependencies = [ 588 | "autocfg", 589 | ] 590 | 591 | [[package]] 592 | name = "nix" 593 | version = "0.16.1" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb" 596 | dependencies = [ 597 | "bitflags", 598 | "cc", 599 | "cfg-if 0.1.10", 600 | "libc", 601 | "void", 602 | ] 603 | 604 | [[package]] 605 | name = "nix" 606 | version = "0.22.0" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" 609 | dependencies = [ 610 | "bitflags", 611 | "cc", 612 | "cfg-if 1.0.0", 613 | "libc", 614 | "memoffset", 615 | ] 616 | 617 | [[package]] 618 | name = "num-traits" 619 | version = "0.2.14" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 622 | dependencies = [ 623 | "autocfg", 624 | ] 625 | 626 | [[package]] 627 | name = "number_prefix" 628 | version = "0.4.0" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 631 | 632 | [[package]] 633 | name = "object" 634 | version = "0.26.2" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" 637 | dependencies = [ 638 | "memchr", 639 | ] 640 | 641 | [[package]] 642 | name = "once_cell" 643 | version = "1.8.0" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 646 | 647 | [[package]] 648 | name = "opaque-debug" 649 | version = "0.3.0" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 652 | 653 | [[package]] 654 | name = "parse_int" 655 | version = "0.6.0" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "2d695b79916a2c08bcff7be7647ab60d1402885265005a6658ffe6d763553c5a" 658 | dependencies = [ 659 | "num-traits", 660 | ] 661 | 662 | [[package]] 663 | name = "paw" 664 | version = "1.0.0" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" 667 | dependencies = [ 668 | "paw-attributes", 669 | "paw-raw", 670 | ] 671 | 672 | [[package]] 673 | name = "paw-attributes" 674 | version = "1.0.2" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" 677 | dependencies = [ 678 | "proc-macro2", 679 | "quote", 680 | "syn", 681 | ] 682 | 683 | [[package]] 684 | name = "paw-raw" 685 | version = "1.0.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" 688 | 689 | [[package]] 690 | name = "pkg-config" 691 | version = "0.3.20" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" 694 | 695 | [[package]] 696 | name = "probe-rs" 697 | version = "0.11.0" 698 | source = "git+https://github.com/probe-rs/probe-rs/?rev=9100410735b27b4050c744445e8b347c2a894ab1#9100410735b27b4050c744445e8b347c2a894ab1" 699 | dependencies = [ 700 | "anyhow", 701 | "base64", 702 | "bincode", 703 | "bitfield", 704 | "bitvec", 705 | "enum-primitive-derive", 706 | "gimli", 707 | "hidapi", 708 | "ihex", 709 | "jaylink", 710 | "jep106", 711 | "libftdi1-sys", 712 | "log", 713 | "num-traits", 714 | "object", 715 | "once_cell", 716 | "probe-rs-target", 717 | "rusb", 718 | "scroll", 719 | "serde", 720 | "serde_yaml", 721 | "static_assertions", 722 | "svg", 723 | "thiserror", 724 | "thousands", 725 | ] 726 | 727 | [[package]] 728 | name = "probe-rs-target" 729 | version = "0.11.0" 730 | source = "git+https://github.com/probe-rs/probe-rs/?rev=9100410735b27b4050c744445e8b347c2a894ab1#9100410735b27b4050c744445e8b347c2a894ab1" 731 | dependencies = [ 732 | "base64", 733 | "jep106", 734 | "serde", 735 | ] 736 | 737 | [[package]] 738 | name = "proc-macro-crate" 739 | version = "1.1.0" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" 742 | dependencies = [ 743 | "thiserror", 744 | "toml", 745 | ] 746 | 747 | [[package]] 748 | name = "proc-macro-error" 749 | version = "1.0.4" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 752 | dependencies = [ 753 | "proc-macro-error-attr", 754 | "proc-macro2", 755 | "quote", 756 | "syn", 757 | "version_check", 758 | ] 759 | 760 | [[package]] 761 | name = "proc-macro-error-attr" 762 | version = "1.0.4" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 765 | dependencies = [ 766 | "proc-macro2", 767 | "quote", 768 | "version_check", 769 | ] 770 | 771 | [[package]] 772 | name = "proc-macro2" 773 | version = "1.0.29" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" 776 | dependencies = [ 777 | "unicode-xid", 778 | ] 779 | 780 | [[package]] 781 | name = "quote" 782 | version = "1.0.9" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 785 | dependencies = [ 786 | "proc-macro2", 787 | ] 788 | 789 | [[package]] 790 | name = "radium" 791 | version = "0.6.2" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" 794 | 795 | [[package]] 796 | name = "regex" 797 | version = "1.5.4" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 800 | dependencies = [ 801 | "aho-corasick", 802 | "memchr", 803 | "regex-syntax", 804 | ] 805 | 806 | [[package]] 807 | name = "regex-syntax" 808 | version = "0.6.25" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 811 | 812 | [[package]] 813 | name = "rusb" 814 | version = "0.8.1" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "d9a5084628cc5be77b1c750b3e5ee0cc519d2f2491b3f06b78b3aac3328b00ad" 817 | dependencies = [ 818 | "libc", 819 | "libusb1-sys", 820 | ] 821 | 822 | [[package]] 823 | name = "scroll" 824 | version = "0.10.2" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" 827 | 828 | [[package]] 829 | name = "serde" 830 | version = "1.0.130" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 833 | dependencies = [ 834 | "serde_derive", 835 | ] 836 | 837 | [[package]] 838 | name = "serde_derive" 839 | version = "1.0.130" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 842 | dependencies = [ 843 | "proc-macro2", 844 | "quote", 845 | "syn", 846 | ] 847 | 848 | [[package]] 849 | name = "serde_yaml" 850 | version = "0.8.21" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" 853 | dependencies = [ 854 | "dtoa", 855 | "indexmap", 856 | "serde", 857 | "yaml-rust", 858 | ] 859 | 860 | [[package]] 861 | name = "serialport" 862 | version = "4.0.1" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "5d8cd7c0f22290ee2c01457009fa6fc1cae4153d5608a924e5dc423babc2c655" 865 | dependencies = [ 866 | "CoreFoundation-sys", 867 | "IOKit-sys", 868 | "bitflags", 869 | "cfg-if 0.1.10", 870 | "libudev", 871 | "mach 0.2.3", 872 | "nix 0.16.1", 873 | "regex", 874 | "winapi", 875 | ] 876 | 877 | [[package]] 878 | name = "sha2" 879 | version = "0.9.8" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" 882 | dependencies = [ 883 | "block-buffer", 884 | "cfg-if 1.0.0", 885 | "cpufeatures", 886 | "digest", 887 | "opaque-debug", 888 | ] 889 | 890 | [[package]] 891 | name = "stable_deref_trait" 892 | version = "1.2.0" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 895 | 896 | [[package]] 897 | name = "static_assertions" 898 | version = "1.1.0" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 901 | 902 | [[package]] 903 | name = "strsim" 904 | version = "0.8.0" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 907 | 908 | [[package]] 909 | name = "strsim" 910 | version = "0.10.0" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 913 | 914 | [[package]] 915 | name = "structopt" 916 | version = "0.3.23" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" 919 | dependencies = [ 920 | "clap", 921 | "lazy_static", 922 | "paw", 923 | "structopt-derive", 924 | ] 925 | 926 | [[package]] 927 | name = "structopt-derive" 928 | version = "0.4.16" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" 931 | dependencies = [ 932 | "heck", 933 | "proc-macro-error", 934 | "proc-macro2", 935 | "quote", 936 | "syn", 937 | ] 938 | 939 | [[package]] 940 | name = "svg" 941 | version = "0.10.0" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "e72d8b19ab05827afefcca66bf47040c1e66a0901eb814784c77d4ec118bd309" 944 | 945 | [[package]] 946 | name = "syn" 947 | version = "1.0.77" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" 950 | dependencies = [ 951 | "proc-macro2", 952 | "quote", 953 | "unicode-xid", 954 | ] 955 | 956 | [[package]] 957 | name = "tap" 958 | version = "1.0.1" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 961 | 962 | [[package]] 963 | name = "termcolor" 964 | version = "1.1.2" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 967 | dependencies = [ 968 | "winapi-util", 969 | ] 970 | 971 | [[package]] 972 | name = "terminal_size" 973 | version = "0.1.17" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 976 | dependencies = [ 977 | "libc", 978 | "winapi", 979 | ] 980 | 981 | [[package]] 982 | name = "textwrap" 983 | version = "0.11.0" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 986 | dependencies = [ 987 | "unicode-width", 988 | ] 989 | 990 | [[package]] 991 | name = "thiserror" 992 | version = "1.0.29" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" 995 | dependencies = [ 996 | "thiserror-impl", 997 | ] 998 | 999 | [[package]] 1000 | name = "thiserror-impl" 1001 | version = "1.0.29" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" 1004 | dependencies = [ 1005 | "proc-macro2", 1006 | "quote", 1007 | "syn", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "thousands" 1012 | version = "0.2.0" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" 1015 | 1016 | [[package]] 1017 | name = "toml" 1018 | version = "0.5.8" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 1021 | dependencies = [ 1022 | "serde", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "typenum" 1027 | version = "1.14.0" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" 1030 | 1031 | [[package]] 1032 | name = "unicode-segmentation" 1033 | version = "1.8.0" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1036 | 1037 | [[package]] 1038 | name = "unicode-width" 1039 | version = "0.1.9" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1042 | 1043 | [[package]] 1044 | name = "unicode-xid" 1045 | version = "0.2.2" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1048 | 1049 | [[package]] 1050 | name = "vcpkg" 1051 | version = "0.2.15" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1054 | 1055 | [[package]] 1056 | name = "vec_map" 1057 | version = "0.8.2" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1060 | 1061 | [[package]] 1062 | name = "version_check" 1063 | version = "0.9.3" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1066 | 1067 | [[package]] 1068 | name = "void" 1069 | version = "1.0.2" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1072 | 1073 | [[package]] 1074 | name = "winapi" 1075 | version = "0.3.9" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1078 | dependencies = [ 1079 | "winapi-i686-pc-windows-gnu", 1080 | "winapi-x86_64-pc-windows-gnu", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "winapi-i686-pc-windows-gnu" 1085 | version = "0.4.0" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1088 | 1089 | [[package]] 1090 | name = "winapi-util" 1091 | version = "0.1.5" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1094 | dependencies = [ 1095 | "winapi", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "winapi-x86_64-pc-windows-gnu" 1100 | version = "0.4.0" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1103 | 1104 | [[package]] 1105 | name = "wyz" 1106 | version = "0.4.0" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" 1109 | dependencies = [ 1110 | "tap", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "xmas-elf" 1115 | version = "0.8.0" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "8d29b4d8e7beaceb4e77447ba941a7600d23d0319ab52da0461abea214832d5a" 1118 | dependencies = [ 1119 | "zero", 1120 | ] 1121 | 1122 | [[package]] 1123 | name = "yaml-rust" 1124 | version = "0.4.5" 1125 | source = "registry+https://github.com/rust-lang/crates.io-index" 1126 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 1127 | dependencies = [ 1128 | "linked-hash-map", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "zero" 1133 | version = "0.1.2" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" 1136 | --------------------------------------------------------------------------------