From bccdc9a3c410413b9f2a94e89add0e21fae99c2a Mon Sep 17 00:00:00 2001 From: gnxlxnxx Date: Sun, 14 Nov 2021 13:08:05 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 1 + Cargo.lock | 693 +++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 21 ++ LICENSE.md | 10 + Readme.md | 43 ++++ src/main.rs | 185 ++++++++++++++ src/utils.rs | 85 +++++++ 7 files changed, 1038 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE.md create mode 100644 Readme.md create mode 100644 src/main.rs create mode 100644 src/utils.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fcaba63 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,693 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cargo-dfu" +version = "0.0.1" +dependencies = [ + "cargo-project", + "colored", + "dfu", + "goblin", + "log", + "maplit", + "pretty_env_logger", + "rusb", + "structopt", +] + +[[package]] +name = "cargo-project" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e57b974bffaf97c6a66551e4f947e34637ec25f35aaf9b45f03326a9e3874f" +dependencies = [ + "failure", + "glob", + "log", + "rustc-cfg", + "serde", + "serde_derive", + "toml", +] + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "dfu" +version = "0.4.3" +dependencies = [ + "log", + "nix", + "serde", + "usbapi", +] + +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "goblin" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" + +[[package]] +name = "libusb1-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8772b7e8d4d988e19684aec5a3f5e470ecaf5c705cf0303da3973508e873027" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "nix" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + +[[package]] +name = "pkg-config" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "pretty_env_logger" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" +dependencies = [ + "chrono", + "env_logger", + "log", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rusb" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b454219aa5007af92a042ec13b2035325318a21d3c6be18bf592f841430794" +dependencies = [ + "libc", + "libusb1-sys", +] + +[[package]] +name = "rustc-cfg" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad221fe7cd09334f8735dcc157b1178e343f43dfaefcd1b09d7fd4fc0921b6f" +dependencies = [ + "failure", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[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]] +name = "syn" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "sysfs-serde" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95eb4a78bc7d9d0bbc4a4cd2f5d2756e67e27a4d11bb52df6406508dae15066a" +dependencies = [ + "log", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +dependencies = [ + "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]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "usbapi" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc33ce833e969eaf16937f8ec81bd10e52428159e4d45dd3d70b0c0f6558e416" +dependencies = [ + "libc", + "log", + "nix", + "sysfs-serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..81b2592 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cargo-dfu" +authors = ["Roman Kretschmer "] +version = "0.0.1" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +goblin = "0.2.3" +colored = "2.0.0" +rusb = "0.9.0" +pretty_env_logger = "0.3.0" +cargo-project = "0.2.4" +structopt = "0.3.2" +maplit = "1.0.2" +log = "0.4.6" +dfu = {version = "0.4", path = "/home/roman/dfuflash/dfu"} + +#[dependencies.dfu] +# path = "/home/roman/dfuflash/dfu" diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..04945f8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,10 @@ + The MIT License (MIT) + +Copyright © 2021 Roman Kretschmer and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..30be516 --- /dev/null +++ b/Readme.md @@ -0,0 +1,43 @@ +# cargo-dfu + +This crate provides a cargo subcommand to flash ELF binaries via dfu +Most STM chips will probably work with this, although you might need to add the vid and pid to the vendor map + +## Installation + +You can install this utility with cargo: + +```bash +cargo install cargo-dfu +``` + +## Usage + +You can use it like cargo build or cargo-flash with the option of giving the vid and pid: + +```bash +cargo dfu --vid --pid +``` + +### Examples + +#### flash the debug version of the current crate + +```bash +cargo dfu +``` + +#### specifying the vid and pid + +```bash +cargo dfu --vid 0x483 --pid 0xdf11 +``` + +## Add chip definitions +feel free to open a PR to add chips to this + +## Roadmap +- [ ] add chip to vendor map so one can optionally use --chip to specify the desired chip +- [ ] add some more chips to the crate (like the gd32vf103) +- [ ] make this crate multi-platform (PR to either the dfu crate to use rusb or the usbapi to add platform support) + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..a1c96cf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,185 @@ +mod utils; + +use crate::utils::{elf_to_bin, flash_bin, vendor_map}; +use colored::*; +use rusb::{open_device_with_vid_pid, GlobalContext}; + +use std::path::PathBuf; +use std::process::{Command, Stdio}; +use std::time::Instant; +use structopt::StructOpt; + +fn main() { + // Initialize the logging backend. + pretty_env_logger::init(); + + // Get commandline options. + // Skip the first arg which is the calling application name. + let opt = Opt::from_iter(std::env::args().skip(1)); + + // Try and get the cargo project information. + let project = cargo_project::Project::query(".").expect("Couldn't parse the Cargo.toml"); + + // Decide what artifact to use. + let artifact = if let Some(bin) = &opt.bin { + cargo_project::Artifact::Bin(bin) + } else if let Some(example) = &opt.example { + cargo_project::Artifact::Example(example) + } else { + cargo_project::Artifact::Bin(project.name()) + }; + + // Decide what profile to use. + let profile = if opt.release { + cargo_project::Profile::Release + } else { + cargo_project::Profile::Dev + }; + + // Try and get the artifact path. + let path = project + .path( + artifact, + profile, + opt.target.as_deref(), + "x86_64-unknown-linux-gnu", + ) + .expect("Couldn't find the build result"); + + // Remove first two args which is the calling application name and the `dfu` command from cargo. + let mut args: Vec<_> = std::env::args().skip(2).collect(); + + // 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. + let flags = ["--pid", "--vid"].iter(); + for flag in flags { + if let Some(index) = args.iter().position(|x| x == flag) { + args.remove(index); + args.remove(index); + } + } + + let status = Command::new("cargo") + .arg("build") + .args(args) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn() + .unwrap() + .wait() + .unwrap(); + + if !status.success() { + exit_with_process_status(status) + } + + let d = if let (Some(v), Some(p)) = (opt.vid, opt.pid) { + open_device_with_vid_pid(v, p) + .expect("Are you sure device is plugged in and in bootloader mode?") + } else { + println!( + " {} for a connected device with known vid/pid pair.", + "Searching".green().bold(), + ); + + let devices: Vec<_> = rusb::devices() + .expect("Error with Libusb") + .iter() + .map(|d| d.device_descriptor().unwrap()) + .collect(); + + let mut device: Option> = None; + + let vendor = vendor_map(); + + for d in devices { + if let Some(products) = vendor.get(&d.vendor_id()) { + if products.contains(&d.product_id()) { + if let Some(d) = open_device_with_vid_pid(d.vendor_id(), d.product_id()) { + device = Some(d); + break; + } + } + } + } + device.expect("Are you sure device is plugged in and in bootloader mode?") + }; + + println!( + " {} {} {}", + "Trying ".green().bold(), + d.read_manufacturer_string_ascii(&d.device().device_descriptor().unwrap()) + .unwrap(), + d.read_product_string_ascii(&d.device().device_descriptor().unwrap()) + .unwrap() + ); + + println!(" {} {:?}", "Flashing".green().bold(), path); + + let (binary, address) = elf_to_bin(path).unwrap(); + + // Start timer. + let instant = Instant::now(); + + // let bininfo = hf2::bin_info(&d).expect("bin_info failed"); + // log::debug!("{:?}", bininfo); + flash_bin(&binary, address, &d.device()).unwrap(); + + // Stop timer. + let elapsed = instant.elapsed(); + println!( + " {} in {}s", + "Finished".green().bold(), + elapsed.as_millis() as f32 / 1000.0 + ); +} + +#[cfg(unix)] +fn exit_with_process_status(status: std::process::ExitStatus) -> ! { + use std::os::unix::process::ExitStatusExt; + let status = status.code().or_else(|| status.signal()).unwrap_or(1); + std::process::exit(status) +} + +#[cfg(not(unix))] +fn exit_with_process_status(status: std::process::ExitStatus) -> ! { + let status = status.code().unwrap_or(1); + std::process::exit(status) +} + +fn parse_hex_16(input: &str) -> Result { + if let Some(stripped) = input.strip_prefix("0x") { + u16::from_str_radix(stripped, 16) + } else { + input.parse::() + } +} + +#[allow(unused)] +#[derive(Debug, StructOpt)] +struct Opt { + // `cargo build` arguments + #[structopt(name = "binary", long = "bin")] + bin: Option, + #[structopt(name = "example", long = "example")] + example: Option, + #[structopt(name = "package", short = "p", long = "package")] + package: Option, + #[structopt(name = "release", long = "release")] + release: bool, + #[structopt(name = "target", long = "target")] + target: Option, + #[structopt(name = "PATH", long = "manifest-path", parse(from_os_str))] + manifest_path: Option, + #[structopt(long)] + no_default_features: bool, + #[structopt(long)] + all_features: bool, + #[structopt(long)] + features: Vec, + + #[structopt(name = "pid", long = "pid", parse(try_from_str = parse_hex_16))] + pid: Option, + #[structopt(name = "vid", long = "vid", parse(try_from_str = parse_hex_16))] + vid: Option, +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..a0d4be5 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,85 @@ +use goblin::elf::program_header::PT_LOAD; +use rusb::GlobalContext; + +use std::path::PathBuf; +use std::{fs::File, io::Read}; + +#[derive(Debug)] +pub enum UtilError { + Elf(goblin::error::Error), + Dfu(dfu::error::Error), + File(std::io::Error) +} + +/// 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, u32), UtilError> { + let mut file = File::open(path).map_err(|e| UtilError::File(e))?; + let mut buffer = vec![]; + 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 mut start_address: u64 = 0; + let mut last_address: u64 = 0; + + let mut data = vec![]; + for (i, ph) in binary + .program_headers + .iter() + .filter(|ph| { + ph.p_type == PT_LOAD + && ph.p_filesz > 0 + && ph.p_offset >= binary.header.e_ehsize as u64 + && ph.is_read() + }) + .enumerate() + { + // first time through grab the starting physical address + if i == 0 { + start_address = ph.p_paddr; + } + // on subsequent passes, if there's a gap between this section and the + // previous one, fill it with zeros + else { + let difference = (ph.p_paddr - last_address) as usize; + data.resize(data.len() + difference, 0x0); + } + + data.extend_from_slice(&buffer[ph.p_offset as usize..][..ph.p_filesz as usize]); + + last_address = ph.p_paddr + ph.p_filesz; + } + + Ok((data, start_address as u32)) +} + +pub fn flash_bin( + binary: &[u8], + address: u32, + d: &rusb::Device, +) -> 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))?; + if binary.len() < 2048 { + dfu.write_flash_from_slice(address, binary).map_err(|e| UtilError::Dfu(e))?; + } else { + // hacky bug workaround + std::fs::write("target/out.bin", binary).map_err(|e| UtilError::File(e))?; + dfu.download_raw( + &mut std::fs::OpenOptions::new() + .read(true) + .open("target/out.bin") + .map_err(|e| UtilError::File(e))?, + address, + None, + ).map_err(|e| UtilError::Dfu(e))?; + std::fs::remove_file("target/out.bin").map_err(|e| UtilError::File(e))?; + } + + Ok(()) +} + +pub fn vendor_map() -> std::collections::HashMap> { + maplit::hashmap! { + 0x0483 => vec![0xdf11], + } +}