mirror of
https://github.com/gnxlxnxx/cargo-dfu.git
synced 2026-07-27 15:23:02 +02:00
Compare commits
6
Commits
4e2c0f79a6
...
6b79d67ff8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b79d67ff8 | ||
|
|
504ae4e4f0
|
||
|
|
c88e6db3c3
|
||
|
|
a7f1125c94
|
||
|
|
e71d9f9dd4
|
||
|
|
e62d032072
|
Generated
+4
-2
@@ -75,7 +75,7 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cargo-dfu"
|
name = "cargo-dfu"
|
||||||
version = "0.0.3"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo-project",
|
"cargo-project",
|
||||||
"colored",
|
"colored",
|
||||||
@@ -156,7 +156,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dfu"
|
name = "dfu"
|
||||||
version = "0.4.3"
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb1d1eb7e47b3cba338775698712a8cb285aa15d45e58329c59411a55fbc1b98"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"nix",
|
"nix",
|
||||||
|
|||||||
+2
-5
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cargo-dfu"
|
name = "cargo-dfu"
|
||||||
authors = ["Roman Kretschmer <roman@kretschmer.email>"]
|
authors = ["Roman Kretschmer <roman@kretschmer.email>"]
|
||||||
version = "0.0.3"
|
version = "0.0.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "cargo extension for flashing embedded rust programs via dfu"
|
description = "cargo extension for flashing embedded rust programs via dfu"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -22,7 +22,4 @@ cargo-project = "0.2.4"
|
|||||||
structopt = "0.3.2"
|
structopt = "0.3.2"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
dfu = {version = "0.4", path = "/home/roman/dfuflash/dfu"}
|
dfu = "0.4"
|
||||||
|
|
||||||
#[dependencies.dfu]
|
|
||||||
# path = "/home/roman/dfuflash/dfu"
|
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ cargo dfu <args> --vid <vid> --pid <pid>
|
|||||||
cargo dfu
|
cargo dfu
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### specifying the chip
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo dfu --chip stm32
|
||||||
|
```
|
||||||
|
|
||||||
#### specifying the vid and pid
|
#### specifying the vid and pid
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -36,8 +42,12 @@ cargo dfu --vid 0x483 --pid 0xdf11
|
|||||||
## Add chip definitions
|
## Add chip definitions
|
||||||
feel free to open a PR to add chips to this
|
feel free to open a PR to add chips to this
|
||||||
|
|
||||||
## Roadmap
|
## Notes
|
||||||
- [ ] add chip to vendor map so one can optionally use --chip to specify the desired chip
|
some chips like the gd32vf103 need additional udev rules therefor you need to copy the rules from the udev file into /etc/udev/rules.d/
|
||||||
- [ ] add some more chips to the crate (like the gd32vf103)
|
```lang=bash
|
||||||
- [ ] make this crate multi-platform (PR to either the dfu crate to use rusb or the usbapi to add platform support)
|
sudo cp udev.rules /etc/udev/rules.d/cargo-dfu.rules
|
||||||
|
```
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
- [ ] make this crate multi-platform (PR to either the dfu crate to use rusb or the usbapi to add platform support)
|
||||||
|
- [ ] check if multiple chips are connected
|
||||||
|
|||||||
+32
-6
@@ -17,6 +17,13 @@ fn main() {
|
|||||||
// Skip the first arg which is the calling application name.
|
// Skip the first arg which is the calling application name.
|
||||||
let opt = Opt::from_iter(std::env::args().skip(1));
|
let opt = Opt::from_iter(std::env::args().skip(1));
|
||||||
|
|
||||||
|
if opt.list_chips {
|
||||||
|
for vendor in vendor_map() {
|
||||||
|
println!("{}", vendor.0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Try and get the cargo project information.
|
// Try and get the cargo project information.
|
||||||
let project = cargo_project::Project::query(".").expect("Couldn't parse the Cargo.toml");
|
let project = cargo_project::Project::query(".").expect("Couldn't parse the Cargo.toml");
|
||||||
|
|
||||||
@@ -51,7 +58,7 @@ fn main() {
|
|||||||
|
|
||||||
// todo, keep as iter. difficult because we want to filter map remove two items at once.
|
// todo, keep as iter. difficult because we want to filter map remove two items at once.
|
||||||
// Remove our args as cargo build does not understand them.
|
// Remove our args as cargo build does not understand them.
|
||||||
let flags = ["--pid", "--vid"].iter();
|
let flags = ["--pid", "--vid", "--chip"].iter();
|
||||||
for flag in flags {
|
for flag in flags {
|
||||||
if let Some(index) = args.iter().position(|x| x == flag) {
|
if let Some(index) = args.iter().position(|x| x == flag) {
|
||||||
args.remove(index);
|
args.remove(index);
|
||||||
@@ -76,6 +83,22 @@ fn main() {
|
|||||||
let d = if let (Some(v), Some(p)) = (opt.vid, opt.pid) {
|
let d = if let (Some(v), Some(p)) = (opt.vid, opt.pid) {
|
||||||
open_device_with_vid_pid(v, p)
|
open_device_with_vid_pid(v, p)
|
||||||
.expect("Are you sure device is plugged in and in bootloader mode?")
|
.expect("Are you sure device is plugged in and in bootloader mode?")
|
||||||
|
} else if let Some(c) = opt.chip {
|
||||||
|
println!(" {} for a connected {}.", "Searching".green().bold(), c);
|
||||||
|
|
||||||
|
let mut device: Option<rusb::DeviceHandle<GlobalContext>> = None;
|
||||||
|
|
||||||
|
let vendor = vendor_map();
|
||||||
|
|
||||||
|
if let Some(products) = vendor.get(&c) {
|
||||||
|
for (v, p) in products {
|
||||||
|
if let Some(d) = open_device_with_vid_pid(*v, *p) {
|
||||||
|
device = Some(d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
device.expect("Are you sure device is plugged in and in bootloader mode?")
|
||||||
} else {
|
} else {
|
||||||
println!(
|
println!(
|
||||||
" {} for a connected device with known vid/pid pair.",
|
" {} for a connected device with known vid/pid pair.",
|
||||||
@@ -90,11 +113,9 @@ fn main() {
|
|||||||
|
|
||||||
let mut device: Option<rusb::DeviceHandle<GlobalContext>> = None;
|
let mut device: Option<rusb::DeviceHandle<GlobalContext>> = None;
|
||||||
|
|
||||||
let vendor = vendor_map();
|
|
||||||
|
|
||||||
for d in devices {
|
for d in devices {
|
||||||
if let Some(products) = vendor.get(&d.vendor_id()) {
|
for vendor in vendor_map() {
|
||||||
if products.contains(&d.product_id()) {
|
if vendor.1.contains(&(d.vendor_id(), d.product_id())) {
|
||||||
if let Some(d) = open_device_with_vid_pid(d.vendor_id(), d.product_id()) {
|
if let Some(d) = open_device_with_vid_pid(d.vendor_id(), d.product_id()) {
|
||||||
device = Some(d);
|
device = Some(d);
|
||||||
break;
|
break;
|
||||||
@@ -107,7 +128,7 @@ fn main() {
|
|||||||
|
|
||||||
println!(
|
println!(
|
||||||
" {} {} {}",
|
" {} {} {}",
|
||||||
"Trying ".green().bold(),
|
"Found ".green().bold(),
|
||||||
d.read_manufacturer_string_ascii(&d.device().device_descriptor().unwrap())
|
d.read_manufacturer_string_ascii(&d.device().device_descriptor().unwrap())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
d.read_product_string_ascii(&d.device().device_descriptor().unwrap())
|
d.read_product_string_ascii(&d.device().device_descriptor().unwrap())
|
||||||
@@ -182,4 +203,9 @@ struct Opt {
|
|||||||
pid: Option<u16>,
|
pid: Option<u16>,
|
||||||
#[structopt(name = "vid", long = "vid", parse(try_from_str = parse_hex_16))]
|
#[structopt(name = "vid", long = "vid", parse(try_from_str = parse_hex_16))]
|
||||||
vid: Option<u16>,
|
vid: Option<u16>,
|
||||||
|
|
||||||
|
#[structopt(name = "chip", long = "chip")]
|
||||||
|
chip: Option<String>,
|
||||||
|
#[structopt(name = "list-chips", long = "list-chips")]
|
||||||
|
list_chips: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-7
@@ -8,14 +8,15 @@ use std::{fs::File, io::Read};
|
|||||||
pub enum UtilError {
|
pub enum UtilError {
|
||||||
Elf(goblin::error::Error),
|
Elf(goblin::error::Error),
|
||||||
Dfu(dfu::error::Error),
|
Dfu(dfu::error::Error),
|
||||||
File(std::io::Error)
|
File(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a contiguous bin with 0s between non-contiguous sections and starting address from an elf.
|
/// Returns a contiguous bin with 0s between non-contiguous sections and starting address from an elf.
|
||||||
pub fn elf_to_bin(path: PathBuf) -> Result<(Vec<u8>, u32), UtilError> {
|
pub fn elf_to_bin(path: PathBuf) -> Result<(Vec<u8>, u32), UtilError> {
|
||||||
let mut file = File::open(path).map_err(|e| UtilError::File(e))?;
|
let mut file = File::open(path).map_err(|e| UtilError::File(e))?;
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
file.read_to_end(&mut buffer).map_err(|e| UtilError::File(e))?;
|
file.read_to_end(&mut buffer)
|
||||||
|
.map_err(|e| UtilError::File(e))?;
|
||||||
|
|
||||||
let binary = goblin::elf::Elf::parse(buffer.as_slice()).map_err(|e| UtilError::Elf(e))?;
|
let binary = goblin::elf::Elf::parse(buffer.as_slice()).map_err(|e| UtilError::Elf(e))?;
|
||||||
|
|
||||||
@@ -58,9 +59,11 @@ pub fn flash_bin(
|
|||||||
address: u32,
|
address: u32,
|
||||||
d: &rusb::Device<GlobalContext>,
|
d: &rusb::Device<GlobalContext>,
|
||||||
) -> Result<(), UtilError> {
|
) -> Result<(), UtilError> {
|
||||||
let mut dfu = dfu::Dfu::from_bus_device(d.bus_number(), d.address(), 0_u32, 0_u32).map_err(|e| UtilError::Dfu(e))?;
|
let mut dfu = dfu::Dfu::from_bus_device(d.bus_number(), d.address(), 0_u32, 0_u32)
|
||||||
|
.map_err(|e| UtilError::Dfu(e))?;
|
||||||
if binary.len() < 2048 {
|
if binary.len() < 2048 {
|
||||||
dfu.write_flash_from_slice(address, binary).map_err(|e| UtilError::Dfu(e))?;
|
dfu.write_flash_from_slice(address, binary)
|
||||||
|
.map_err(|e| UtilError::Dfu(e))?;
|
||||||
} else {
|
} else {
|
||||||
// hacky bug workaround
|
// hacky bug workaround
|
||||||
std::fs::write("target/out.bin", binary).map_err(|e| UtilError::File(e))?;
|
std::fs::write("target/out.bin", binary).map_err(|e| UtilError::File(e))?;
|
||||||
@@ -71,15 +74,17 @@ pub fn flash_bin(
|
|||||||
.map_err(|e| UtilError::File(e))?,
|
.map_err(|e| UtilError::File(e))?,
|
||||||
address,
|
address,
|
||||||
None,
|
None,
|
||||||
).map_err(|e| UtilError::Dfu(e))?;
|
)
|
||||||
|
.map_err(|e| UtilError::Dfu(e))?;
|
||||||
std::fs::remove_file("target/out.bin").map_err(|e| UtilError::File(e))?;
|
std::fs::remove_file("target/out.bin").map_err(|e| UtilError::File(e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vendor_map() -> std::collections::HashMap<u16, Vec<u16>> {
|
pub fn vendor_map() -> std::collections::HashMap<String, Vec<(u16, u16)>> {
|
||||||
maplit::hashmap! {
|
maplit::hashmap! {
|
||||||
0x0483 => vec![0xdf11],
|
"stm32".to_string() => vec![(0x0483, 0xdf11)],
|
||||||
|
"gd32vf103".to_string() => vec![(0x28e9, 0x0189)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# gd32vf103
|
||||||
|
SUBSYSTEMS=="usb" ATTRS{idVendor}=="28e9" ATTRS{idProduct}=="0189" MODE:="0666"
|
||||||
Reference in New Issue
Block a user