9 Commits
Author SHA1 Message Date
gnxlxnxx fa2b286f6b Use clap instead of structopt
- because of the note that they're in maintenance mode: https://github.com/TeXitoi/structopt#maintenance
2022-01-20 11:48:10 +01:00
gnxlxnxx 6b79d67ff8 Update Readme 2021-11-26 19:12:53 +01:00
gnxlxnxx 504ae4e4f0 Use stm32 instead of stm32f4
- the vid and pid seem to be the same across all stm32 devices
2021-11-26 19:11:59 +01:00
gnxlxnxx c88e6db3c3 Update Readme 2021-11-26 18:49:49 +01:00
gnxlxnxx a7f1125c94 add udev rules 2021-11-26 18:49:24 +01:00
gnxlxnxx e71d9f9dd4 Update Cargo.toml 2021-11-26 18:48:54 +01:00
gnxlxnxx e62d032072 Add --chip option 2021-11-26 18:48:11 +01:00
gnxlxnxx 4e2c0f79a6 Update Cargo.toml 2021-11-14 13:36:49 +01:00
gnxlxnxx ce89c2d469 Update Cargo.toml 2021-11-14 13:33:55 +01:00
6 changed files with 141 additions and 110 deletions
Generated
+57 -72
View File
@@ -26,15 +26,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@@ -75,9 +66,10 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]] [[package]]
name = "cargo-dfu" name = "cargo-dfu"
version = "0.0.1" version = "0.0.4"
dependencies = [ dependencies = [
"cargo-project", "cargo-project",
"clap",
"colored", "colored",
"dfu", "dfu",
"goblin", "goblin",
@@ -85,7 +77,6 @@ dependencies = [
"maplit", "maplit",
"pretty_env_logger", "pretty_env_logger",
"rusb", "rusb",
"structopt",
] ]
[[package]] [[package]]
@@ -130,17 +121,32 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.3" version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
dependencies = [ dependencies = [
"ansi_term",
"atty", "atty",
"bitflags", "bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim", "strsim",
"termcolor",
"textwrap", "textwrap",
"unicode-width", ]
"vec_map",
[[package]]
name = "clap_derive"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
] ]
[[package]] [[package]]
@@ -156,7 +162,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",
@@ -223,13 +231,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "heck" name = "hashbrown"
version = "0.3.3" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"unicode-segmentation", [[package]]
] name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@@ -249,6 +260,16 @@ dependencies = [
"quick-error", "quick-error",
] ]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -354,6 +375,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.22" version = "0.3.22"
@@ -509,33 +539,9 @@ dependencies = [
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
dependencies = [
"clap",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "syn" name = "syn"
@@ -580,12 +586,9 @@ dependencies = [
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "time" name = "time"
@@ -607,18 +610,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.2" version = "0.2.2"
@@ -643,12 +634,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.3" version = "0.9.3"
+8 -6
View File
@@ -1,10 +1,15 @@
[package] [package]
name = "cargo-dfu" name = "cargo-dfu"
authors = ["Roman Kretschmer <roman@kretschmer.email>"] authors = ["Roman Kretschmer <roman@kretschmer.email>"]
version = "0.0.1" 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"
homepage = "https://github.com/gnxlxnxx/cargo-dfu"
repository = "https://github.com/gnxlxnxx/cargo-dfu.git"
categories = ["embedded", "hardware-support"]
keywords = ["dfu", "flashing", "embedded"]
readme = "Readme.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -14,10 +19,7 @@ colored = "2.0.0"
rusb = "0.9.0" rusb = "0.9.0"
pretty_env_logger = "0.3.0" pretty_env_logger = "0.3.0"
cargo-project = "0.2.4" cargo-project = "0.2.4"
structopt = "0.3.2" clap = {version = "3.0.10", features=["derive"]}
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"
+14 -4
View File
@@ -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
+48 -21
View File
@@ -4,10 +4,11 @@ use crate::utils::{elf_to_bin, flash_bin, vendor_map};
use colored::*; use colored::*;
use rusb::{open_device_with_vid_pid, GlobalContext}; use rusb::{open_device_with_vid_pid, GlobalContext};
use clap::Parser;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::time::Instant; use std::time::Instant;
use structopt::StructOpt; // use structopt::StructOpt;
fn main() { fn main() {
// Initialize the logging backend. // Initialize the logging backend.
@@ -15,7 +16,14 @@ fn main() {
// Get commandline options. // Get commandline options.
// 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::parse_from(std::env::args());
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 +59,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 +84,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 +114,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 +129,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())
@@ -155,31 +177,36 @@ fn parse_hex_16(input: &str) -> Result<u16, std::num::ParseIntError> {
} }
} }
#[allow(unused)] #[derive(Debug, Parser)]
#[derive(Debug, StructOpt)] #[clap(author, version, about, long_about = None)]
struct Opt { struct Opt {
// `cargo build` arguments // `cargo build` arguments
#[structopt(name = "binary", long = "bin")] #[clap(name = "binary", long = "bin")]
bin: Option<String>, bin: Option<String>,
#[structopt(name = "example", long = "example")] #[clap(name = "example", long = "example")]
example: Option<String>, example: Option<String>,
#[structopt(name = "package", short = "p", long = "package")] #[clap(name = "package", short = 'p', long = "package")]
package: Option<String>, package: Option<String>,
#[structopt(name = "release", long = "release")] #[clap(name = "release", long = "release")]
release: bool, release: bool,
#[structopt(name = "target", long = "target")] #[clap(name = "target", long = "target")]
target: Option<String>, target: Option<String>,
#[structopt(name = "PATH", long = "manifest-path", parse(from_os_str))] #[clap(name = "PATH", long = "manifest-path", parse(from_os_str))]
manifest_path: Option<PathBuf>, manifest_path: Option<PathBuf>,
#[structopt(long)] #[clap(long)]
no_default_features: bool, no_default_features: bool,
#[structopt(long)] #[clap(long)]
all_features: bool, all_features: bool,
#[structopt(long)] #[clap(long)]
features: Vec<String>, features: Vec<String>,
#[structopt(name = "pid", long = "pid", parse(try_from_str = parse_hex_16))] #[clap(name = "pid", long = "pid", parse(try_from_str = parse_hex_16))]
pid: Option<u16>, pid: Option<u16>,
#[structopt(name = "vid", long = "vid", parse(try_from_str = parse_hex_16))] #[clap(name = "vid", long = "vid", parse(try_from_str = parse_hex_16))]
vid: Option<u16>, vid: Option<u16>,
#[clap(name = "chip", long = "chip")]
chip: Option<String>,
#[clap(name = "list-chips", long = "list-chips")]
list_chips: bool,
} }
+12 -7
View File
@@ -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)],
} }
} }
+2
View File
@@ -0,0 +1,2 @@
# gd32vf103
SUBSYSTEMS=="usb" ATTRS{idVendor}=="28e9" ATTRS{idProduct}=="0189" MODE:="0666"