Skip to content

Commit 2e9347d

Browse files
authored
Merge pull request #141 from MabezDev/feature/firmware-header
Customize firmware image header
2 parents c6d5b0f + 682d7da commit 2e9347d

File tree

14 files changed

+429
-175
lines changed

14 files changed

+429
-175
lines changed

.github/workflows/rust.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ jobs:
115115
with:
116116
command: clippy
117117
# `identity_op` and `or_fun_call` leads to false positives
118-
args: -- -D warnings -A clippy::identity_op -A clippy::or_fun_call
118+
# `too-many-arguments` is relatively arbitrary
119+
args: -- -D warnings -A clippy::identity_op -A clippy::or_fun_call -A clippy::too-many-arguments
119120

120121
build:
121122
name: Build Static Binaries

cargo-espflash/src/main.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use clap::Parser;
1010
use espflash::{
1111
cli::{
1212
board_info, connect, flash_elf_image, monitor::monitor, save_elf_as_image, ConnectOpts,
13-
FlashOpts,
13+
FlashConfigOpts, FlashOpts,
1414
},
1515
Chip, Config, ImageFormatId,
1616
};
@@ -81,12 +81,14 @@ pub struct BuildOpts {
8181
/// Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
8282
#[clap(short = 'Z')]
8383
pub unstable: Option<Vec<String>>,
84+
#[clap(flatten)]
85+
pub flash_config_opts: FlashConfigOpts,
8486
}
8587

8688
#[derive(Parser)]
8789
pub struct SaveImageOpts {
8890
#[clap(flatten)]
89-
pub build_args: BuildOpts,
91+
pub build_opts: BuildOpts,
9092
/// File name to save the generated image to
9193
pub file: PathBuf,
9294
}
@@ -160,6 +162,9 @@ fn flash(
160162
bootloader,
161163
partition_table,
162164
image_format,
165+
opts.build_opts.flash_config_opts.flash_mode,
166+
opts.build_opts.flash_config_opts.flash_size,
167+
opts.build_opts.flash_config_opts.flash_freq,
163168
)?;
164169
}
165170

