Skip to content

Commit f41338c

Browse files
committed
implement compression for flashing to esp32
1 parent 0f9f0c4 commit f41338c

File tree

4 files changed

+60
-15
lines changed

4 files changed

+60
-15
lines changed

espflash/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ strum = "0.21.0"
3232
strum_macros = "0.21.1"
3333
csv = "1.1.6"
3434
regex = "1.5.4"
35+
flate2 = "1"
3536

3637
[dev-dependencies]
3738
pretty_assertions = "0.7.1"

espflash/src/flasher.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212

1313
pub(crate) type Encoder<'a> = SlipEncoder<'a, Box<dyn SerialPort>>;
1414

15-
const FLASH_SECTOR_SIZE: usize = 0x1000;
15+
pub(crate) const FLASH_SECTOR_SIZE: usize = 0x1000;
1616
const FLASH_BLOCK_SIZE: usize = 0x100;
1717
const FLASH_SECTORS_PER_BLOCK: usize = FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE;
1818
pub(crate) const FLASH_WRITE_SIZE: usize = 0x400;
@@ -42,6 +42,10 @@ pub(crate) enum Command {
4242
SpiSetParams = 0x0B,
4343
SpiAttach = 0x0D,
4444
ChangeBaud = 0x0F,
45+
FlashDeflateBegin = 0x10,
46+
FlashDeflateData = 0x11,
47+
FlashDeflateEnd = 0x12,
48+
FlashMd5 = 0x13,
4549
}
4650

4751
impl Command {
@@ -63,7 +67,9 @@ impl Command {
6367
}
6468
match self {
6569
Command::FlashBegin => calc_timeout(ERASE_REGION_TIMEOUT_PER_MB, size),
66-
Command::FlashData => calc_timeout(ERASE_WRITE_TIMEOUT_PER_MB, size),
70+
Command::FlashData | Command::FlashDeflateData => {
71+
calc_timeout(ERASE_WRITE_TIMEOUT_PER_MB, size)
72+
}
6773
_ => self.timeout(),
6874
}
6975
}

espflash/src/flashtarget/esp32.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::connection::Connection;
22
use crate::elf::{FirmwareImage, RomSegment};
33
use crate::error::Error;
4-
use crate::flasher::{get_erase_size, Command, SpiAttachParams, FLASH_WRITE_SIZE};
5-
use crate::flashtarget::{begin_command, block_command, FlashTarget};
4+
use crate::flasher::{Command, SpiAttachParams, FLASH_SECTOR_SIZE, FLASH_WRITE_SIZE};
5+
use crate::flashtarget::{begin_command, block_command_with_timeout, FlashTarget};
66
use crate::Chip;
7+
use flate2::write::{ZlibDecoder, ZlibEncoder};
8+
use flate2::Compression;
79
use indicatif::{ProgressBar, ProgressStyle};
10+
use std::io::Write;
811

912
pub struct Esp32Target {
1013
chip: Chip,
@@ -35,21 +38,26 @@ impl FlashTarget for Esp32Target {
3538
segment: RomSegment,
3639
) -> Result<(), Error> {
3740
let addr = segment.addr;
38-
let block_count = (segment.data.len() + FLASH_WRITE_SIZE - 1) / FLASH_WRITE_SIZE;
41+
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best());
42+
encoder.write_all(&segment.data)?;
43+
let compressed = encoder.finish()?;
44+
let block_count = (compressed.len() + FLASH_WRITE_SIZE - 1) / FLASH_WRITE_SIZE;
45+
let erase_count = (segment.data.len() + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
3946

40-
let erase_size = segment.data.len() as u32;
47+
// round up to sector size
48+
let erase_size = (erase_count * FLASH_SECTOR_SIZE) as u32;
4149

4250
begin_command(
4351
connection,
44-
Command::FlashBegin,
52+
Command::FlashDeflateBegin,
4553
erase_size,
4654
block_count as u32,
4755
FLASH_WRITE_SIZE as u32,
4856
addr,
4957
self.chip != Chip::Esp32,
5058
)?;
5159

52-
let chunks = segment.data.chunks(FLASH_WRITE_SIZE);
60+
let chunks = compressed.chunks(FLASH_WRITE_SIZE);
5361

5462
let (_, chunk_size) = chunks.size_hint();
5563
let chunk_size = chunk_size.unwrap_or(0) as u64;
@@ -60,16 +68,25 @@ impl FlashTarget for Esp32Target {
6068
.progress_chars("#>-"),
6169
);
6270

71+
// decode the chunks to see how much data the device will have to save
72+
let mut decoder = ZlibDecoder::new(Vec::new());
73+
let mut decoded_size = 0;
74+
6375
for (i, block) in chunks.enumerate() {
76+
decoder.write_all(block)?;
77+
decoder.flush()?;
78+
let size = decoder.get_ref().len() - decoded_size;
79+
decoded_size = decoder.get_ref().len();
80+
6481
pb_chunk.set_message(format!("segment 0x{:X} writing chunks", addr));
65-
let block_padding = FLASH_WRITE_SIZE - block.len();
66-
block_command(
82+
block_command_with_timeout(
6783
connection,
68-
Command::FlashData,
84+
Command::FlashDeflateData,
6985
block,
70-
block_padding,
86+
0,
7187
0xff,
7288
i as u32,
89+
Command::FlashDeflateData.timeout_for_size(size as u32),
7390
)?;
7491
pb_chunk.inc(1);
7592
}
@@ -80,8 +97,8 @@ impl FlashTarget for Esp32Target {
8097
}
8198

8299
fn finish(&mut self, connection: &mut Connection, reboot: bool) -> Result<(), Error> {
83-
connection.with_timeout(Command::FlashEnd.timeout(), |connection| {
84-
connection.write_command(Command::FlashEnd as u8, &[1][..], 0)
100+
connection.with_timeout(Command::FlashDeflateEnd.timeout(), |connection| {
101+
connection.write_command(Command::FlashDeflateEnd as u8, &[1][..], 0)
85102
})?;
86103
if reboot {
87104
connection.reset()

espflash/src/flashtarget/mod.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub use esp32::Esp32Target;
1111
pub use esp8266::Esp8266Target;
1212
pub use ram::RamTarget;
1313
use std::mem::size_of;
14+
use std::time::Duration;
1415

1516
pub trait FlashTarget {
1617
fn begin(&mut self, connection: &mut Connection, image: &FirmwareImage) -> Result<(), Error>;
@@ -81,6 +82,26 @@ fn block_command(
8182
padding: usize,
8283
padding_byte: u8,
8384
sequence: u32,
85+
) -> Result<(), Error> {
86+
block_command_with_timeout(
87+
connection,
88+
command,
89+
data,
90+
padding,
91+
padding_byte,
92+
sequence,
93+
command.timeout_for_size(data.len() as u32),
94+
)
95+
}
96+
97+
fn block_command_with_timeout(
98+
connection: &mut Connection,
99+
command: Command,
100+
data: &[u8],
101+
padding: usize,
102+
padding_byte: u8,
103+
sequence: u32,
104+
timout: Duration,
84105
) -> Result<(), Error> {
85106
let params = BlockParams {
86107
size: (data.len() + padding) as u32,
@@ -97,7 +118,7 @@ fn block_command(
97118
check = checksum(&[padding_byte], check);
98119
}
99120

100-
connection.with_timeout(command.timeout_for_size(data.len() as u32), |connection| {
121+
connection.with_timeout(timout, |connection| {
101122
connection.command(
102123
command as u8,
103124
(length as u16, |encoder: &mut Encoder| {

0 commit comments

Comments
 (0)