Skip to content

Commit c8b4146

Browse files
committed
add flashtarget abstraction for handling differences between targets
1 parent 0700010 commit c8b4146

File tree

5 files changed

+329
-125
lines changed

5 files changed

+329
-125
lines changed

espflash/src/flasher.rs

Lines changed: 24 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
use bytemuck::{__core::time::Duration, bytes_of, Pod, Zeroable};
2-
use indicatif::{ProgressBar, ProgressStyle};
32
use serial::{BaudRate, SerialPort};
43
use strum_macros::Display;
54

6-
use std::{mem::size_of, thread::sleep};
5+
use std::thread::sleep;
76

7+
use crate::elf::RomSegment;
8+
use crate::flashtarget::{ChipTarget, FlashTarget, RamTarget};
89
use crate::{
910
chip::Chip, connection::Connection, elf::FirmwareImage, encoder::SlipEncoder, error::RomError,
1011
Error, PartitionTable,
1112
};
1213

13-
type Encoder<'a> = SlipEncoder<'a, Box<dyn SerialPort>>;
14+
pub(crate) type Encoder<'a> = SlipEncoder<'a, Box<dyn SerialPort>>;
1415

15-
const MAX_RAM_BLOCK_SIZE: usize = 0x1800;
1616
const FLASH_SECTOR_SIZE: usize = 0x1000;
1717
const FLASH_BLOCK_SIZE: usize = 0x100;
1818
const FLASH_SECTORS_PER_BLOCK: usize = FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE;
19-
const FLASH_WRITE_SIZE: usize = 0x400;
19+
pub(crate) const FLASH_WRITE_SIZE: usize = 0x400;
2020