@@ -282,7 +287,6 @@ fn build(
282287

283288
// If no target artifact was found, we don't have a path to return.
284289
let target_artifact = target_artifact.ok_or(Error::NoArtifact)?;
285-
286290
let artifact_path = target_artifact.executable.unwrap().into();
287291

288292
Ok(artifact_path)
@@ -294,7 +298,7 @@ fn save_image(
294298
cargo_config: CargoConfig,
295299
) -> Result<()> {
296300
let target = opts
297-
.build_args
301+
.build_opts
298302
.target
299303
.as_deref()
300304
.or_else(|| cargo_config.target())
@@ -303,18 +307,26 @@ fn save_image(
303307

304308
let chip = Chip::from_target(target).ok_or_else(|| Error::UnknownTarget(target.into()))?;
305309

306-
let path = build(&opts.build_args, &cargo_config, Some(chip))?;
310+
let path = build(&opts.build_opts, &cargo_config, Some(chip))?;
307311
let elf_data = fs::read(path).into_diagnostic()?;
308312

309313
let image_format = opts
310-
.build_args
314+
.build_opts
311315
.format
312316
.as_deref()
313317
.map(ImageFormatId::from_str)
314318
.transpose()?
315319
.or(metadata.format);
316320

317-
save_elf_as_image(chip, &elf_data, opts.file, image_format)?;
321+
save_elf_as_image(
322+
chip,
323+
&elf_data,
324+
opts.file,
325+
image_format,
326+
opts.build_opts.flash_config_opts.flash_mode,
327+
opts.build_opts.flash_config_opts.flash_size,
328+
opts.build_opts.flash_config_opts.flash_freq,
329+
)?;
318330

319331
Ok(())
320332
}

espflash/src/chip/esp32/esp32.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,12 @@ impl Esp32 {
183183
fn test_esp32_rom() {
184184
use std::fs::read;
185185

186+
use crate::elf::FirmwareImageBuilder;
187+
186188
let input_bytes = read("./tests/data/esp32").unwrap();
187189
let expected_bin = read("./tests/data/esp32.bin").unwrap();
188190

189-
let image = FirmwareImage::from_data(&input_bytes).unwrap();
191+
let image = FirmwareImageBuilder::new(&input_bytes).build().unwrap();
190192
let flash_image = Esp32BootloaderFormat::new(&image, Chip::Esp32, PARAMS, None, None).unwrap();
191193

192194
let segments = flash_image.flash_segments().collect::<Vec<_>>();

espflash/src/chip/esp8266.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,12 @@ impl ReadEFuse for Esp8266 {
9090
fn test_esp8266_rom() {
9191
use std::fs::read;
9292

93+
use crate::elf::FirmwareImageBuilder;
94+
9395
let input_bytes = read("./tests/data/esp8266").unwrap();
9496
let expected_bin = read("./tests/data/esp8266.bin").unwrap();
9597

96-
let image = FirmwareImage::from_data(&input_bytes).unwrap();
98+
let image = FirmwareImageBuilder::new(&input_bytes).build().unwrap();
9799
let flash_image = Esp8266Format::new(&image).unwrap();
98100

99101
let segments = flash_image.flash_segments().collect::<Vec<_>>();

espflash/src/cli/mod.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ use clap::Parser;
1111
use config::Config;
1212
use miette::{IntoDiagnostic, Result, WrapErr};
1313
use serialport::{FlowControl, SerialPortType};
14+
use strum::VariantNames;
1415

1516
use crate::{
16-
cli::serial::get_serial_port_info, error::Error, Chip, FirmwareImage, Flasher, ImageFormatId,
17-
PartitionTable,
17+
cli::serial::get_serial_port_info,
18+
elf::{FirmwareImageBuilder, FlashFrequency, FlashMode},
19+
error::Error,
20+
flasher::FlashSize,
21+
Chip, Flasher, ImageFormatId, PartitionTable,
1822
};
1923

2024
pub mod config;
@@ -48,6 +52,19 @@ pub struct FlashOpts {
4852
pub monitor: bool,
4953
}
5054

55+
#[derive(Parser)]
56+
pub struct FlashConfigOpts {
57+
/// Flash mode to use
58+
#[clap(short = 'm', long, possible_values = FlashMode::VARIANTS, value_name = "MODE")]
59+
pub flash_mode: Option<FlashMode>,
60+
/// Flash size of the target
61+
#[clap(short = 's', long, possible_values = FlashSize::VARIANTS, value_name = "SIZE")]
62+
pub flash_size: Option<FlashSize>,
63+
/// Flash frequency
64+
#[clap(short = 'f', long, possible_values = FlashFrequency::VARIANTS, value_name = "FREQUENCY")]
65+
pub flash_freq: Option<FlashFrequency>,
66+
}
67+
5168
pub fn connect(opts: &ConnectOpts, config: &Config) -> Result<Flasher> {
5269
let port_info = get_serial_port_info(opts, config)?;
5370

@@ -82,8 +99,15 @@ pub fn save_elf_as_image(
8299
elf_data: &[u8],
83100
path: PathBuf,
84101
image_format: Option<ImageFormatId>,
102+
flash_mode: Option<FlashMode>,
103+
flash_size: Option<FlashSize>,
104+
flash_freq: Option<FlashFrequency>,
85105
) -> Result<()> {
86-
let image = FirmwareImage::from_data(elf_data)?;
106+
let image = FirmwareImageBuilder::new(elf_data)
107+
.flash_mode(flash_mode)
108+
.flash_size(flash_size)
109+
.flash_freq(flash_freq)
110+
.build()?;
87111

88112
let flash_image = chip.get_flash_image(&image, None, None, image_format, None)?;
89113
let parts: Vec<_> = flash_image.ota_segments().collect();
@@ -107,6 +131,9 @@ pub fn flash_elf_image(
107131
bootloader: Option<&Path>,
108132
partition_table: Option<&Path>,
109133
image_format: Option<ImageFormatId>,
134+
flash_mode: Option<FlashMode>,
135+
flash_size: Option<FlashSize>,
136+
flash_freq: Option<FlashFrequency>,
110137
) -> Result<()> {
111138
// If the '--bootloader' option is provided, load the binary file at the
112139
// specified path.
@@ -137,7 +164,15 @@ pub fn flash_elf_image(
137164

138165
// Load the ELF data, optionally using the provider bootloader/partition
139166
// table/image format, to the device's flash memory.
140-
flasher.load_elf_to_flash_with_format(elf_data, bootloader, partition_table, image_format)?;
167+
flasher.load_elf_to_flash_with_format(
168+
elf_data,
169+
bootloader,
170+
partition_table,
171+
image_format,
172+
flash_mode,
173+
flash_size,
174+
flash_freq,
175+
)?;
141176
println!("\nFlashing has completed!");
142177

143178
Ok(())

espflash/src/connection.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
error::{ConnectionError, Error, ResultExt, RomError, RomErrorKind},
1616
};
1717

18+
const DEFAULT_CONNECT_ATTEMPTS: usize = 7;
1819
const USB_SERIAL_JTAG_PID: u16 = 0x1001;
1920

2021
#[derive(Debug, Copy, Clone, BinRead)]
@@ -51,6 +52,75 @@ impl Connection {
5152
}
5253
}
5354

55+
pub fn begin(&mut self) -> Result<(), Error> {
56+
let mut extra_delay = false;
57+
for i in 0..DEFAULT_CONNECT_ATTEMPTS {
58+
if self.connect_attempt(extra_delay).is_err() {
59+
extra_delay = !extra_delay;
60+
61+
let delay_text = if extra_delay { "extra" } else { "default" };
62+
println!("Unable to connect, retrying with {} delay...", delay_text);
63+
} else {
64+
// Print a blank line if more than one connection attempt was made to visually
65+
// separate the status text and whatever comes next.
66+
if i > 0 {
67+
println!();
68+
}
69+
return Ok(());
70+
}
71+
}
72+
73+
Err(Error::Connection(ConnectionError::ConnectionFailed))
74+
}
75+
76+
fn connect_attempt(&mut self, extra_delay: bool) -> Result<(), Error> {
77+
self.reset_to_flash(extra_delay)?;
78+
79+
for _ in 0..5 {
80+
self.flush()?;
81+
if self.sync().is_ok() {
82+
return Ok(());
83+
}
84+
}
85+
86+
Err(Error::Connection(ConnectionError::ConnectionFailed))
87+
}
88+
89+
fn sync(&mut self) -> Result<(), Error> {
90+
self.with_timeout(CommandType::Sync.timeout(), |connection| {
91+
connection.write_command(Command::Sync)?;
92+
connection.flush()?;
93+
94+
for _ in 0..100 {
95+
match connection.read_response()? {
96+
Some(response) if response.return_op == CommandType::Sync as u8 => {
97+
if response.status == 1 {
98+
let _error = connection.flush();
99+
return Err(Error::RomError(RomError::new(
100+
CommandType::Sync,
101+
RomErrorKind::from(response.error),
102+
)));
103+
} else {
104+
break;
105+
}
106+
}
107+
_ => continue,
108+
}
109+
}
110+
111+
Ok(())
112+
})?;
113+
114+
for _ in 0..700 {
115+
match self.read_response()? {
116+
Some(_) => break,
117+
_ => continue,
118+
}
119+
}
120+
121+
Ok(())
122+
}
123+
54124
pub fn reset(&mut self) -> Result<(), Error> {
55125
sleep(Duration::from_millis(100));
56126

0 commit comments

Comments
 (0)