Initial
This commit is contained in:
commit
dcd89f09f7
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
2427
Cargo.lock
generated
Normal file
2427
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "web-flash"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.5.0-rc.2"
|
||||
espflash = { version = "1.5.2-dev", git = "https://github.com/esp-rs/espflash", branch = "bugfix/chip-name-esptool" }
|
||||
clap = { version = "3.1.18", features=["env"] }
|
||||
opener = "0.5.0"
|
||||
anyhow = "1.0.57"
|
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# esp-web-flash-server
|
||||
|
||||
Starts a local server serving a web page to flash a given ELF file.
|
||||
|
||||
```
|
||||
web-flash 0.1.0
|
||||
|
||||
USAGE:
|
||||
web-flash.exe [OPTIONS] --chip <CHIP> <ELF>
|
||||
|
||||
ARGS:
|
||||
<ELF>
|
||||
|
||||
OPTIONS:
|
||||
-b, --bootloader <BOOTLOADER> path to bootloader
|
||||
-c, --chip <CHIP> chip name
|
||||
-h, --help Print help information
|
||||
-p, --partition-table <PARTITION_TABLE> path to partition table csv
|
||||
-V, --version Print version information
|
||||
```
|
164
src/main.rs
Normal file
164
src/main.rs
Normal file
@ -0,0 +1,164 @@
|
||||
use ::rocket::async_main;
|
||||
use anyhow::Result;
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
|
||||
use clap::Parser;
|
||||
use espflash::{elf::FirmwareImageBuilder, Chip, FlashSize, PartitionTable};
|
||||
use rocket::{response::content, State};
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// chip name
|
||||
#[clap(short, long)]
|
||||
chip: Chip,
|
||||
|
||||
/// path to bootloader
|
||||
#[clap(short, long)]
|
||||
bootloader: Option<PathBuf>,
|
||||
|
||||
/// path to partition table csv
|
||||
#[clap(short, long)]
|
||||
partition_table: Option<PathBuf>,
|
||||
|
||||
elf: PathBuf,
|
||||
}
|
||||
|
||||
#[get("/bootloader.bin")]
|
||||
fn bootloader(data: &State<PartsData>) -> Vec<u8> {
|
||||
data.bootloader.clone()
|
||||
}
|
||||
|
||||
#[get("/partitions.bin")]
|
||||
fn partitions(data: &State<PartsData>) -> Vec<u8> {
|
||||
data.partitions.clone()
|
||||
}
|
||||
|
||||
#[get("/firmware.bin")]
|
||||
fn firmware(data: &State<PartsData>) -> Vec<u8> {
|
||||
data.firmware.clone()
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> content::RawHtml<&'static str> {
|
||||
content::RawHtml(
|
||||
"
|
||||
<html>
|
||||
<script
|
||||
type=\"module\"
|
||||
src=\"https://unpkg.com/esp-web-tools@8.0.2/dist/web/install-button.js?module\">
|
||||
</script>
|
||||
<body>
|
||||
|
||||
<esp-web-install-button
|
||||
manifest=\"/manifest.json\">
|
||||
</esp-web-install-button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[get("/manifest.json")]
|
||||
fn manifest(data: &State<PartsData>) -> content::RawJson<String> {
|
||||
content::RawJson(format!(
|
||||
r#"
|
||||
{{
|
||||
"name": "Something",
|
||||
"version": "1",
|
||||
"home_assistant_domain": "esphome",
|
||||
"funding_url": "https://esphome.io/guides/supporters.html",
|
||||
"new_install_prompt_erase": false,
|
||||
"builds": [
|
||||
{{
|
||||
"chipFamily": "{}",
|
||||
"parts": [
|
||||
{{ "path": "bootloader.bin", "offset": 4096 }},
|
||||
{{ "path": "partitions.bin", "offset": 32768 }},
|
||||
{{ "path": "firmware.bin", "offset": 65536 }}
|
||||
]
|
||||
}}
|
||||
]
|
||||
}}
|
||||
"#,
|
||||
data.chip
|
||||
))
|
||||
}
|
||||
|
||||
struct PartsData {
|
||||
chip: String,
|
||||
bootloader: Vec<u8>,
|
||||
partitions: Vec<u8>,
|
||||
firmware: Vec<u8>,
|
||||
}
|
||||
|
||||
fn prepare() -> Result<PartsData> {
|
||||
let opts = Args::parse();
|
||||
|
||||
let elf = std::fs::read(opts.elf)?;
|
||||
|
||||
let p = if let Some(p) = &opts.partition_table {
|
||||
Some(PartitionTable::try_from_bytes(std::fs::read(p)?)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let b = if let Some(p) = &opts.bootloader {
|
||||
Some(std::fs::read(p)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let firmware = FirmwareImageBuilder::new(&elf)
|
||||
.flash_size(Some(FlashSize::Flash4Mb)) // TODO make configurable
|
||||
.build()?;
|
||||
|
||||
let chip = opts.chip;
|
||||
let chip_name = match chip {
|
||||
Chip::Esp32 => "ESP32",
|
||||
Chip::Esp32c3 => "ESP32-C3",
|
||||
Chip::Esp32s2 => "ESP32-S2",
|
||||
Chip::Esp32s3 => "ESP32-S3",
|
||||
Chip::Esp8266 => "ESP8266",
|
||||
};
|
||||
|
||||
let image = chip.get_flash_image(&firmware, b, p, None, None)?;
|
||||
let parts: Vec<_> = image.flash_segments().collect();
|
||||
let bootloader = &parts[0];
|
||||
let partitions = &parts[1];
|
||||
let app = &parts[2];
|
||||
|
||||
Ok(PartsData {
|
||||
chip: chip_name.to_string(),
|
||||
bootloader: bootloader.data.to_vec(),
|
||||
partitions: partitions.data.to_vec(),
|
||||
firmware: app.data.to_vec(),
|
||||
})
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let data = prepare()?;
|
||||
|
||||
std::thread::spawn(|| {
|
||||
std::thread::sleep(Duration::from_millis(1000));
|
||||
opener::open_browser("http://127.0.0.1:8000/").ok();
|
||||
});
|
||||
|
||||
async_main(async move {
|
||||
let _res = rocket::build()
|
||||
.mount(
|
||||
"/",
|
||||
routes![index, manifest, bootloader, partitions, firmware],
|
||||
)
|
||||
.manage(data)
|
||||
.launch()
|
||||
.await
|
||||
.expect("Problem launching server");
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user