From fc5643b0b5cb61a3473b221e8095292c098bf5b1 Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Sun, 7 Aug 2022 20:49:58 +1200 Subject: [PATCH 1/9] enable support for loader stubs (via --use-stub arg) --- Cargo.lock | 2 + espflash/Cargo.toml | 2 + espflash/src/cli/mod.rs | 19 ++++++--- espflash/src/connection.rs | 4 +- espflash/src/elf.rs | 2 +- espflash/src/flasher.rs | 66 ++++++++++++++++++++++++++++++- espflash/src/lib.rs | 2 + espflash/src/main.rs | 11 ++++-- espflash/src/stubs/mod.rs | 56 ++++++++++++++++++++++++++ stubs/README.md | 2 + stubs/stub_flasher_32.json | 7 ++++ stubs/stub_flasher_32c2.json | 7 ++++ stubs/stub_flasher_32c3.json | 7 ++++ stubs/stub_flasher_32c6beta.json | 7 ++++ stubs/stub_flasher_32h2beta1.json | 7 ++++ stubs/stub_flasher_32h2beta2.json | 7 ++++ stubs/stub_flasher_32s2.json | 7 ++++ stubs/stub_flasher_32s3.json | 7 ++++ stubs/stub_flasher_32s3beta2.json | 7 ++++ stubs/stub_flasher_8266.json | 7 ++++ 20 files changed, 222 insertions(+), 14 deletions(-) create mode 100644 espflash/src/stubs/mod.rs create mode 100644 stubs/README.md create mode 100644 stubs/stub_flasher_32.json create mode 100644 stubs/stub_flasher_32c2.json create mode 100644 stubs/stub_flasher_32c3.json create mode 100644 stubs/stub_flasher_32c6beta.json create mode 100644 stubs/stub_flasher_32h2beta1.json create mode 100644 stubs/stub_flasher_32h2beta2.json create mode 100644 stubs/stub_flasher_32s2.json create mode 100644 stubs/stub_flasher_32s3.json create mode 100644 stubs/stub_flasher_32s3beta2.json create mode 100644 stubs/stub_flasher_8266.json diff --git a/Cargo.lock b/Cargo.lock index 16660bd1..4fa9fbe9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -492,6 +492,7 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" name = "espflash" version = "1.6.1-dev" dependencies = [ + "base64", "binread", "bytemuck", "clap", @@ -510,6 +511,7 @@ dependencies = [ "regex", "serde", "serde-hex", + "serde_json", "serde_plain", "serialport", "sha2", diff --git a/espflash/Cargo.toml b/espflash/Cargo.toml index 0e51fa3e..6d94ab28 100644 --- a/espflash/Cargo.toml +++ b/espflash/Cargo.toml @@ -29,6 +29,7 @@ bin-dir = "{ bin }{ binary-ext }" pkg-fmt = "zip" [dependencies] +base64 = "0.13.0" binread = "2.2" bytemuck = { version = "1.11", features = ["derive"] } clap = { version = "3.2", features = ["derive"] } @@ -47,6 +48,7 @@ parse_int = "0.6" regex = "1.6" serde = { version = "1.0", features = ["derive"] } serde-hex = "0.1" +serde_json = "1.0.83" serde_plain = "1.0" serialport = "4.2" sha2 = "0.10" diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 5335313c..ab22291e 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -31,16 +31,21 @@ pub mod monitor; mod serial; -#[derive(Parser)] +#[derive(Parser, Debug)] pub struct ConnectOpts { /// Serial port connected to target device pub serial: Option, + /// Baud rate at which to flash target device #[clap(long)] pub speed: Option, + + /// Use RAM stub for loading + #[clap(long)] + pub use_stub: bool, } -#[derive(Parser)] +#[derive(Parser, Debug)] pub struct FlashOpts { /// Load the application to RAM instead of Flash #[clap(long)] @@ -56,7 +61,7 @@ pub struct FlashOpts { pub monitor: bool, } -#[derive(Parser)] +#[derive(Parser, Debug)] pub struct FlashConfigOpts { /// Flash mode to use #[clap(short = 'm', long, possible_values = FlashMode::VARIANTS, value_name = "MODE")] @@ -69,7 +74,7 @@ pub struct FlashConfigOpts { pub flash_freq: Option, } -#[derive(Parser)] +#[derive(Parser, Debug)] pub struct PartitionTableOpts { /// Convert CSV parition table to binary representation #[clap(long, required_unless_present_any = ["info", "to-csv"])] @@ -87,13 +92,15 @@ pub struct PartitionTableOpts { output: Option, } -#[derive(Parser)] +#[derive(Parser, Debug)] pub struct WriteBinToFlashOpts { /// Address at which to write the binary file #[clap(value_parser = parse_u32)] addr: u32, + /// File containing the binary data to write bin_file: String, + #[clap(flatten)] connect_opts: ConnectOpts, } @@ -131,7 +138,7 @@ pub fn connect(opts: &ConnectOpts, config: &Config) -> Result { _ => unreachable!(), }; - Ok(Flasher::connect(serial, port_info, opts.speed)?) + Ok(Flasher::connect(serial, port_info, opts.speed, opts.use_stub)?) } pub fn board_info(opts: ConnectOpts, config: Config) -> Result<()> { diff --git a/espflash/src/connection.rs b/espflash/src/connection.rs index aaf9ed25..f8da35d0 100644 --- a/espflash/src/connection.rs +++ b/espflash/src/connection.rs @@ -86,7 +86,7 @@ impl Connection { Err(Error::Connection(ConnectionError::ConnectionFailed)) } - fn sync(&mut self) -> Result<(), Error> { + pub(crate) fn sync(&mut self) -> Result<(), Error> { self.with_timeout(CommandType::Sync.timeout(), |connection| { connection.write_command(Command::Sync)?; connection.flush()?; @@ -254,7 +254,7 @@ impl Connection { Ok(()) } - fn read(&mut self, len: usize) -> Result>, Error> { + pub(crate) fn read(&mut self, len: usize) -> Result>, Error> { let mut tmp = Vec::with_capacity(1024); loop { self.decoder.decode(&mut self.serial, &mut tmp)?; diff --git a/espflash/src/elf.rs b/espflash/src/elf.rs index 35bd43fd..21b1814a 100644 --- a/espflash/src/elf.rs +++ b/espflash/src/elf.rs @@ -21,7 +21,7 @@ use crate::{ pub const ESP_CHECKSUM_MAGIC: u8 = 0xef; -#[derive(Copy, Clone, EnumVariantNames)] +#[derive(Copy, Clone, Debug, EnumVariantNames)] #[strum(serialize_all = "UPPERCASE")] pub enum FlashMode { Qio, diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index 6fe19ee0..3340b973 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -11,7 +11,7 @@ use crate::{ elf::{ElfFirmwareImage, FirmwareImage, FlashFrequency, FlashMode, RomSegment}, error::{ConnectionError, FlashDetectError, ResultExt}, image_format::ImageFormatId, - Error, PartitionTable, + Error, PartitionTable, stubs::FlashStub, }; const DEFAULT_TIMEOUT: Duration = Duration::from_secs(3); @@ -192,6 +192,7 @@ impl Flasher { serial: Box, port_info: UsbPortInfo, speed: Option, + use_stub: bool, ) -> Result { // Establish a connection to the device using the default baud rate of 115,200 // and timeout of 3 seconds. @@ -209,6 +210,13 @@ impl Flasher { flash_size: FlashSize::Flash4Mb, spi_params: SpiAttachParams::default(), }; + + // Load flash stub if enabled + if use_stub { + println!("Using flash stub"); + flasher.load_stub()?; + } + flasher.spi_autodetect()?; // Now that we have established a connection and detected the chip and flash @@ -228,11 +236,65 @@ impl Flasher { Ok(flasher) } + /// Load flash stub + fn load_stub(&mut self) -> Result<(), Error> { + + println!("Loading flash stub for chip: {:?}", self.chip); + + // Load flash stub + let stub = FlashStub::get(self.chip).unwrap(); + + let mut ram_target = self.chip.ram_target(Some(stub.entry())); + ram_target.begin(&mut self.connection).flashing()?; + + let (text_addr, text) = stub.text(); + println!("Write {} byte stub text", text.len()); + + ram_target.write_segment( + &mut self.connection, + RomSegment { + addr: text_addr, + data: Cow::Borrowed(&text), + }, + ) + .flashing()?; + + + let (data_addr, data) = stub.data(); + println!("Write {} byte stub data", data.len()); + + ram_target.write_segment( + &mut self.connection, + RomSegment { + addr: data_addr, + data: Cow::Borrowed(&data), + }, + ) + .flashing()?; + + println!("Finish stub write"); + ram_target.finish(&mut self.connection, true).flashing()?; + + println!("Stub written..."); + + // Re-sync connection + self.connection.sync()?; + + // Re-detect chip to check stub is up + let magic = self.connection.read_reg(CHIP_DETECT_MAGIC_REG_ADDR)?; + let chip = Chip::from_magic(magic)?; + println!("Re-detected chip: {:?}", chip); + + Ok(()) + } + fn spi_autodetect(&mut self) -> Result<(), Error> { // Loop over all available SPI parameters until we find one that successfully // reads the flash size. for spi_params in TRY_SPI_PARAMS.iter().copied() { - self.enable_flash(spi_params)?; + if let Err(_e) = self.enable_flash(spi_params) { + continue; + } if let Some(flash_size) = self.flash_detect()? { // Flash detection was successful, so save the flash size and SPI parameters and // return. diff --git a/espflash/src/lib.rs b/espflash/src/lib.rs index 983258e8..5816ffb1 100644 --- a/espflash/src/lib.rs +++ b/espflash/src/lib.rs @@ -19,3 +19,5 @@ pub mod partition_table; #[doc(hidden)] pub mod cli; + +pub mod stubs; diff --git a/espflash/src/main.rs b/espflash/src/main.rs index ae5c1e22..50636db8 100644 --- a/espflash/src/main.rs +++ b/espflash/src/main.rs @@ -12,25 +12,30 @@ use espflash::{ use miette::{IntoDiagnostic, Result, WrapErr}; use strum::VariantNames; -#[derive(Parser)] +#[derive(Debug, Parser)] #[clap(version, propagate_version = true)] struct Opts { /// Image format to flash #[clap(long, possible_values = &["bootloader", "direct-boot"])] pub format: Option, + #[clap(flatten)] pub flash_config_opts: FlashConfigOpts, + #[clap(flatten)] flash_opts: FlashOpts, + #[clap(flatten)] connect_opts: ConnectOpts, + /// ELF image to flash image: Option, + #[clap(subcommand)] subcommand: Option, } -#[derive(Parser)] +#[derive(Debug, Parser)] pub enum SubCommand { /// Display information about the connected board and exit without flashing BoardInfo(ConnectOpts), @@ -44,7 +49,7 @@ pub enum SubCommand { WriteBinToFlash(WriteBinToFlashOpts), } -#[derive(Parser)] +#[derive(Debug, Parser)] pub struct SaveImageOpts { #[clap(flatten)] pub flash_config_opts: FlashConfigOpts, diff --git a/espflash/src/stubs/mod.rs b/espflash/src/stubs/mod.rs new file mode 100644 index 00000000..38a87031 --- /dev/null +++ b/espflash/src/stubs/mod.rs @@ -0,0 +1,56 @@ +use serde::{Serialize, Deserialize}; + +use crate::Chip; + + +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct FlashStub { + entry: u32, + text: String, + text_start: u32, + data: String, + data_start: u32, +} + +const STUB_32: &str = include_str!("../../../stubs/stub_flasher_32.json"); +const STUB_32C2: &str = include_str!("../../../stubs/stub_flasher_32c2.json"); +const STUB_32C3: &str = include_str!("../../../stubs/stub_flasher_32c3.json"); +const STUB_32S2: &str = include_str!("../../../stubs/stub_flasher_32s2.json"); +const STUB_32S3: &str = include_str!("../../../stubs/stub_flasher_32s3.json"); +const STUB_8266: &str = include_str!("../../../stubs/stub_flasher_8266.json"); + +impl FlashStub { + /// Fetch flash stub for the provided chip + pub fn get(chip: Chip) -> Result { + let s = match chip { + Chip::Esp32 => STUB_32, + Chip::Esp32c2 => STUB_32C2, + Chip::Esp32c3 => STUB_32C3, + Chip::Esp32s2 => STUB_32S2, + Chip::Esp32s3 => STUB_32S3, + Chip::Esp8266 => STUB_8266, + }; + + let stub: FlashStub = serde_json::from_str(s) + .map_err(|_| () )?; + + Ok(stub) + } + + /// Fetch stub entry point + pub fn entry(&self) -> u32 { + self.entry + } + + /// Fetch text start address and bytes + pub fn text(&self) -> (u32, Vec) { + let v = base64::decode(&self.text).unwrap(); + (self.text_start, v) + } + + /// Fetch data start address and bytes + pub fn data(&self) -> (u32, Vec) { + let v = base64::decode(&self.data).unwrap(); + (self.data_start, v) + } +} diff --git a/stubs/README.md b/stubs/README.md new file mode 100644 index 00000000..d3d6e4ae --- /dev/null +++ b/stubs/README.md @@ -0,0 +1,2 @@ + +Flasher stubs from https://github.com/espressif/esptool/tree/master/esptool/targets/stub_flasher diff --git a/stubs/stub_flasher_32.json b/stubs/stub_flasher_32.json new file mode 100644 index 00000000..37b9ae2f --- /dev/null +++ b/stubs/stub_flasher_32.json @@ -0,0 +1,7 @@ +{ + "entry": 1074521516, + "text": "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", + "text_start": 1074520064, + "data": "CMD8Pw==", + "data_start": 1073605544 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32c2.json b/stubs/stub_flasher_32c2.json new file mode 100644 index 00000000..988dea7c --- /dev/null +++ b/stubs/stub_flasher_32c2.json @@ -0,0 +1,7 @@ +{ + "entry": 1077413328, + "text": "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", + "text_start": 1077411840, + "data": "DEDKPw==", + "data_start": 1070295976 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32c3.json b/stubs/stub_flasher_32c3.json new file mode 100644 index 00000000..125df7ec --- /dev/null +++ b/stubs/stub_flasher_32c3.json @@ -0,0 +1,7 @@ +{ + "entry": 1077413488, + "text": "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", + "text_start": 1077411840, + "data": "DEDIPw==", + "data_start": 1070164904 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32c6beta.json b/stubs/stub_flasher_32c6beta.json new file mode 100644 index 00000000..730bd23f --- /dev/null +++ b/stubs/stub_flasher_32c6beta.json @@ -0,0 +1,7 @@ +{ + "entry": 1077413328, + "text": "ARG3BwBgSsgDqYcAJspOxlLEBs4izLcEAGD9WTdKyD/ATBN09D8N4PJAYkQjqCQBsknSREJJIkoFYYKAiECDJwoAE3X1D4KXfRTjGTT/yb83JwBgfEudi/X/NzcAYHxLnYv1/4KAQREGxt03tycAYCOmBwI3BwAImMOYQ33/yFeyQBNF9f8FiUEBgoBBEQbG2T993TcHAEC3JwBgmMM3JwBgHEP9/7JAQQGCgEERIsQ3RMk/kwfECZxLBsYmwqHPXTcxyRMExAkYSL1HgURj1ucABES9iJO0FABNP5U/HEQ3BwABE5bHAGN/5gC3BoAAmeC3BgABNycAYFDDFMO3JgBgmEJ9/0FHkeAFRxRIupccxJmOFMiyQCJEkkRBAYKAEwcADJxBYxvlAIHnhUecwSGoI6AFAPlXPoWCgAVHY4fnAIlGY43XAP1X/beTFwUBEwewDcGH4xHl/olHyb+TB8ANYxb1AJjBkwcADPG3kwbQDf1X4xLV/JjBkwewDW2/t0XJP0ERk4VFCQbGUT9jSQUGt0fJP5OHxwCDpgcIA9dHCBN19Q9CB0GDEwYXAEIGQYIjkscINpcjAKcAA9dHCJFnk4cHBEIHQYNjHvcCN8fIPxMHxwChZ7qXA6YHCLcGyT+3R8k/k4fHAJOGxgRjH+YAI6bHCCOg1wgjkgcIIaD5V+MG9fyyQEEBgoAjptcII6DnCN23AREizDdEyT+TB8QJJsrERwbOSshOxhMExAlj85UAroS5wAMpRACqiSaZE1nJABxIY1XwABxEY1/5Ahk9fd1IQCaGzoWXAMj/54Dg7BN19Q8BxZMHQAxcyFxAppdcwFxEs4SXQETE8kBiRNJEQkmySQVhgoANNWW/AREGziLMdTs3BM4/bAATBUT/lwDI/+eAgOuFRxXlskeT9wcgPsbhOzcnAGAcR7cGQAATBUT/1Y8cx7JFlwDI/+eAIOmzN6AA8kBiRD6FBWGCgEERt0fJPwVHBsYjjucIk4fHCRPXxQCYxwVnfRfMw8jH+Y06laqVsYGMyyOqBwBBNxnBEwVQDLJAQQGCgEERBsYTBwAMYxDlAhMFsA2XAMj/54AA0xMFwA2yQEEBFwPI/2cAA9ITB7AN4xjl/pcAyP/ngADREwXQDcW3QREixCbCBsYqhLMEtQBjF5QAskAiRJJEQQGCgANFBAAFBEU37bd1cUrBfXMFaSLFJsPO3tLc1toGx310GpGTBwkHipcTBIT6PpSqiSKFroSXAMj/54BgJpMHCQcFaoqXs4pHQbngBWeTBwcHfXSTBYT6ipcTBIT5PpSTBwcHipe+lSKFlwDI/+eAoCMihcFFhT8BRQVjGpG6QCpEmkQKSfZZZlrWWklhgoAmiWNzmgAFaUqG1oVOhZcAyP/ngKDRE3X1DwHtSobWhSKFlwDI/+eA4B7KmbOEJEFptxMFMAZVvxMFAAwXA8j/ZwDDwXFxfXNWy1rJXsdixQbXItUm00rRTs9SzWbDasHu3qqKGpETBQACLouyizaMAsKXAMj/54DgGIVnY+d3E4VkfXSThwQHipcTBIT6PpQihZcAyP/ngKAXfXqThwQHipeTDDr5vpyThwQHEw2K+YqXAUk+nYVnk4cHB4qXs4RHAYOtRPlj9G0LY3G5A0WgpTfOhSaFQTWFN06GpoUihZcAyP/ngAATzppOmWN2aQOzB7lBY/KHA7MHK0HeiWPzdwG+iU6GpoVWhZcAyP/ngODBE3X1D03dhWeThwcHipezhEcBI6wE+IFJjU2jiQT4ZoWXAMj/54Dgsn35A8U0+eqF6T5jTwUA4+I9/4Vnk4cHB4qXM4c3AVKXIwqn+IUJ8bf5V+MU9fwRR+OG6fQFZ5MHBwd9dJMFhPqKlxMEhPk+lJMHBweKl76VIoWXAMj/54CACFU1IoXBRXU7cT0TBQAClwDI/+eAIAYFYxqRulAqVJpUCln6SWpK2kpKS7pLKkyaTApN9l1NYYKAt1dBSRlxk4f3hAFFPs6G3qLcptrK2M7W0tTW0trQ3s7izObK6sjuxpcAyP/ngACst0fIPzd3yT+ThwcAEweHumPm5xQlNZFFaAiBMwU1t8fIP5OHxwAhZz6XIyD3CLcFOEC3BzhAk4cHGAFGk4UFADdKyD8VRSMg+gCXAMj/54Bg+zcHAGBcRxMFAAK3Ssk/k+cXEFzHlwDI/+eAIPqXAMj/54CgCrdHAGCcX5OKygATCgoAEeUT9ccBYRUTNRUAgUWXAMj/54DgrMFnN0vJP/0XEwcAEIVmQWa3BQABAUWTCcsJjWs3TMg/lwDI/+eAYKfOm5MMzACDp8oI9d+DpMoIhUcjpgoIIwLxAoPHFAAJRyMT4QKjAvECAtRNR2OL5wZRR2OJ5wYpR2Oe5wCDxzQAA8ckAKIH2Y8RR2OV5wCcRJxDPtQdM6FFSBA9OQPHNACDxyQAkWYiB12Pk4cGAWP+5wITBbANlwDI/+eAQJITBcANlwDI/+eAgJETBeAOlwDI/+eAwJDVMb23I6AHAJEHfbXJRyMT8QJ1t4PHFAA1RmOPxyxjYfYQGUZjjsc2Y2L2CA1GY4XHGGNs9gQJRmOAxygBSRME8A8TdfQPvT4TdfkPpT5ZOeMQBPKDxxQAPUdji+dEY233NhFHY4TnVBlHY4XnVg1H45Dn8IPFNACDxyQAE4WEAaIF3Y3BFSU85bWRRmOI1ySVRuOV1/rBRwVFYxX3EJxE2EgjJPoAIyLqAHWipUZjgNcmY+/2Ap1GY4zXKKFG45/X9pMHQAJjE/ceAtQdRAFFlwDI/+eAQIMBRe00ITEZMaFFSBB9FDE+ffABSQFEkb+pRmON1yStRuOS1/ThR2Ma9x7cTJhM1EiQSMxEiESXAMj/54CgjCqJMzWgACqEFbfRRmOA1w5j7fYExUZjhtcIY+r2Ar1GY4jXFsFG45DX8AVEYx73DJxIEWdja/cmwETMSIhEM4SHAgU8I6wJACOki7DxoMlGY4vXFs1G45jX7MFHBURjFfcKzESIRHU0RaiTBiANY4jXEmPg9gKTBgANY4nXCJMGEA3jktfqoUdjC/cIBUUqhKWokwYwDWOE10STBkAN45TX6INHywljjwcYnERBFwOkSQFjhOcAEwQADIFHkwbwDmPM5w4Dx1QAg8dEAAFJIgddj4PHZADCB12Pg8d0AOIH2Y/jhfbkEwQQDIm1BUQJ73AQgUUBRZewzP/ngOCACeXRRWgQ5TIBRAFJDbUFRG3/l/DH/+eA4HkzNKAA9bcDrYQAwESzZ40AE5dHASXzzTgx/UFpIp19Gf19MwWNQBnoAUWxtzGBl/DH/+eAAHcd/W6U5bezdyUB9fdBaTMFjUBjbokAfXkzBY1AedgxgZfwx//ngIB0GflKlPW3QYGX8Mf/54BAc+MTBfAzBCRB+behR+MB9+QBSRMEAAxBu8FHzb/BRwVE4xH39pxIY+/2DsxIiER9OI23M4b0AANGhgGFB7GO9b2DR8sJrc+Dp8kA7eMjDgsIA6RJAT23AUkFRR21kUcFReMU9+qIRIFFl/DH/+eAQHCpt5N39wDJ/xNdRwAThIQAAUn9XeN1qd1IRJfwx//ngGBcHERYQBRAfY9jh7cBkEKTx/f/8Y9dj5jCBQlBBNm/kUepv4MlSgBBF5HlAc8BSRMEYAzNsYMnigBj5ecGk3c3AJ3/AyiKAAFGgUczBfhAs4b1AGPp5wDjAwbWIyLaACMkqgCpuzOG9AAQTpEHkMIFRum/oUcFReMQ9+ADJIoAGcATBIAMIyQKACMiCgAzNYAA3bMBSRMEIAy1uQFJEwSADJW5AUkTBJAMtbFJR2OJ5xxjYvcERUfjlue4g8c0AAPHJAAThIQBogfZj5ONB/8FSYOnyQBjhQ0AmcNjRCARY1cJGBMHcAwjqukA45wHtJMHkAxZohMHIA1ji+cMEwdADeOR57QDxDQAg8ckACIEXYyX8Mf/54DgVwOpyQBBFGNzJAEiieMPCbADpEkASpQxgIOnCQFjVvAAg6eJAGNQ9Arv8A/Kdd0DpUkASoaThYQBl/DH/+eAYFMJxZMHQAwjqvkAg6dJAMqXI6L5AIOnyQAziSdBI6YpAZfwx//ngKBRybQJZRMFBXEDqcQAgESX8Mf/54AAQ7cHAGDYS7cGAAHBFpNXRwESB3WPvYvZj7OHJwMBRbPVhwKX8Mf/54DgQxMFgD6X8Mf/54CgP5281EiQSMxEiETv8M/+pbTv8K/Egb+3dsk/A6eGurfHyD+Th8cAmY8+1oOni7A3fck/btATDc0Jk4SGugVIY/P9AA1IQsY6xO/wL8EiRzJIN0XJP6KFfBCTBswAEBATBUULl/DH/+eAwEOCVwMnjbCMQLON/UAdjz6UslcjJO2wKom+lYzAkwfMAJ2NAcWhZ+Oa9eZmhe/w79IjoJQBnbXjHwnm44kHnJMHgAwjqvkA2bKcROORB5wBRZfwx//ngIA2CWUTBQVxl/DH/+eAoDKX8Mf/54AgNnm6wETjDQSYAUWX8Mf/54AANBMFgD6X8Mf/54BAMAKUvbr2UGZU1lRGWbZZJlqWWgZb9ktmTNZMRk22TQlhgoAAAA==", + "text_start": 1077411840, + "data": "DEDIPw==", + "data_start": 1070164904 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32h2beta1.json b/stubs/stub_flasher_32h2beta1.json new file mode 100644 index 00000000..bfb62c03 --- /dev/null +++ b/stubs/stub_flasher_32h2beta1.json @@ -0,0 +1,7 @@ +{ + "entry": 1077413328, + "text": "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", + "text_start": 1077411840, + "data": "DEDIPw==", + "data_start": 1070164904 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32h2beta2.json b/stubs/stub_flasher_32h2beta2.json new file mode 100644 index 00000000..4ab15211 --- /dev/null +++ b/stubs/stub_flasher_32h2beta2.json @@ -0,0 +1,7 @@ +{ + "entry": 1077413328, + "text": "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", + "text_start": 1077411840, + "data": "DEDIPw==", + "data_start": 1070164904 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32s2.json b/stubs/stub_flasher_32s2.json new file mode 100644 index 00000000..288eb717 --- /dev/null +++ b/stubs/stub_flasher_32s2.json @@ -0,0 +1,7 @@ +{ + "entry": 1073907552, + "text": "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", + "text_start": 1073905664, + "data": "CAD9Pw==", + "data_start": 1073622004 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32s3.json b/stubs/stub_flasher_32s3.json new file mode 100644 index 00000000..0fe3f533 --- /dev/null +++ b/stubs/stub_flasher_32s3.json @@ -0,0 +1,7 @@ +{ + "entry": 1077381512, + "text": "FIADYACAA2CsK8s/BIADYDZBAIH7/wxJwCAAmQjGBAAAgfj/wCAAqAiB9/+goHSICOAIACH2/8AgAIgCJ+jhHfAAAAAIAABgHAAAYAAAAGAQAABgNkEAIfv/wCAAOAJB+v/AIAAoBCAglJziBgUAAABB9v+B5f/AIACoBIgIoKB04AgACyJmAueG9P8h8f/AIAA5Ah3wAABUIABgVDAAYDZBAJH9/8AgAIgJgIAkVkj/kfr/wCAAiAmAgCRWSP8d8AAAACwgAGAAIABgAAAACDZBAOX8/yH7/wwIwCAAiQKR+/+B+f/AIACSaADAIACYCFZ5/8AgAIgCfPKAIjAgIAQd8AAAAABANkEAZfz/Fpr/ge3/kfz/wCAAmQjAIACYCFZ5/x3wAACQAMs/CIDKP4CAAACEgAAAQEAAAEjAyj+UAMs/NkEAsfj/IKB0pRMBluoFgfb/kfb/oKB0kJiAwCAAsikAkfP/kIiAwCAAkhgAkJD0G8nAwPTAIADCWACam8AgAKJJAMAgAJIYAIHq/5CQ9ICA9IeZRoHk/5Hl/6Ho/5qYwCAAyAmx5P+HnBlGAgB86Ica4UYJAAAAwCAAiQrAIAC5CUYCAMAgALkKwCAAiQmR2P+aiAwJwCAAklgAHfAAAOgIAED0CABAuAgAQDaBAAxLDBqB+//gCAAsBwYRAAxLDBqB+P/gCABwVEMMCAwW0JUR7QKJQYkxmSE5EYkBLA8MjRwsDEutBmlhaVGB7//gCAAMS60Gger/4AgAWjNaIlBEwOYUtwwCHfAAADaBAAxLDBqB4//gCAAcBgYMAAAAYFRDDAgMGtCVEQyNOTHtAolhqVGZQYkhiRHZASwPDMwMS4HZ/+AIAFBEwFozWiLmFM0MAh3wAAAUKABANkEAIKIggf3/4AgAHfAAAFwHAEA2QQCB/v/gCAAiChgMGSLC/QwIIImDLQgd8AAANkEAgff/4AgAIgoYDBkiwvwMCCCJgy0IHfAAAAAAAgC8/84/iCYAQIQbAECUJgBAkBsAQDZBAOX6/6xqMfn/Qff/jLKoA4H3/+AIAK0EBgkArQSB9f/gCACoA4H0/+AIAEYIAKX5/4Ht/zKgIKCDg4CoIBaSAIHu/+AIAIYBAACB6v/gCAAd8PAryz+wK8s/KCYAQDZBACH8/4Hh/8gCqAix+v+B+//gCAAMCIkCHfCQBgBANkEA5fL/FqoAgfL/gigAjBjl/P9l8/8WGgAMSoH4/+AIAB3wSAYAQDZBAGXw/xZKA5Ho/4IpAKLIAakJkef/DAqKmSJJAILIwQwZgKmDoIB0zIiir0CqIiCJg5yYJfj/BgUAAAAAIKIgge7/4AgA5e3/FioApfj/HfAAADZBAIKgwK0Ch5INoqDb5fn/oqDcRgMAAACCoNuHkgXl+P+ioN1l+P8d8AAANkEAOjIGAgAAogIAGyJl/P83kvQd8AAANkEAoqDAJfb/HfAAqCvLP6Qryz9AJgBANCYAQNAmAEA2YQB8yK0Ch5MtMaD/xgUAAKgDDBy9AYH3/+AIAIHh/qIBAIgI4AgAqAOB8//gCADmGt3GCgAAAGYDJgwDzQEMKzJhAIHu/+AIAJgBgej/N5kNqAhmGggx5v/AIACiQwCZCB3wAACAAAAAAAGYAMs/////AAQgAGAMCQBAAAkAQDZBADH6/yIjBBYSCeW9/xa6CIhDDPkMAoepDoIjApCIEJKgAYApgyAgdKW//+W4/7gjke//QIsRh7ksnJL7K7CyowxMAAxAsLCxDBqB6//gCAAcAkYOAAAMTAwagej/4AgADBJGCgAAkd//zBKR3v+h4f/AIACJCoHb/sAgAJkIwCAAmAhWef8cCQwYIImTLQiIQyCIwIlDiCMqKCkjHfAUCgBANmEAQdH/WDRQM2MWkwtYFFpTUFxBhgAAJfT/aESmFgRoJGel8iWy/xaa/3gUYcf/MFeAV7ZtsqAEDBqBCP/gCABwUHSSoQBQacBnswjNA70CrQcGDwBgxiAgsiBwpyBS1f+ZETpVJcD/UFhBDAgGBQCQySCCYQCZEeW+/4gBYtYBG4iAgHSYEWqnYLKAVzjgYMPAZb3/DEsMGoHw/uAIAIYFAADNA70CrQeB1P/gCACgoHSMOiKgxClUKBQ6IikUKDQwMsAyZAMd8AAAcOL6PwggAGAAAEAAvAoAQMgKAEA2YQBlo/8x+f8QsSAwoyCB+v/gCABNCgwS7LqIAZKiAJCIEIkBpaf/kfL/ofL/wCAAiAmgiCDAIACJCbgBrQOB7//gCACgJIMd8AAA/w8AADZBAIGF/5KgAZJIADCcQZJoApH6/zJoASk4MDC0miIqMzA8QQwCKVg5SGX4/y0KjBoioMUd8AAAABAAAFgQAABcHABAIAoAQGgcAEB0HABANiEhotEQgfr/4AgAhg4AAFH2/5Fu/1BDYzqCzQS9ASCiIIe5ByWy/8YBAAAAgfH/4AgAoKB0/CrNBL0BotEQge7/4AgASiJAM8BWI/yh5/+y0RAaqoHp/+AIAKHk/xwLGqolzP8tAwYBAAAAIqBjHfAAAABsEAAAaBAAAHAQAAB4EAAAdBAAAGAGAEA2QSFh+/8aZlkGDAVi0RBQpSBSZhqltf9x0f9HtwIGPwCtBoHQ/+AIAIHy/3Hv/xqIepGZCMYtAFBzwKFB/3B0YzqCzQe9AYe6CSCiIOWm/wYCAACtAoHE/+AIAKCgdJxaDAiCZhZ9CJHk/4Hg/xqZiqGpCYYNAABlw/9wtyCtAWXB/+XC/80HELEgYKYggbf/4AgAeiJ6VTe1xYHV/3ImGhqIiAhwdcCHN4yG7P+SoACSRmyR0P8QmYCiKQCBz//gCABW2v6xpv+iBmwau2WiAPfqE/ZHEIHI/xqIiAh6mKJJABt3RvH/fOmXmsBmRwhyJho3twJ3tZ6hmf9gtiAQqoCBm//gCABluv+hlf+yoBAaqmW4/6W5/wwaZaX/HfAAAMo/T0hBSfQryz9EgTdAmCAMYKCCN0BkhDdACAAIYIAhDGAQgDdAEIADYFSAN0AMAABgOEAAYP//AAAAAAEAAAAABBAnAAAsgQBgAAAAgIyAAAAQQAAAAAD//wBAAAAAAMo/BADKPxQAAGDw//8A9CvLPwgAyj+wAMs/gAcAQHgbAEC4JgBAZCYAQHQfAEDsCgBAUAoAQAAGAEAcKQBAJCcAQAgoAEDkBgBAdIEEQJwJAED8CQBACAoAQKgGAECECQBAbAkAQJAJAEAoCABA2AYAQDbhACHL/wwKImEMQqAAgeb/4AgAIcb/Mcf/xgAASQJLIjcy+GWp/wxLosEwZaf/5aj/Qdz9Idz9McD/KiTAIABJAiGP/TkCZY7/LQoWCgYhRv7Bnf6oArKgAoGf/uAIADG3/7G3/xwaDAzAIACpA4HP/+AIAKE7/lKgAYE//uAIALGw/6gCgcr/4AgAqAKBN/7gCACoAoHH/+AIADGr/8AgACgDUCIgwCAAKQMGGAAAZYn/FuoCMaX/oqARsaX/wCAAomMAzQKBuf/gCAAxof8MRcAgACgDoSP+UCIgwCAAKQMGCQCxnP+gyiCioAWBr//gCAAxmv9SoQHAIAAoA6KgIFAiIMAgACkDgRv+4AgAgar/4AgAIZL/wCAAKALMuhzDMCIQIsL4DBMgo4MMC4Gj/+AIAPGL/9EM/8GL/7GL/+KhAAwKgZ7/4AgAIYz/UX7+KkRi1StGFgAAAACBW/7AIAAyCAAwMHQWcwSh/v3AIAAiSACB/v3gCAChff+Bkf/gCACBkf/gCABxev986MAgADgHoXn/gDMQwCAAOQeBi//gCACBiv/gCAAgoiCBif/gCADAIAAoBBYC+gwHwCAAOAQMEsAgAHkEIkEkIgMBDCh5oSJBJYJRExw3dxIiHEd3Eh9mkh8iAwNyAwKAIhFwIiBmQhAoI8AgACgCKaEGAQAcIiJRE2WL/wyLosEkZYn/sgMDggMCIVr/gLsRgIsgICD0h7IRoqDA5YT/oqDuZYT/pYj/ht7/cgMBDNInlwJG1gB3MllmZwIGEQH2dyNmNwJGpgD2RwpmJwIGigAGKwAAAGZHAka5AGZXAkbsAMYmAAAMkieXAsbNAHcyEGZ3AsbtAGaHAkYjAAYgAAAAZpcCRt8ADLInlwJGtQBGGwAcQieXAoYpAHcyLxwSJ5cCxo4AdzIQDPInlwKGZgBmtwLGewCGEQAcIieXAsafABwyJ5cCRmYAxgwAACKg0ieXAoZhAHcyFCKg0CeXAoYhACKg0SeXAoYkAEYEACKg0yeXAkZ9ASKg1CeXAgZ4AAwHIqD/BucAAAAsSQwHIqDAlxgCRuMALQd5oQx3IKIgpXT/IKIgJXT/JXj/JXj/sqAIosEkC3fldf9W9/1GRQAAIqABVrg1gLgggKggwsEQgR7/4AgAjQpWejS9B6LBEIJhEyVz/8avAAwSVkgzgmETgRf/4AgAgiETRlcAACaIBAwSBscAeCMoMyCHIICAtFbY/uWT/1Z6/sYLAACB6P1wrEF3uBe9CgxMDBqB5/3gCACGAwAi0vBy1xBGAwCBBP/gCAAW2v6G7f8AAMwSxpUAcJD0Vln8xgwAkdj9cKD1d7kevQrCoASioAGB1v3gCADGBAAAkeD+miKR1/6ad8YCAIH0/uAIABaa/obc/4HS/ic4xSonxgoAgcn9cKxBd7gWvQoMTAwagcj94AgARgMActcQRgMAAACB5v7gCAAW6v7Gzv8nl9BGdwAMByKgwCaIAoaTAAwHLQfGkQAmuPXGaQAioAEmuAKGjQCyIwOiIwLlj/+GCAAAIqABJrgCBogAkb3+giMEcqAAIqDCh7kCBoQAuFOoI6WI/wwXDAKgJ5NGfwAAIqABJrgCxnwAgiMEkbH+cqAAIqDCh7kCxngAKDO4U6gjICiCZYX/cZv9DAiJZ3LXKyknDBKgKINGcACRlv0MB6IJACKgxneaAoZsAChZmCOyyPCwmcCCoMCQKJOSoO9GAgB6g4IIGBt3gJkwtyfycgMFggMEgHcRgHcgggMGAIgRcHggggMHgIgBcIgggJnAgqDBDAeQKJPGWACBfv0ioMaSCAB9CRZZFZg4DAcioMh3GQIGUgCSSAAoWIZPAAAciQwHDBKXGALGTAD4c+hj2FPIQ7gzqCOBjf7gCAB9CgwKcCqDxkUAAAAMEiZIAsZCAKgjDAuBhP7gCAAGIQAAgKA0DAcioMB3GgJGPACAhEGLk30KfPvGDwCoOYJhE5JhErJhEYF6/uAIAJIhEoIhEygpqBnCKQCgohCyIREmAg7AIADSLAAgKzDQIhAgqiDAIACpDBt3kskQhze8BpT/ZkgChpL/DAcioMBGJAAMEia4AsYhACFY/ohTeCOJAiFX/nkCDAIGHQDBU/4MB9gMssjwDBKNB9CCg7AngyCIECKgxneYWZFN/iKgyegJtz5OsKAUIqDAd5pFLQoMH0YCACpzeGdLInkKjQ8gfsAqrbcy7Rao3akMeQnGdP8ADBJmiBpxPv4oBxYiACKgyAwKqQdxOf6pBwwXIKeTLQoMByCgdCU8/3CgdKU7/6U//1bSrnIDAYKgD4cXPnc4FGZHAgZ7AGZnAsaAACY3Asaz/gYgABwiJ5cCRnUAdzIKHBInlwJGPgCGrf4ioNInF1IioNQnF3bGqf4AAHIjAzIjAmUh/1aaqaEV/oEp/uAIAIEc/pEc/sAgAIIoAK0CgLQ1wIgRkIgQgIsgcLiCMLvCgSn+4AgAoqPogR7+4AgAhpf+ANIjBcIjBLIjA6gjpWr/BpP+ALIDAyIDAoC7ESC7ILLL8KLDGGVI/8aM/iIDA3IDAoAiEXAiIIEY/uAIAHHt/CLC8Ig3gCJjFjKhiBeKgoCMQYYCAAAAgmET5Tr/giETmEemGQWSJwKXqOtl+P4Wmv+iJwEgwiCywxiBCP7gCAAWSgAyoMQ5VzgXKjM5Fzg3ICPAKTeBAv7gCAAGcP4AIsMYImEQcgMDggMCgHcRgHcgcsfwDBlGIAAAACHj/THk+5gCebGQM8A5QTgmDBk3twEMOZJhEiUz/5IhEjHb/ZkBsiEQ6AKh2v3CwSzywRDdA4Hs/eAIAJ0KuCaosYIhEKC7wKqIuSagd8C4AqhBDByquwwKkKyDuQKCYRCgoHQwu8DMatLbgNCsg4zaMKMgkmESpTf/kiESMmIAMiUDjKeQjzGQiMDWKABW4/bWeQAioMcpVUYAAIxJjKMGQP4AIqDIzEPGPf4ioMkpVcY7/gAoI1aSjiUT/6Go/YG9/eAIAIHJ/eAIAAY1/gAAACgzFsKMZRH/oqPogbX94AgA4AIAhi7+AAAAHfAAADZBAJ0CgqDAKAOHmQ/MMgwSBgcADAIpA3zihg4AJhIFJiIUBgMAgqDbgCkjh5koDCIpA3zyxgcAIqDcJ5kKDBIpAy0IBgQAAACCoN188oeZBgwSKQMioNsd8AAA", + "text_start": 1077379072, + "data": "CADKPw==", + "data_start": 1070279668 +} \ No newline at end of file diff --git a/stubs/stub_flasher_32s3beta2.json b/stubs/stub_flasher_32s3beta2.json new file mode 100644 index 00000000..99cb6d65 --- /dev/null +++ b/stubs/stub_flasher_32s3beta2.json @@ -0,0 +1,7 @@ +{ + "entry": 1077381512, + "text": "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", + "text_start": 1077379072, + "data": "CADKPw==", + "data_start": 1070279668 +} \ No newline at end of file diff --git a/stubs/stub_flasher_8266.json b/stubs/stub_flasher_8266.json new file mode 100644 index 00000000..98223b80 --- /dev/null +++ b/stubs/stub_flasher_8266.json @@ -0,0 +1,7 @@ +{ + "entry": 1074843652, + "text": "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", + "text_start": 1074843648, + "data": "CIH+PwUFBAACAwcAAwMLALnXEEDv1xBAHdgQQLrYEEBo5xBAHtkQQHTZEEDA2RBAaOcQQILaEED/2hBAwNsQQGjnEEBo5xBAWNwQQGjnEEA33xBAAOAQQDvgEEBo5xBAaOcQQNfgEEBo5xBAv+EQQGXiEECj4xBAY+QQQDTlEEBo5xBAaOcQQGjnEEBo5xBAYuYQQGjnEEBX5xBAkN0QQI/YEECm5RBAq9oQQPzZEEBo5xBA7OYQQDHnEEBo5xBAaOcQQGjnEEBo5xBAaOcQQGjnEEBo5xBAaOcQQCLaEEBf2hBAvuUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA", + "data_start": 1073720488 +} \ No newline at end of file From d8219806ed274704610d524021e5841808a7f624 Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Mon, 8 Aug 2022 11:15:40 +1200 Subject: [PATCH 2/9] add log framework, stub decode tests --- Cargo.lock | 105 +++++++++++++++++++++++++++++++++++++ cargo-espflash/Cargo.toml | 4 +- cargo-espflash/src/main.rs | 32 ++++++++--- espflash/Cargo.toml | 4 +- espflash/src/chip/mod.rs | 4 +- espflash/src/cli/mod.rs | 17 +++--- espflash/src/flasher.rs | 26 ++++----- espflash/src/main.rs | 14 +++++ espflash/src/stubs/mod.rs | 36 +++++++++++-- 9 files changed, 208 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4fa9fbe9..107862a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "array-init" version = "0.0.4" @@ -191,11 +200,13 @@ dependencies = [ "cargo_toml", "clap", "espflash", + "log", "miette", "serde", "strum", "thiserror", "toml", + "tracing-subscriber", ] [[package]] @@ -504,6 +515,7 @@ dependencies = [ "espmonitor", "flate2", "indicatif", + "log", "maplit", "md5", "miette", @@ -520,6 +532,7 @@ dependencies = [ "strum_macros", "thiserror", "toml", + "tracing-subscriber", "update-informer", "xmas-elf", ] @@ -781,6 +794,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.9" @@ -974,6 +996,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "pkg-config" version = "0.3.25" @@ -1058,6 +1086,9 @@ name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] [[package]] name = "regex-syntax" @@ -1265,6 +1296,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook" version = "0.3.14" @@ -1471,6 +1511,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1495,6 +1544,56 @@ dependencies = [ "serde", ] +[[package]] +name = "tracing" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" +dependencies = [ + "ansi_term", + "matchers", + "once_cell", + "regex", + "sharded-slab", + "smallvec 1.9.0", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "typenum" version = "1.15.0" @@ -1587,6 +1686,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" diff --git a/cargo-espflash/Cargo.toml b/cargo-espflash/Cargo.toml index 80f9b696..9af457df 100644 --- a/cargo-espflash/Cargo.toml +++ b/cargo-espflash/Cargo.toml @@ -32,10 +32,12 @@ pkg-fmt = "zip" [dependencies] cargo_metadata = "0.15" cargo_toml = "0.11" -clap = { version = "3.2", features = ["derive"] } +clap = { version = "3.2", features = ["derive", "env"] } espflash = { version = "=1.6.1-dev", path = "../espflash" } +log = "0.4.17" miette = { version = "5.2", features = ["fancy"] } serde = { version = "1.0", features = ["derive"] } strum = "0.24" thiserror = "1.0" +tracing-subscriber = { version = "0.3.11", features = [ "env-filter" ] } toml = "0.5" diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index 23ca6fd8..6960f60f 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -15,8 +15,10 @@ use espflash::{ }, Chip, Config, ImageFormatId, }; +use log::debug; use miette::{IntoDiagnostic, Result, WrapErr}; use strum::VariantNames; +use tracing_subscriber::{filter::LevelFilter, EnvFilter}; use crate::{ cargo_config::{parse_cargo_config, CargoConfig}, @@ -28,19 +30,23 @@ mod cargo_config; mod error; mod package_metadata; -#[derive(Parser)] +#[derive(Debug, Clone, Parser)] #[clap(bin_name = "cargo", version, propagate_version = true)] struct Opts { #[clap(subcommand)] subcommand: CargoSubCommand, + + /// Log level + #[clap(long, default_value = "info", env)] + log_level: LevelFilter, } -#[derive(Parser)] +#[derive(Debug, Clone, Parser)] enum CargoSubCommand { Espflash(EspFlashOpts), } -#[derive(Parser)] +#[derive(Debug, Clone, Parser)] struct EspFlashOpts { #[clap(flatten)] flash_opts: FlashOpts, @@ -52,7 +58,7 @@ struct EspFlashOpts { subcommand: Option, } -#[derive(Parser)] +#[derive(Debug, Clone, Parser)] pub enum SubCommand { /// Display information about the connected board and exit without flashing BoardInfo(ConnectOpts), @@ -64,7 +70,7 @@ pub enum SubCommand { PartitionTable(PartitionTableOpts), } -#[derive(Parser)] +#[derive(Debug, Clone, Parser)] pub struct BuildOpts { /// Build the application using the release profile #[clap(long)] @@ -100,7 +106,7 @@ pub struct BuildOpts { pub flash_config_opts: FlashConfigOpts, } -#[derive(Parser)] +#[derive(Debug, Clone, Parser)] pub struct SaveImageOpts { #[clap(flatten)] pub build_opts: BuildOpts, @@ -125,8 +131,20 @@ fn main() -> Result<()> { check_for_updates(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - let CargoSubCommand::Espflash(opts) = Opts::parse().subcommand; + // Parse options + let opts = Opts::parse(); + + // Setup logging + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env().add_directive(opts.log_level.into())) + .init(); + + // Extract subcommand + let CargoSubCommand::Espflash(opts) = opts.subcommand; + + debug!("subcommand options: {:?}", opts); + // Load configuration and metadata let config = Config::load()?; let metadata = CargoEspFlashMeta::load("Cargo.toml")?; let cargo_config = parse_cargo_config(".")?; diff --git a/espflash/Cargo.toml b/espflash/Cargo.toml index 6d94ab28..fadd4a4c 100644 --- a/espflash/Cargo.toml +++ b/espflash/Cargo.toml @@ -32,7 +32,7 @@ pkg-fmt = "zip" base64 = "0.13.0" binread = "2.2" bytemuck = { version = "1.11", features = ["derive"] } -clap = { version = "3.2", features = ["derive"] } +clap = { version = "3.2", features = ["derive", "env"] } comfy-table = "6.0" crossterm = "0.24" csv = "1.1" @@ -41,6 +41,7 @@ directories-next = "2.0" espmonitor = "0.10" flate2 = "1.0" indicatif = "0.17" +log = "0.4.17" maplit = "1.0" md5 = "0.7" miette = { version = "5.2", features = ["fancy"] } @@ -51,6 +52,7 @@ serde-hex = "0.1" serde_json = "1.0.83" serde_plain = "1.0" serialport = "4.2" +tracing-subscriber = { version = "0.3.11", features = [ "env-filter" ] } sha2 = "0.10" slip-codec = "0.3" strum = "0.24" diff --git a/espflash/src/chip/mod.rs b/espflash/src/chip/mod.rs index c5ac0142..b0b99480 100644 --- a/espflash/src/chip/mod.rs +++ b/espflash/src/chip/mod.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, ops::Range, str::FromStr}; use maplit::hashmap; -use strum_macros::{Display, EnumVariantNames}; +use strum_macros::{Display, EnumIter, EnumVariantNames}; pub use self::{ esp32::{Esp32, Esp32Params, Esp32c2, Esp32c3, Esp32s2, Esp32s3}, @@ -143,7 +143,7 @@ impl SpiRegisters { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Display, EnumVariantNames)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Display, EnumVariantNames, EnumIter)] pub enum Chip { #[strum(serialize = "ESP32")] Esp32, diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index ab22291e..ba21916f 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -31,7 +31,7 @@ pub mod monitor; mod serial; -#[derive(Parser, Debug)] +#[derive(Clone, Debug, Parser)] pub struct ConnectOpts { /// Serial port connected to target device pub serial: Option, @@ -45,7 +45,7 @@ pub struct ConnectOpts { pub use_stub: bool, } -#[derive(Parser, Debug)] +#[derive(Clone, Debug, Parser)] pub struct FlashOpts { /// Load the application to RAM instead of Flash #[clap(long)] @@ -61,7 +61,7 @@ pub struct FlashOpts { pub monitor: bool, } -#[derive(Parser, Debug)] +#[derive(Debug, Clone, Parser)] pub struct FlashConfigOpts { /// Flash mode to use #[clap(short = 'm', long, possible_values = FlashMode::VARIANTS, value_name = "MODE")] @@ -74,7 +74,7 @@ pub struct FlashConfigOpts { pub flash_freq: Option, } -#[derive(Parser, Debug)] +#[derive(Clone, Debug, Parser)] pub struct PartitionTableOpts { /// Convert CSV parition table to binary representation #[clap(long, required_unless_present_any = ["info", "to-csv"])] @@ -92,7 +92,7 @@ pub struct PartitionTableOpts { output: Option, } -#[derive(Parser, Debug)] +#[derive(Clone, Debug, Parser)] pub struct WriteBinToFlashOpts { /// Address at which to write the binary file #[clap(value_parser = parse_u32)] @@ -138,7 +138,12 @@ pub fn connect(opts: &ConnectOpts, config: &Config) -> Result { _ => unreachable!(), }; - Ok(Flasher::connect(serial, port_info, opts.speed, opts.use_stub)?) + Ok(Flasher::connect( + serial, + port_info, + opts.speed, + opts.use_stub, + )?) } pub fn board_info(opts: ConnectOpts, config: Config) -> Result<()> { diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index 3340b973..e7c4e4fe 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -1,6 +1,7 @@ use std::{borrow::Cow, str::FromStr, thread::sleep}; use bytemuck::{Pod, Zeroable, __core::time::Duration}; +use log::debug; use serialport::{SerialPort, UsbPortInfo}; use strum_macros::{Display, EnumVariantNames}; @@ -11,7 +12,8 @@ use crate::{ elf::{ElfFirmwareImage, FirmwareImage, FlashFrequency, FlashMode, RomSegment}, error::{ConnectionError, FlashDetectError, ResultExt}, image_format::ImageFormatId, - Error, PartitionTable, stubs::FlashStub, + stubs::FlashStub, + Error, PartitionTable, }; const DEFAULT_TIMEOUT: Duration = Duration::from_secs(3); @@ -238,8 +240,7 @@ impl Flasher { /// Load flash stub fn load_stub(&mut self) -> Result<(), Error> { - - println!("Loading flash stub for chip: {:?}", self.chip); + debug!("Loading flash stub for chip: {:?}", self.chip); // Load flash stub let stub = FlashStub::get(self.chip).unwrap(); @@ -248,9 +249,10 @@ impl Flasher { ram_target.begin(&mut self.connection).flashing()?; let (text_addr, text) = stub.text(); - println!("Write {} byte stub text", text.len()); + debug!("Write {} byte stub text", text.len()); - ram_target.write_segment( + ram_target + .write_segment( &mut self.connection, RomSegment { addr: text_addr, @@ -259,11 +261,11 @@ impl Flasher { ) .flashing()?; - let (data_addr, data) = stub.data(); - println!("Write {} byte stub data", data.len()); + debug!("Write {} byte stub data", data.len()); - ram_target.write_segment( + ram_target + .write_segment( &mut self.connection, RomSegment { addr: data_addr, @@ -272,10 +274,10 @@ impl Flasher { ) .flashing()?; - println!("Finish stub write"); + debug!("Finish stub write"); ram_target.finish(&mut self.connection, true).flashing()?; - - println!("Stub written..."); + + debug!("Stub written..."); // Re-sync connection self.connection.sync()?; @@ -283,7 +285,7 @@ impl Flasher { // Re-detect chip to check stub is up let magic = self.connection.read_reg(CHIP_DETECT_MAGIC_REG_ADDR)?; let chip = Chip::from_magic(magic)?; - println!("Re-detected chip: {:?}", chip); + debug!("Re-detected chip: {:?}", chip); Ok(()) } diff --git a/espflash/src/main.rs b/espflash/src/main.rs index 50636db8..23351413 100644 --- a/espflash/src/main.rs +++ b/espflash/src/main.rs @@ -9,8 +9,10 @@ use espflash::{ }, Chip, Config, ImageFormatId, }; +use log::debug; use miette::{IntoDiagnostic, Result, WrapErr}; use strum::VariantNames; +use tracing_subscriber::{filter::LevelFilter, EnvFilter}; #[derive(Debug, Parser)] #[clap(version, propagate_version = true)] @@ -33,6 +35,10 @@ struct Opts { #[clap(subcommand)] subcommand: Option, + + /// Log level + #[clap(long, default_value = "info", env)] + log_level: LevelFilter, } #[derive(Debug, Parser)] @@ -80,9 +86,17 @@ fn main() -> Result<()> { check_for_updates(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + // Read options and configuration let mut opts = Opts::parse(); let config = Config::load()?; + debug!("options: {:?}", opts); + + // Setup logging + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env().add_directive(opts.log_level.into())) + .init(); + if opts.subcommand.is_none() { // If neither the IMAGE nor SERIAL arguments have been provided, print the // help message and exit. diff --git a/espflash/src/stubs/mod.rs b/espflash/src/stubs/mod.rs index 38a87031..7b7bec66 100644 --- a/espflash/src/stubs/mod.rs +++ b/espflash/src/stubs/mod.rs @@ -1,18 +1,25 @@ -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use crate::Chip; - +/// Flash stub object (deserialized from json as used by `esptool.py`) #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct FlashStub { + /// Entry point (address) entry: u32, + /// Text (b64 encoded) text: String, + /// Start of text section address text_start: u32, + /// Data data: String, + /// Start of data section address data_start: u32, } -const STUB_32: &str = include_str!("../../../stubs/stub_flasher_32.json"); +// Include stub objects in binary + +const STUB_32: &str = include_str!("../../../stubs/stub_flasher_32.json"); const STUB_32C2: &str = include_str!("../../../stubs/stub_flasher_32c2.json"); const STUB_32C3: &str = include_str!("../../../stubs/stub_flasher_32c3.json"); const STUB_32S2: &str = include_str!("../../../stubs/stub_flasher_32s2.json"); @@ -31,8 +38,7 @@ impl FlashStub { Chip::Esp8266 => STUB_8266, }; - let stub: FlashStub = serde_json::from_str(s) - .map_err(|_| () )?; + let stub: FlashStub = serde_json::from_str(s).map_err(|_| ())?; Ok(stub) } @@ -54,3 +60,23 @@ impl FlashStub { (self.data_start, v) } } + +#[cfg(test)] +mod tests { + use strum::IntoEnumIterator; + + use super::FlashStub; + use crate::Chip; + + #[test] + fn check_stub_encodings() { + for c in Chip::iter() { + // Stub must be valid json + let s = FlashStub::get(c).unwrap(); + + // Data decoded from b64 + let _ = s.text(); + let _ = s.data(); + } + } +} From 26e7c000aad90374b9ef783f0a986efe75f062de Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Mon, 8 Aug 2022 11:37:07 +1200 Subject: [PATCH 3/9] allow flash detect on flash enable failure it appears some boards report SpiAttach failed when flash has already been loaded by the stub --- espflash/src/flasher.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index e7c4e4fe..933eeba3 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -294,10 +294,17 @@ impl Flasher { // Loop over all available SPI parameters until we find one that successfully // reads the flash size. for spi_params in TRY_SPI_PARAMS.iter().copied() { + debug!("Attempting flash enable with: {:?}", spi_params); + + // Send `SpiAttach` to enable flash, in some instances this command + // may fail while the flash connection succeeds if let Err(_e) = self.enable_flash(spi_params) { - continue; + debug!("Flash enable failed"); } + if let Some(flash_size) = self.flash_detect()? { + debug!("Flash detect OK!"); + // Flash detection was successful, so save the flash size and SPI parameters and // return. self.flash_size = flash_size; @@ -305,8 +312,12 @@ impl Flasher { return Ok(()); } + + debug!("Flash detect failed"); } + debug!("SPI flash autodetection failed"); + // None of the SPI parameters were successful. Err(Error::FlashConnect) } From 57572d98d94c1ea3d48eecfd32efe90812fe62ef Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Tue, 9 Aug 2022 10:41:13 +1200 Subject: [PATCH 4/9] support baud rate switching with flash stubs Co-authored-by: Timothy Mertz --- espflash/src/command.rs | 11 +++++++---- espflash/src/flasher.rs | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/espflash/src/command.rs b/espflash/src/command.rs index 88f7332a..f9605967 100644 --- a/espflash/src/command.rs +++ b/espflash/src/command.rs @@ -113,7 +113,10 @@ pub enum Command<'a> { spi_params: SpiAttachParams, }, ChangeBaud { - speed: u32, + /// New baud rate + new_baud: u32, + /// Prior baud rate ('0' for ROM flasher) + prior_baud: u32, }, FlashDeflateBegin { size: u32, @@ -267,14 +270,14 @@ impl<'a> Command<'a> { Command::SpiAttach { spi_params } => { write_basic(writer, &spi_params.encode(), 0)?; } - Command::ChangeBaud { speed } => { + Command::ChangeBaud { new_baud, prior_baud } => { // length writer.write_all(&(8u16.to_le_bytes()))?; // checksum writer.write_all(&(0u32.to_le_bytes()))?; // data - writer.write_all(&speed.to_le_bytes())?; - writer.write_all(&0u32.to_le_bytes())?; + writer.write_all(&new_baud.to_le_bytes())?; + writer.write_all(&prior_baud.to_le_bytes())?; } Command::FlashDeflateBegin { size, diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index 933eeba3..735d0f4b 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -183,10 +183,16 @@ struct EntryParams { } pub struct Flasher { + /// Connection for flash operations connection: Connection, + /// Chip ID chip: Chip, + /// Flash size, loaded from SPI flash flash_size: FlashSize, + /// Configuration for SPI attached flash (0 to use fused values) spi_params: SpiAttachParams, + /// Indicate RAM stub loader is in use + use_stub: bool, } impl Flasher { @@ -211,6 +217,7 @@ impl Flasher { chip, flash_size: FlashSize::Flash4Mb, spi_params: SpiAttachParams::default(), + use_stub, }; // Load flash stub if enabled @@ -590,9 +597,16 @@ impl Flasher { } pub fn change_baud(&mut self, speed: u32) -> Result<(), Error> { + debug!("Change baud to: {}", speed); + + let prior_baud = match self.use_stub { + true => self.connection.get_baud()?, + false => 0, + }; + self.connection .with_timeout(CommandType::ChangeBaud.timeout(), |connection| { - connection.command(Command::ChangeBaud { speed }) + connection.command(Command::ChangeBaud { new_baud: speed, prior_baud }) })?; self.connection.set_baud(speed)?; std::thread::sleep(Duration::from_secs_f32(0.05)); From a9d51deabb0752332db3b350ed587288804f1edb Mon Sep 17 00:00:00 2001 From: Timothy Mertz Date: Wed, 10 Aug 2022 08:56:15 +1200 Subject: [PATCH 5/9] Fix SpiAttach when using stub --- espflash/src/chip/mod.rs | 8 ++++++-- espflash/src/command.rs | 14 ++++++++++++-- espflash/src/flash_target/esp32.rs | 14 +++++++++++--- espflash/src/flasher.rs | 28 +++++++++++++++++++--------- 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/espflash/src/chip/mod.rs b/espflash/src/chip/mod.rs index b0b99480..fefb2fef 100644 --- a/espflash/src/chip/mod.rs +++ b/espflash/src/chip/mod.rs @@ -299,10 +299,14 @@ impl Chip { Box::new(RamTarget::new(entry)) } - pub fn flash_target(&self, spi_params: SpiAttachParams) -> Box { + pub fn flash_target( + &self, + spi_params: SpiAttachParams, + use_stub: bool, + ) -> Box { match self { Chip::Esp8266 => Box::new(Esp8266Target::new()), - _ => Box::new(Esp32Target::new(*self, spi_params)), + _ => Box::new(Esp32Target::new(*self, spi_params, use_stub)), } } diff --git a/espflash/src/command.rs b/espflash/src/command.rs index f9605967..27fd8e0d 100644 --- a/espflash/src/command.rs +++ b/espflash/src/command.rs @@ -112,6 +112,9 @@ pub enum Command<'a> { SpiAttach { spi_params: SpiAttachParams, }, + SpiAttachStub { + spi_params: SpiAttachParams, + }, ChangeBaud { /// New baud rate new_baud: u32, @@ -150,6 +153,7 @@ impl<'a> Command<'a> { Command::WriteReg { .. } => CommandType::WriteReg, Command::ReadReg { .. } => CommandType::ReadReg, Command::SpiAttach { .. } => CommandType::SpiAttach, + Command::SpiAttachStub { .. } => CommandType::SpiAttach, Command::ChangeBaud { .. } => CommandType::ChangeBaud, Command::FlashDeflateBegin { .. } => CommandType::FlashDeflateBegin, Command::FlashDeflateData { .. } => CommandType::FlashDeflateData, @@ -268,9 +272,15 @@ impl<'a> Command<'a> { write_basic(writer, &address.to_le_bytes(), 0)?; } Command::SpiAttach { spi_params } => { - write_basic(writer, &spi_params.encode(), 0)?; + write_basic(writer, &spi_params.encode(false), 0)?; } - Command::ChangeBaud { new_baud, prior_baud } => { + Command::SpiAttachStub { spi_params } => { + write_basic(writer, &spi_params.encode(true), 0)?; + } + Command::ChangeBaud { + new_baud, + prior_baud, + } => { // length writer.write_all(&(8u16.to_le_bytes()))?; // checksum diff --git a/espflash/src/flash_target/esp32.rs b/espflash/src/flash_target/esp32.rs index 458b445f..2c64d029 100644 --- a/espflash/src/flash_target/esp32.rs +++ b/espflash/src/flash_target/esp32.rs @@ -13,13 +13,15 @@ use std::io::Write; pub struct Esp32Target { chip: Chip, spi_attach_params: SpiAttachParams, + use_stub: bool, } impl Esp32Target { - pub fn new(chip: Chip, spi_attach_params: SpiAttachParams) -> Self { + pub fn new(chip: Chip, spi_attach_params: SpiAttachParams, use_stub: bool) -> Self { Esp32Target { chip, spi_attach_params, + use_stub, } } } @@ -27,8 +29,14 @@ impl Esp32Target { impl FlashTarget for Esp32Target { fn begin(&mut self, connection: &mut Connection) -> Result<(), Error> { connection.with_timeout(CommandType::SpiAttach.timeout(), |connection| { - connection.command(Command::SpiAttach { - spi_params: self.spi_attach_params, + connection.command(if self.use_stub { + Command::SpiAttachStub { + spi_params: self.spi_attach_params, + } + } else { + Command::SpiAttach { + spi_params: self.spi_attach_params, + } }) })?; diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index 735d0f4b..e7c21d84 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -138,17 +138,20 @@ impl SpiAttachParams { } } - pub fn encode(self) -> Vec { + pub fn encode(self, stub: bool) -> Vec { let packed = ((self.hd as u32) << 24) | ((self.cs as u32) << 18) | ((self.d as u32) << 12) | ((self.q as u32) << 6) | (self.clk as u32); - if packed == 0 { - vec![0; 5] - } else { - packed.to_le_bytes().to_vec() + + let mut encoded: Vec = packed.to_le_bytes().to_vec(); + + if !stub { + encoded.append(&mut vec![0u8; 4]); } + + encoded } } @@ -369,7 +372,11 @@ impl Flasher { _ => { self.connection .with_timeout(CommandType::SpiAttach.timeout(), |connection| { - connection.command(Command::SpiAttach { spi_params }) + connection.command(if self.use_stub { + Command::SpiAttachStub { spi_params } + } else { + Command::SpiAttach { spi_params } + }) })?; } } @@ -537,7 +544,7 @@ impl Flasher { ) -> Result<(), Error> { let image = ElfFirmwareImage::try_from(elf_data)?; - let mut target = self.chip.flash_target(self.spi_params); + let mut target = self.chip.flash_target(self.spi_params, self.use_stub); target.begin(&mut self.connection).flashing()?; let flash_image = self.chip.get_flash_image( @@ -564,7 +571,7 @@ impl Flasher { /// Load an bin image to flash at a specific address pub fn write_bin_to_flash(&mut self, addr: u32, data: &[u8]) -> Result<(), Error> { - let mut target = self.chip.flash_target(self.spi_params); + let mut target = self.chip.flash_target(self.spi_params, self.use_stub); target.begin(&mut self.connection).flashing()?; let segment = RomSegment { addr, @@ -606,7 +613,10 @@ impl Flasher { self.connection .with_timeout(CommandType::ChangeBaud.timeout(), |connection| { - connection.command(Command::ChangeBaud { new_baud: speed, prior_baud }) + connection.command(Command::ChangeBaud { + new_baud: speed, + prior_baud, + }) })?; self.connection.set_baud(speed)?; std::thread::sleep(Duration::from_secs_f32(0.05)); From 668a4bfde6129fddb41e1aca6f0ba9289c30dcbe Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Fri, 12 Aug 2022 08:32:26 +1200 Subject: [PATCH 6/9] remove error option in FlashStub::get --- espflash/src/flasher.rs | 2 +- espflash/src/stubs/mod.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index e7c21d84..cebf8671 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -253,7 +253,7 @@ impl Flasher { debug!("Loading flash stub for chip: {:?}", self.chip); // Load flash stub - let stub = FlashStub::get(self.chip).unwrap(); + let stub = FlashStub::get(self.chip); let mut ram_target = self.chip.ram_target(Some(stub.entry())); ram_target.begin(&mut self.connection).flashing()?; diff --git a/espflash/src/stubs/mod.rs b/espflash/src/stubs/mod.rs index 7b7bec66..9441344a 100644 --- a/espflash/src/stubs/mod.rs +++ b/espflash/src/stubs/mod.rs @@ -28,7 +28,7 @@ const STUB_8266: &str = include_str!("../../../stubs/stub_flasher_8266.json"); impl FlashStub { /// Fetch flash stub for the provided chip - pub fn get(chip: Chip) -> Result { + pub fn get(chip: Chip) -> FlashStub { let s = match chip { Chip::Esp32 => STUB_32, Chip::Esp32c2 => STUB_32C2, @@ -38,9 +38,9 @@ impl FlashStub { Chip::Esp8266 => STUB_8266, }; - let stub: FlashStub = serde_json::from_str(s).map_err(|_| ())?; + let stub: FlashStub = serde_json::from_str(s).unwrap(); - Ok(stub) + stub } /// Fetch stub entry point @@ -72,7 +72,7 @@ mod tests { fn check_stub_encodings() { for c in Chip::iter() { // Stub must be valid json - let s = FlashStub::get(c).unwrap(); + let s = FlashStub::get(c); // Data decoded from b64 let _ = s.text(); From 4297771cf9cf0323cfa9d245c3608fbed76ab676 Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Fri, 12 Aug 2022 13:31:53 +1200 Subject: [PATCH 7/9] for clippy --- cargo-espflash/src/main.rs | 2 +- espflash/src/main.rs | 2 +- espflash/src/partition_table.rs | 14 ++++++++------ espflash/src/stubs/mod.rs | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index 6960f60f..f922c1cd 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -135,7 +135,7 @@ fn main() -> Result<()> { let opts = Opts::parse(); // Setup logging - let _ = tracing_subscriber::fmt() + tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env().add_directive(opts.log_level.into())) .init(); diff --git a/espflash/src/main.rs b/espflash/src/main.rs index 23351413..f0ae202d 100644 --- a/espflash/src/main.rs +++ b/espflash/src/main.rs @@ -93,7 +93,7 @@ fn main() -> Result<()> { debug!("options: {:?}", opts); // Setup logging - let _ = tracing_subscriber::fmt() + tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env().add_directive(opts.log_level.into())) .init(); diff --git a/espflash/src/partition_table.rs b/espflash/src/partition_table.rs index 952c98da..495e8460 100644 --- a/espflash/src/partition_table.rs +++ b/espflash/src/partition_table.rs @@ -29,7 +29,7 @@ const MD5_PART_MAGIC_BYTES: &[u8] = &[ ]; const END_MARKER: [u8; 32] = [0xFF; 32]; -#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, BinRead)] +#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, BinRead)] #[repr(u8)] #[br(little, repr = u8)] #[serde(rename_all = "lowercase")] @@ -62,7 +62,7 @@ impl Display for Type { } } -#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, BinRead)] +#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, BinRead)] #[repr(u8)] #[br(little, repr = u8)] pub enum AppType { @@ -104,7 +104,7 @@ pub enum AppType { Test = 0x20, } -#[derive(Copy, Clone, Debug, Deserialize, EnumIter, Serialize, PartialEq, BinRead)] +#[derive(Copy, Clone, Debug, Deserialize, EnumIter, Serialize, PartialEq, Eq, BinRead)] #[repr(u8)] #[br(little, repr = u8)] #[serde(rename_all = "lowercase")] @@ -127,7 +127,7 @@ impl DataType { } } -#[derive(Debug, Serialize, Deserialize, PartialEq, Copy, Clone, BinRead)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Copy, Clone, BinRead)] #[serde(untagged)] pub enum SubType { App(AppType), @@ -162,7 +162,7 @@ impl SubType { } } -#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, BinRead)] +#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, BinRead)] #[repr(u8)] #[br(little, repr = u8)] #[serde(rename_all = "lowercase")] @@ -176,7 +176,7 @@ impl Flags { } } -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize)] pub struct PartitionTable { partitions: Vec, } @@ -544,6 +544,8 @@ impl PartialEq for Partition { } } +impl Eq for Partition {} + impl Partition { pub fn new( name: String, diff --git a/espflash/src/stubs/mod.rs b/espflash/src/stubs/mod.rs index 9441344a..67571165 100644 --- a/espflash/src/stubs/mod.rs +++ b/espflash/src/stubs/mod.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::Chip; /// Flash stub object (deserialized from json as used by `esptool.py`) -#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub struct FlashStub { /// Entry point (address) entry: u32, From 0b8f61bc1e96416d9f24f47642356041dd4b8c5e Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Tue, 16 Aug 2022 10:30:06 +1200 Subject: [PATCH 8/9] Disable encryption when using stub Co-authored-by: Timothy Mertz --- espflash/src/flash_target/esp32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/espflash/src/flash_target/esp32.rs b/espflash/src/flash_target/esp32.rs index 2c64d029..462d7b8f 100644 --- a/espflash/src/flash_target/esp32.rs +++ b/espflash/src/flash_target/esp32.rs @@ -108,7 +108,7 @@ impl FlashTarget for Esp32Target { blocks: block_count as u32, block_size: FLASH_WRITE_SIZE as u32, offset: addr, - supports_encryption: self.chip != Chip::Esp32, + supports_encryption: self.chip != Chip::Esp32 && !self.use_stub, })?; Ok(()) }, From d15beb540bcb96ba9f48e81a5626f2dabc524e33 Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Thu, 18 Aug 2022 09:48:37 +1200 Subject: [PATCH 9/9] Look for stub handshake Co-authored-by: Timothy Mertz --- espflash/src/error.rs | 2 ++ espflash/src/flash_target/ram.rs | 7 +++---- espflash/src/flasher.rs | 8 ++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/espflash/src/error.rs b/espflash/src/error.rs index 6933f699..8d0d61a9 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -152,6 +152,8 @@ pub enum ConnectionError { help("Try hard-resetting the device and try again, if the error persists your rom might be corrupted") )] OverSizedPacket, + #[error("Invalid stub handshake response received")] + InvalidStubHandshake, } #[derive(Debug, Default, Clone)] diff --git a/espflash/src/flash_target/ram.rs b/espflash/src/flash_target/ram.rs index f0f601af..f3edb109 100644 --- a/espflash/src/flash_target/ram.rs +++ b/espflash/src/flash_target/ram.rs @@ -67,13 +67,12 @@ impl FlashTarget for RamTarget { if reboot { let entry = self.entry.unwrap_or_default(); connection.with_timeout(CommandType::MemEnd.timeout(), |connection| { - connection.write_command(Command::MemEnd { + connection.command(Command::MemEnd { no_entry: entry == 0, entry, }) - }) - } else { - Ok(()) + })?; } + Ok(()) } } diff --git a/espflash/src/flasher.rs b/espflash/src/flasher.rs index cebf8671..719e8152 100644 --- a/espflash/src/flasher.rs +++ b/espflash/src/flasher.rs @@ -26,6 +26,8 @@ const FLASH_SECTORS_PER_BLOCK: usize = FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE; // register used for chip detect const CHIP_DETECT_MAGIC_REG_ADDR: u32 = 0x40001000; +const EXPECTED_STUB_HANDSHAKE: &str = "OHAI"; + #[derive(Clone, Copy, Debug, Eq, PartialEq, Display, EnumVariantNames)] #[repr(u8)] pub enum FlashSize { @@ -289,8 +291,10 @@ impl Flasher { debug!("Stub written..."); - // Re-sync connection - self.connection.sync()?; + match self.connection.read(EXPECTED_STUB_HANDSHAKE.len())? { + Some(resp) if resp == EXPECTED_STUB_HANDSHAKE.as_bytes() => Ok(()), + _ => Err(Error::Connection(ConnectionError::InvalidStubHandshake)), + }?; // Re-detect chip to check stub is up let magic = self.connection.read_reg(CHIP_DETECT_MAGIC_REG_ADDR)?;