2121
// register used for chip detect
2222
const CHIP_DETECT_MAGIC_REG_ADDR: u32 = 0x40001000;
@@ -30,7 +30,7 @@ const SYNC_TIMEOUT: Duration = Duration::from_millis(100);
3030
#[derive(Copy, Clone, Debug)]
3131
#[allow(dead_code)]
3232
#[repr(u8)]
33-
enum Command {
33+
pub(crate) enum Command {
3434
FlashBegin = 0x02,
3535
FlashData = 0x03,
3636
FlashEnd = 0x04,
@@ -109,7 +109,7 @@ impl FlashSize {
109109

110110
#[derive(Copy, Clone)]
111111
#[repr(C)]
112-
struct SpiAttachParams {
112+
pub struct SpiAttachParams {
113113
clk: u8,
114114
q: u8,
115115
d: u8,
@@ -341,64 +341,6 @@ impl Flasher {
341341
})
342342
}
343343

344-
fn block_command(
345-
&mut self,
346-
command: Command,
347-
data: &[u8],
348-
padding: usize,
349-
padding_byte: u8,
350-
sequence: u32,
351-
) -> Result<(), Error> {
352-
let params = BlockParams {
353-
size: (data.len() + padding) as u32,
354-
sequence,
355-
dummy1: 0,
356-
dummy2: 0,
357-
};
358-
359-
let length = size_of::<BlockParams>() + data.len() + padding;
360-
361-
let mut check = checksum(data, CHECKSUM_INIT);
362-
363-
for _ in 0..padding {
364-
check = checksum(&[padding_byte], check);
365-
}
366-
367-
self.connection
368-
.with_timeout(command.timeout_for_size(data.len() as u32), |connection| {
369-
connection.command(
370-
command as u8,
371-
(length as u16, |encoder: &mut Encoder| {
372-
encoder.write(bytes_of(&params))?;
373-
encoder.write(data)?;
374-
let padding = &[padding_byte; FLASH_WRITE_SIZE][0..padding];
375-
encoder.write(padding)?;
376-
Ok(())
377-
}),
378-
check as u32,
379-
)?;
380-
Ok(())
381-
})
382-
}
383-
384-
fn mem_finish(&mut self, entry: u32) -> Result<(), Error> {
385-
let params = EntryParams {
386-
no_entry: (entry == 0) as u32,
387-
entry,
388-
};
389-
self.connection
390-
.with_timeout(Command::MemEnd.timeout(), |connection| {
391-
connection.write_command(Command::MemEnd as u8, bytes_of(&params), 0)
392-
})
393-
}
394-
395-
fn flash_finish(&mut self, reboot: bool) -> Result<(), Error> {
396-
self.connection
397-
.with_timeout(Command::FlashEnd.timeout(), |connection| {
398-
connection.write_command(Command::FlashEnd as u8, &[(!reboot) as u8][..], 0)
399-
})
400-
}
401-
402344
fn enable_flash(&mut self, spi_attach_params: SpiAttachParams) -> Result<(), Error> {
403345
match self.chip {
404346
Chip::Esp8266 => {
@@ -523,31 +465,24 @@ impl Flasher {
523465
pub fn load_elf_to_ram(&mut self, elf_data: &[u8]) -> Result<(), Error> {
524466
let image = FirmwareImage::from_data(elf_data).map_err(|_| Error::InvalidElf)?;
525467

468+
let mut target = RamTarget::new();
469+
target.begin(&mut self.connection, &image)?;
470+
526471
if image.rom_segments(self.chip).next().is_some() {
527472
return Err(Error::ElfNotRamLoadable);
528473
}
529474

530475
for segment in image.ram_segments(self.chip) {
531-
let padding = 4 - segment.data.len() % 4;
532-
let block_count =
533-
(segment.data.len() + padding + MAX_RAM_BLOCK_SIZE - 1) / MAX_RAM_BLOCK_SIZE;
534-
self.begin_command(
535-
Command::MemBegin,
536-
segment.data.len() as u32,
537-
block_count as u32,
538-
MAX_RAM_BLOCK_SIZE as u32,
539-
segment.addr,
476+
target.write_segment(
477+
&mut self.connection,
478+
RomSegment {
479+
addr: segment.addr,
480+
data: segment.data.into(),
481+
},
540482
)?;
541-
542-
for (i, block) in segment.data.chunks(MAX_RAM_BLOCK_SIZE).enumerate() {
543-
let block_padding = if i == block_count - 1 { padding } else { 0 };
544-
self.block_command(Command::MemData, block, block_padding, 0, i as u32)?;
545-
}
546483
}
547484

548-
self.mem_finish(image.entry())?;
549-
550-
Ok(())
485+
target.finish(&mut self.connection, true)
551486
}
552487

553488
/// Load an elf image to flash and execute it
@@ -557,56 +492,20 @@ impl Flasher {
557492
bootloader: Option<Vec<u8>>,
558493
partition_table: Option<PartitionTable>,
559494
) -> Result<(), Error> {
560-
self.enable_flash(self.spi_params)?;
561-
562495
let mut image = FirmwareImage::from_data(elf_data).map_err(|_| Error::InvalidElf)?;
563496
image.flash_size = self.flash_size();
564497

498+
let mut target = ChipTarget::new(self.chip, self.spi_params);
499+
target.begin(&mut self.connection, &image)?;
500+
565501
for segment in self
566502
.chip
567503
.get_flash_segments(&image, bootloader, partition_table)
568504
{
569-
let segment = segment?;
570-
let addr = segment.addr;
571-
let block_count = (segment.data.len() + FLASH_WRITE_SIZE - 1) / FLASH_WRITE_SIZE;
572-
573-
let erase_size = match self.chip {
574-
Chip::Esp8266 => get_erase_size(addr as usize, segment.data.len()) as u32,
575-
_ => segment.data.len() as u32,
576-
};
577-
578-
self.begin_command(
579-
Command::FlashBegin,
580-
erase_size,
581-
block_count as u32,
582-
FLASH_WRITE_SIZE as u32,
583-
addr,
584-
)?;
585-
586-
let chunks = segment.data.chunks(FLASH_WRITE_SIZE);
587-
588-
let (_, chunk_size) = chunks.size_hint();
589-
let chunk_size = chunk_size.unwrap_or(0) as u64;
590-
let pb_chunk = ProgressBar::new(chunk_size);
591-
pb_chunk.set_style(
592-
ProgressStyle::default_bar()
593-
.template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
594-
.progress_chars("#>-"),
595-
);
596-
597-
for (i, block) in chunks.enumerate() {
598-
pb_chunk.set_message(format!("segment 0x{:X} writing chunks", addr));
599-
let block_padding = FLASH_WRITE_SIZE - block.len();
600-
self.block_command(Command::FlashData, block, block_padding, 0xff, i as u32)?;
601-
pb_chunk.inc(1);
602-
}
603-
604-
pb_chunk.finish_with_message(format!("segment 0x{:X}", addr));
505+
target.write_segment(&mut self.connection, segment?)?;
605506
}
606507

607-
self.flash_finish(false)?;
608-
609-
self.connection.reset()?;
508+
target.finish(&mut self.connection, true)?;
610509

611510
Ok(())
612511
}
@@ -630,7 +529,7 @@ impl Flasher {
630529
}
631530
}
632531

633-
fn get_erase_size(offset: usize, size: usize) -> usize {
532+
pub(crate) fn get_erase_size(offset: usize, size: usize) -> usize {
634533
let sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
635534
let start_sector = offset / FLASH_SECTOR_SIZE;
636535

@@ -646,7 +545,7 @@ fn get_erase_size(offset: usize, size: usize) -> usize {
646545
}
647546
}
648547

649-
const CHECKSUM_INIT: u8 = 0xEF;
548+
pub(crate) const CHECKSUM_INIT: u8 = 0xEF;
650549

651550
pub fn checksum(data: &[u8], mut checksum: u8) -> u8 {
652551
for byte in data {

espflash/src/flashtarget/chip.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use crate::connection::Connection;
2+
use crate::elf::{FirmwareImage, RomSegment};
3+
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};
6+
use crate::Chip;
7+
use indicatif::{ProgressBar, ProgressStyle};
8+
9+
pub struct ChipTarget {
10+
chip: Chip,
11+
spi_attach_params: SpiAttachParams,
12+
}
13+
14+
impl ChipTarget {
15+
pub fn new(chip: Chip, spi_attach_params: SpiAttachParams) -> Self {
16+
ChipTarget {
17+
chip,
18+
spi_attach_params,
19+
}
20+
}
21+
}
22+
23+
impl FlashTarget for ChipTarget {
24+
fn begin(&mut self, connection: &mut Connection, _image: &FirmwareImage) -> Result<(), Error> {
25+
match self.chip {
26+
Chip::Esp8266 => {
27+
begin_command(
28+
connection,
29+
Command::FlashBegin,
30+
0,
31+
0,
32+
FLASH_WRITE_SIZE as u32,
33+
0,
34+
!(self.chip == Chip::Esp32 || self.chip == Chip::Esp8266),
35+
)?;
36+
}
37+
_ => {
38+
let spi_params = self.spi_attach_params.encode();
39+
connection.with_timeout(Command::SpiAttach.timeout(), |connection| {
40+
connection.command(Command::SpiAttach as u8, spi_params.as_slice(), 0)
41+
})?;
42+
}
43+
}
44+
Ok(())
45+
}
46+
47+
fn write_segment(
48+
&mut self,
49+
connection: &mut Connection,
50+
segment: RomSegment,
51+
) -> Result<(), Error> {
52+
let addr = segment.addr;
53+
let block_count = (segment.data.len() + FLASH_WRITE_SIZE - 1) / FLASH_WRITE_SIZE;
54+
55+
let erase_size = match self.chip {
56+
Chip::Esp8266 => get_erase_size(addr as usize, segment.data.len()) as u32,
57+
_ => segment.data.len() as u32,
58+
};
59+
60+
begin_command(
61+
connection,
62+
Command::FlashBegin,
63+
erase_size,
64+
block_count as u32,
65+
FLASH_WRITE_SIZE as u32,
66+
addr,
67+
!(self.chip == Chip::Esp32 || self.chip == Chip::Esp8266),
68+
)?;
69+
70+
let chunks = segment.data.chunks(FLASH_WRITE_SIZE);
71+
72+
let (_, chunk_size) = chunks.size_hint();
73+
let chunk_size = chunk_size.unwrap_or(0) as u64;
74+
let pb_chunk = ProgressBar::new(chunk_size);
75+
pb_chunk.set_style(
76+
ProgressStyle::default_bar()
77+
.template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
78+
.progress_chars("#>-"),
79+
);
80+
81+
for (i, block) in chunks.enumerate() {
82+
pb_chunk.set_message(format!("segment 0x{:X} writing chunks", addr));
83+
let block_padding = FLASH_WRITE_SIZE - block.len();
84+
block_command(
85+
connection,
86+
Command::FlashData,
87+
block,
88+
block_padding,
89+
0xff,
90+
i as u32,
91+
)?;
92+
pb_chunk.inc(1);
93+
}
94+
95+
pb_chunk.finish_with_message(format!("segment 0x{:X}", addr));
96+
97+
Ok(())
98+
}
99+
100+
fn finish(&mut self, connection: &mut Connection, reboot: bool) -> Result<(), Error> {
101+
connection.with_timeout(Command::FlashEnd.timeout(), |connection| {
102+
connection.write_command(Command::FlashEnd as u8, &[1][..], 0)
103+
})?;
104+
if reboot {
105+
connection.reset()
106+
} else {
107+
Ok(())
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)