├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── Readme.md ├── src ├── main.rs └── utils.rs └── udev.rules /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "0.7.18" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "atty" 31 | version = "0.2.14" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 34 | dependencies = [ 35 | "hermit-abi", 36 | "libc", 37 | "winapi", 38 | ] 39 | 40 | [[package]] 41 | name = "autocfg" 42 | version = "1.0.1" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 45 | 46 | [[package]] 47 | name = "backtrace" 48 | version = "0.3.63" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" 51 | dependencies = [ 52 | "addr2line", 53 | "cc", 54 | "cfg-if", 55 | "libc", 56 | "miniz_oxide", 57 | "object", 58 | "rustc-demangle", 59 | ] 60 | 61 | [[package]] 62 | name = "bitflags" 63 | version = "1.2.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 66 | 67 | [[package]] 68 | name = "bytes" 69 | version = "1.1.0" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 72 | 73 | [[package]] 74 | name = "cargo-dfu" 75 | version = "0.1.2" 76 | dependencies = [ 77 | "cargo-project", 78 | "clap", 79 | "colored", 80 | "dfu-libusb", 81 | "goblin", 82 | "log", 83 | "maplit", 84 | "pretty_env_logger", 85 | "rusb", 86 | ] 87 | 88 | [[package]] 89 | name = "cargo-project" 90 | version = "0.2.7" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "04e57b974bffaf97c6a66551e4f947e34637ec25f35aaf9b45f03326a9e3874f" 93 | dependencies = [ 94 | "failure", 95 | "glob", 96 | "log", 97 | "rustc-cfg", 98 | "serde", 99 | "serde_derive", 100 | "toml", 101 | ] 102 | 103 | [[package]] 104 | name = "cc" 105 | version = "1.0.72" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 108 | 109 | [[package]] 110 | name = "cfg-if" 111 | version = "1.0.0" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 114 | 115 | [[package]] 116 | name = "chrono" 117 | version = "0.4.19" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 120 | dependencies = [ 121 | "libc", 122 | "num-integer", 123 | "num-traits", 124 | "time", 125 | "winapi", 126 | ] 127 | 128 | [[package]] 129 | name = "clap" 130 | version = "3.0.10" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375" 133 | dependencies = [ 134 | "atty", 135 | "bitflags", 136 | "clap_derive", 137 | "indexmap", 138 | "lazy_static", 139 | "os_str_bytes", 140 | "strsim", 141 | "termcolor", 142 | "textwrap", 143 | ] 144 | 145 | [[package]] 146 | name = "clap_derive" 147 | version = "3.0.6" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153" 150 | dependencies = [ 151 | "heck", 152 | "proc-macro-error", 153 | "proc-macro2", 154 | "quote", 155 | "syn", 156 | ] 157 | 158 | [[package]] 159 | name = "colored" 160 | version = "2.0.0" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 163 | dependencies = [ 164 | "atty", 165 | "lazy_static", 166 | "winapi", 167 | ] 168 | 169 | [[package]] 170 | name = "dfu-core" 171 | version = "0.4.2" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "6c3fb34e94bedc8bbd76dfc9f6774896fadbbedac6108fa8a3c46a0125bde188" 174 | dependencies = [ 175 | "bytes", 176 | "displaydoc", 177 | "log", 178 | "pretty-hex", 179 | "thiserror", 180 | ] 181 | 182 | [[package]] 183 | name = "dfu-libusb" 184 | version = "0.3.0" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "00b4d756e08681e12abb006bbcf557b45c89c189c32e08193cb773b9177f837e" 187 | dependencies = [ 188 | "dfu-core", 189 | "libusb1-sys", 190 | "rusb", 191 | "thiserror", 192 | ] 193 | 194 | [[package]] 195 | name = "displaydoc" 196 | version = "0.2.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" 199 | dependencies = [ 200 | "proc-macro2", 201 | "quote", 202 | "syn", 203 | ] 204 | 205 | [[package]] 206 | name = "env_logger" 207 | version = "0.6.2" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" 210 | dependencies = [ 211 | "atty", 212 | "humantime", 213 | "log", 214 | "regex", 215 | "termcolor", 216 | ] 217 | 218 | [[package]] 219 | name = "failure" 220 | version = "0.1.8" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 223 | dependencies = [ 224 | "backtrace", 225 | "failure_derive", 226 | ] 227 | 228 | [[package]] 229 | name = "failure_derive" 230 | version = "0.1.8" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 233 | dependencies = [ 234 | "proc-macro2", 235 | "quote", 236 | "syn", 237 | "synstructure", 238 | ] 239 | 240 | [[package]] 241 | name = "gimli" 242 | version = "0.26.1" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" 245 | 246 | [[package]] 247 | name = "glob" 248 | version = "0.3.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 251 | 252 | [[package]] 253 | name = "goblin" 254 | version = "0.2.3" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" 257 | dependencies = [ 258 | "log", 259 | "plain", 260 | "scroll", 261 | ] 262 | 263 | [[package]] 264 | name = "hashbrown" 265 | version = "0.11.2" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 268 | 269 | [[package]] 270 | name = "heck" 271 | version = "0.4.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 274 | 275 | [[package]] 276 | name = "hermit-abi" 277 | version = "0.1.19" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 280 | dependencies = [ 281 | "libc", 282 | ] 283 | 284 | [[package]] 285 | name = "humantime" 286 | version = "1.3.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 289 | dependencies = [ 290 | "quick-error", 291 | ] 292 | 293 | [[package]] 294 | name = "indexmap" 295 | version = "1.8.0" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" 298 | dependencies = [ 299 | "autocfg", 300 | "hashbrown", 301 | ] 302 | 303 | [[package]] 304 | name = "lazy_static" 305 | version = "1.4.0" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 308 | 309 | [[package]] 310 | name = "libc" 311 | version = "0.2.107" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" 314 | 315 | [[package]] 316 | name = "libusb1-sys" 317 | version = "0.6.0" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "b8772b7e8d4d988e19684aec5a3f5e470ecaf5c705cf0303da3973508e873027" 320 | dependencies = [ 321 | "cc", 322 | "libc", 323 | "pkg-config", 324 | "vcpkg", 325 | ] 326 | 327 | [[package]] 328 | name = "log" 329 | version = "0.4.14" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 332 | dependencies = [ 333 | "cfg-if", 334 | ] 335 | 336 | [[package]] 337 | name = "maplit" 338 | version = "1.0.2" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 341 | 342 | [[package]] 343 | name = "memchr" 344 | version = "2.4.1" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 347 | 348 | [[package]] 349 | name = "miniz_oxide" 350 | version = "0.4.4" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 353 | dependencies = [ 354 | "adler", 355 | "autocfg", 356 | ] 357 | 358 | [[package]] 359 | name = "num-integer" 360 | version = "0.1.44" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 363 | dependencies = [ 364 | "autocfg", 365 | "num-traits", 366 | ] 367 | 368 | [[package]] 369 | name = "num-traits" 370 | version = "0.2.14" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 373 | dependencies = [ 374 | "autocfg", 375 | ] 376 | 377 | [[package]] 378 | name = "object" 379 | version = "0.27.1" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" 382 | dependencies = [ 383 | "memchr", 384 | ] 385 | 386 | [[package]] 387 | name = "os_str_bytes" 388 | version = "6.0.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" 391 | dependencies = [ 392 | "memchr", 393 | ] 394 | 395 | [[package]] 396 | name = "pkg-config" 397 | version = "0.3.22" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" 400 | 401 | [[package]] 402 | name = "plain" 403 | version = "0.2.3" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 406 | 407 | [[package]] 408 | name = "pretty-hex" 409 | version = "0.3.0" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" 412 | 413 | [[package]] 414 | name = "pretty_env_logger" 415 | version = "0.3.1" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" 418 | dependencies = [ 419 | "chrono", 420 | "env_logger", 421 | "log", 422 | ] 423 | 424 | [[package]] 425 | name = "proc-macro-error" 426 | version = "1.0.4" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 429 | dependencies = [ 430 | "proc-macro-error-attr", 431 | "proc-macro2", 432 | "quote", 433 | "syn", 434 | "version_check", 435 | ] 436 | 437 | [[package]] 438 | name = "proc-macro-error-attr" 439 | version = "1.0.4" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 442 | dependencies = [ 443 | "proc-macro2", 444 | "quote", 445 | "version_check", 446 | ] 447 | 448 | [[package]] 449 | name = "proc-macro2" 450 | version = "1.0.32" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" 453 | dependencies = [ 454 | "unicode-xid", 455 | ] 456 | 457 | [[package]] 458 | name = "quick-error" 459 | version = "1.2.3" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 462 | 463 | [[package]] 464 | name = "quote" 465 | version = "1.0.10" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 468 | dependencies = [ 469 | "proc-macro2", 470 | ] 471 | 472 | [[package]] 473 | name = "regex" 474 | version = "1.5.4" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 477 | dependencies = [ 478 | "aho-corasick", 479 | "memchr", 480 | "regex-syntax", 481 | ] 482 | 483 | [[package]] 484 | name = "regex-syntax" 485 | version = "0.6.25" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 488 | 489 | [[package]] 490 | name = "rusb" 491 | version = "0.9.0" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "83b454219aa5007af92a042ec13b2035325318a21d3c6be18bf592f841430794" 494 | dependencies = [ 495 | "libc", 496 | "libusb1-sys", 497 | ] 498 | 499 | [[package]] 500 | name = "rustc-cfg" 501 | version = "0.4.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "8ad221fe7cd09334f8735dcc157b1178e343f43dfaefcd1b09d7fd4fc0921b6f" 504 | dependencies = [ 505 | "failure", 506 | ] 507 | 508 | [[package]] 509 | name = "rustc-demangle" 510 | version = "0.1.21" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 513 | 514 | [[package]] 515 | name = "scroll" 516 | version = "0.10.2" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" 519 | dependencies = [ 520 | "scroll_derive", 521 | ] 522 | 523 | [[package]] 524 | name = "scroll_derive" 525 | version = "0.10.5" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" 528 | dependencies = [ 529 | "proc-macro2", 530 | "quote", 531 | "syn", 532 | ] 533 | 534 | [[package]] 535 | name = "serde" 536 | version = "1.0.130" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 539 | 540 | [[package]] 541 | name = "serde_derive" 542 | version = "1.0.130" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 545 | dependencies = [ 546 | "proc-macro2", 547 | "quote", 548 | "syn", 549 | ] 550 | 551 | [[package]] 552 | name = "strsim" 553 | version = "0.10.0" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 556 | 557 | [[package]] 558 | name = "syn" 559 | version = "1.0.81" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" 562 | dependencies = [ 563 | "proc-macro2", 564 | "quote", 565 | "unicode-xid", 566 | ] 567 | 568 | [[package]] 569 | name = "synstructure" 570 | version = "0.12.6" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 573 | dependencies = [ 574 | "proc-macro2", 575 | "quote", 576 | "syn", 577 | "unicode-xid", 578 | ] 579 | 580 | [[package]] 581 | name = "termcolor" 582 | version = "1.1.2" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 585 | dependencies = [ 586 | "winapi-util", 587 | ] 588 | 589 | [[package]] 590 | name = "textwrap" 591 | version = "0.14.2" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 594 | 595 | [[package]] 596 | name = "thiserror" 597 | version = "1.0.30" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 600 | dependencies = [ 601 | "thiserror-impl", 602 | ] 603 | 604 | [[package]] 605 | name = "thiserror-impl" 606 | version = "1.0.30" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 609 | dependencies = [ 610 | "proc-macro2", 611 | "quote", 612 | "syn", 613 | ] 614 | 615 | [[package]] 616 | name = "time" 617 | version = "0.1.44" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 620 | dependencies = [ 621 | "libc", 622 | "wasi", 623 | "winapi", 624 | ] 625 | 626 | [[package]] 627 | name = "toml" 628 | version = "0.4.10" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" 631 | dependencies = [ 632 | "serde", 633 | ] 634 | 635 | [[package]] 636 | name = "unicode-xid" 637 | version = "0.2.2" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 640 | 641 | [[package]] 642 | name = "vcpkg" 643 | version = "0.2.15" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 646 | 647 | [[package]] 648 | name = "version_check" 649 | version = "0.9.3" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 652 | 653 | [[package]] 654 | name = "wasi" 655 | version = "0.10.0+wasi-snapshot-preview1" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 658 | 659 | [[package]] 660 | name = "winapi" 661 | version = "0.3.9" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 664 | dependencies = [ 665 | "winapi-i686-pc-windows-gnu", 666 | "winapi-x86_64-pc-windows-gnu", 667 | ] 668 | 669 | [[package]] 670 | name = "winapi-i686-pc-windows-gnu" 671 | version = "0.4.0" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 674 | 675 | [[package]] 676 | name = "winapi-util" 677 | version = "0.1.5" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 680 | dependencies = [ 681 | "winapi", 682 | ] 683 | 684 | [[package]] 685 | name = "winapi-x86_64-pc-windows-gnu" 686 | version = "0.4.0" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 689 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-dfu" 3 | authors = ["Roman Kretschmer "] 4 | version = "0.1.2" 5 | edition = "2021" 6 | description = "cargo extension for flashing embedded rust programs via dfu" 7 | license = "MIT" 8 | homepage = "https://github.com/dfu-rs/cargo-dfu" 9 | repository = "https://github.com/dfu-rs/cargo-dfu.git" 10 | categories = ["embedded", "hardware-support"] 11 | keywords = ["dfu", "flashing", "embedded"] 12 | readme = "Readme.md" 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies] 17 | goblin = "0.2.3" 18 | colored = "2.0.0" 19 | rusb = "0.9.0" 20 | pretty_env_logger = "0.3.0" 21 | cargo-project = "0.2.7" 22 | clap = {version = "3.0.10", features=["derive"]} 23 | maplit = "1.0.2" 24 | log = "0.4.6" 25 | dfu-libusb = "0.3.0" 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2021 Roman Kretschmer and contributors 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | 11 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # cargo-dfu 2 | 3 | This crate provides a cargo subcommand to flash ELF binaries via dfu 4 | Most STM chips will probably work with this, although you might need to add the vid and pid to the vendor map 5 | 6 | ## Installation 7 | 8 | You can install this utility with cargo: 9 | 10 | ```bash 11 | cargo install cargo-dfu 12 | ``` 13 | 14 | ## Usage 15 | 16 | You can use it like cargo build or cargo-flash with the option of giving the vid and pid: 17 | 18 | ```bash 19 | cargo dfu --vid --pid 20 | ``` 21 | 22 | ### Examples 23 | 24 | #### flash the debug version of the current crate 25 | 26 | ```bash 27 | cargo dfu 28 | ``` 29 | 30 | #### specifying the chip 31 | 32 | ```bash 33 | cargo dfu --chip stm32 34 | ``` 35 | 36 | #### specifying the vid and pid 37 | 38 | ```bash 39 | cargo dfu --vid 0x483 --pid 0xdf11 40 | ``` 41 | 42 | ## Add chip definitions 43 | feel free to open a PR to add chips to this 44 | 45 | ## Notes 46 | 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/ 47 | ```lang=bash 48 | sudo cp udev.rules /etc/udev/rules.d/cargo-dfu.rules 49 | ``` 50 | 51 | ## Roadmap 52 | - [ ] check if multiple chips are connected 53 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod utils; 2 | 3 | use crate::utils::{elf_to_bin, flash_bin, vendor_map}; 4 | use colored::Colorize; 5 | use rusb::{open_device_with_vid_pid, GlobalContext}; 6 | 7 | use clap::Parser; 8 | use std::path::PathBuf; 9 | use std::process::{Command, Stdio}; 10 | use std::time::Instant; 11 | // use structopt::StructOpt; 12 | 13 | fn main() { 14 | // Initialize the logging backend. 15 | pretty_env_logger::init(); 16 | 17 | // Get commandline options. 18 | // Skip the first arg which is the calling application name. 19 | let opt = Opt::parse_from(std::env::args().skip(1)); 20 | 21 | if opt.list_chips { 22 | for vendor in vendor_map() { 23 | println!("{}", vendor.0); 24 | } 25 | return; 26 | } 27 | 28 | // Try and get the cargo project information. 29 | let project = cargo_project::Project::query(".").expect("Couldn't parse the Cargo.toml"); 30 | 31 | // Decide what artifact to use. 32 | let artifact = if let Some(bin) = &opt.bin { 33 | cargo_project::Artifact::Bin(bin) 34 | } else if let Some(example) = &opt.example { 35 | cargo_project::Artifact::Example(example) 36 | } else { 37 | cargo_project::Artifact::Bin(project.name()) 38 | }; 39 | 40 | // Decide what profile to use. 41 | let profile = if opt.release { 42 | cargo_project::Profile::Release 43 | } else { 44 | cargo_project::Profile::Dev 45 | }; 46 | 47 | // Try and get the artifact path. 48 | let path = project 49 | .path( 50 | artifact, 51 | profile, 52 | opt.target 53 | .as_deref() 54 | .map(|target| target.trim_end_matches(".json")), 55 | "x86_64-unknown-linux-gnu", 56 | ) 57 | .expect("Couldn't find the build result"); 58 | 59 | // Remove first two args which is the calling application name and the `dfu` command from cargo. 60 | let mut args: Vec<_> = std::env::args().skip(2).collect(); 61 | 62 | // todo, keep as iter. difficult because we want to filter map remove two items at once. 63 | // Remove our args as cargo build does not understand them. 64 | let flags = ["--pid", "--vid", "--chip"].iter(); 65 | for flag in flags { 66 | if let Some(index) = args.iter().position(|x| x == flag) { 67 | args.remove(index); 68 | args.remove(index); 69 | } 70 | } 71 | 72 | let status = Command::new("cargo") 73 | .arg("build") 74 | .args(args) 75 | .stdout(Stdio::inherit()) 76 | .stderr(Stdio::inherit()) 77 | .spawn() 78 | .unwrap() 79 | .wait() 80 | .unwrap(); 81 | 82 | if !status.success() { 83 | exit_with_process_status(status) 84 | } 85 | 86 | let Some(d) = (if let (Some(v), Some(p)) = (opt.vid, opt.pid) { 87 | open_device_with_vid_pid(v, p) 88 | } else if let Some(c) = opt.chip { 89 | println!(" {} for a connected {}.", "Searching".green().bold(), c); 90 | 91 | let mut device: Option> = None; 92 | 93 | let vendor = vendor_map(); 94 | 95 | if let Some(products) = vendor.get(&c) { 96 | for (v, p) in products { 97 | if let Some(d) = open_device_with_vid_pid(*v, *p) { 98 | device = Some(d); 99 | break; 100 | } 101 | } 102 | } 103 | 104 | device 105 | } else { 106 | println!( 107 | " {} for a connected device with known vid/pid pair.", 108 | "Searching".green().bold(), 109 | ); 110 | 111 | let devices: Vec<_> = rusb::devices() 112 | .expect("Error with Libusb") 113 | .iter() 114 | .map(|d| d.device_descriptor().unwrap()) 115 | .collect(); 116 | 117 | let mut device: Option> = None; 118 | 119 | for d in devices { 120 | for vendor in vendor_map() { 121 | if vendor.1.contains(&(d.vendor_id(), d.product_id())) { 122 | if let Some(d) = open_device_with_vid_pid(d.vendor_id(), d.product_id()) { 123 | device = Some(d); 124 | break; 125 | } 126 | } 127 | } 128 | } 129 | 130 | device 131 | }) else { 132 | println!( 133 | " {} finding connected devices, have you placed it into bootloader mode?", 134 | "Error".red().bold() 135 | ); 136 | std::process::exit(101); 137 | }; 138 | 139 | println!( 140 | " {} {} {}", 141 | "Found ".green().bold(), 142 | d.read_manufacturer_string_ascii(&d.device().device_descriptor().unwrap()) 143 | .unwrap(), 144 | d.read_product_string_ascii(&d.device().device_descriptor().unwrap()) 145 | .unwrap() 146 | ); 147 | 148 | println!(" {} {:?}", "Flashing".green().bold(), path); 149 | 150 | let (binary, _) = elf_to_bin(path).unwrap(); 151 | 152 | // Start timer. 153 | let instant = Instant::now(); 154 | 155 | // if let Err(e) = flash_bin(&binary, &d.device()) { 156 | // println!(" {} flashing binary: {:?}", "Error".red().bold(), e); 157 | // } 158 | 159 | match flash_bin(&binary, &d.device()) { 160 | Err(utils::UtilError::Dfu(dfu_libusb::Error::LibUsb(rusb::Error::NoDevice))) => { 161 | // works for me? 162 | } 163 | Err(e) => println!(" {} flashing binary: {:?}", "Error".red().bold(), e), 164 | _ => (), 165 | } 166 | 167 | // Stop timer. 168 | let elapsed = instant.elapsed(); 169 | println!( 170 | " {} in {}s", 171 | "Finished".green().bold(), 172 | elapsed.as_millis() as f32 / 1000.0 173 | ); 174 | } 175 | 176 | #[cfg(unix)] 177 | fn exit_with_process_status(status: std::process::ExitStatus) -> ! { 178 | use std::os::unix::process::ExitStatusExt; 179 | let status = status.code().or_else(|| status.signal()).unwrap_or(1); 180 | std::process::exit(status) 181 | } 182 | 183 | #[cfg(not(unix))] 184 | fn exit_with_process_status(status: std::process::ExitStatus) -> ! { 185 | let status = status.code().unwrap_or(1); 186 | std::process::exit(status) 187 | } 188 | 189 | fn parse_hex_16(input: &str) -> Result { 190 | input.strip_prefix("0x").map_or_else( 191 | || input.parse(), 192 | |stripped| u16::from_str_radix(stripped, 16), 193 | ) 194 | } 195 | 196 | #[derive(Debug, Parser)] 197 | #[clap(author, version, about, long_about = None)] 198 | struct Opt { 199 | // `cargo build` arguments 200 | #[clap(name = "binary", long = "bin")] 201 | bin: Option, 202 | #[clap(name = "example", long = "example")] 203 | example: Option, 204 | #[clap(name = "package", short = 'p', long = "package")] 205 | package: Option, 206 | #[clap(name = "release", long = "release")] 207 | release: bool, 208 | #[clap(name = "target", long = "target")] 209 | target: Option, 210 | #[clap(name = "PATH", long = "manifest-path", parse(from_os_str))] 211 | manifest_path: Option, 212 | #[clap(long)] 213 | no_default_features: bool, 214 | #[clap(long)] 215 | all_features: bool, 216 | #[clap(long)] 217 | features: Vec, 218 | 219 | #[clap(name = "pid", long = "pid", parse(try_from_str = parse_hex_16))] 220 | pid: Option, 221 | #[clap(name = "vid", long = "vid", parse(try_from_str = parse_hex_16))] 222 | vid: Option, 223 | 224 | #[clap(name = "chip", long = "chip")] 225 | chip: Option, 226 | #[clap(name = "list-chips", long = "list-chips")] 227 | list_chips: bool, 228 | } 229 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use goblin::elf::program_header::PT_LOAD; 2 | use rusb::GlobalContext; 3 | 4 | use std::path::PathBuf; 5 | use std::{fs::File, io::Read}; 6 | 7 | #[derive(Debug)] 8 | pub enum UtilError { 9 | Elf(goblin::error::Error), 10 | Dfu(dfu_libusb::Error), 11 | File(std::io::Error), 12 | } 13 | 14 | /// Returns a contiguous bin with 0s between non-contiguous sections and starting address from an elf. 15 | pub fn elf_to_bin(path: PathBuf) -> Result<(Vec, u32), UtilError> { 16 | let mut file = File::open(path).map_err(UtilError::File)?; 17 | let mut buffer = vec![]; 18 | file.read_to_end(&mut buffer).map_err(UtilError::File)?; 19 | 20 | let binary = goblin::elf::Elf::parse(buffer.as_slice()).map_err(UtilError::Elf)?; 21 | 22 | let mut start_address: u64 = 0; 23 | let mut last_address: u64 = 0; 24 | 25 | let mut data = vec![]; 26 | for (i, ph) in binary 27 | .program_headers 28 | .iter() 29 | .filter(|ph| { 30 | ph.p_type == PT_LOAD 31 | && ph.p_filesz > 0 32 | && ph.p_offset >= u64::from(binary.header.e_ehsize) 33 | && ph.is_read() 34 | }) 35 | .enumerate() 36 | { 37 | // first time through grab the starting physical address 38 | if i == 0 { 39 | start_address = ph.p_paddr; 40 | } 41 | // on subsequent passes, if there's a gap between this section and the 42 | // previous one, fill it with zeros 43 | else { 44 | let difference = (ph.p_paddr - last_address) as usize; 45 | data.resize(data.len() + difference, 0x0); 46 | } 47 | 48 | data.extend_from_slice(&buffer[ph.p_offset as usize..][..ph.p_filesz as usize]); 49 | 50 | last_address = ph.p_paddr + ph.p_filesz; 51 | } 52 | 53 | Ok(( 54 | data, 55 | u32::try_from(start_address) 56 | .map_err(|e| UtilError::Elf(goblin::error::Error::Malformed(e.to_string())))?, 57 | )) 58 | } 59 | 60 | pub fn flash_bin(binary: &[u8], d: &rusb::Device) -> Result<(), UtilError> { 61 | let mut dfu = dfu_libusb::DfuLibusb::open( 62 | &rusb::Context::new().unwrap(), 63 | d.device_descriptor().unwrap().vendor_id(), 64 | d.device_descriptor().unwrap().product_id(), 65 | 0, 66 | 0, 67 | ) 68 | .map_err(UtilError::Dfu)?; 69 | 70 | dfu.download_from_slice(binary).map_err(UtilError::Dfu)?; 71 | Ok(()) 72 | } 73 | 74 | pub fn vendor_map() -> std::collections::HashMap> { 75 | maplit::hashmap! { 76 | "stm32".to_string() => vec![(0x0483, 0xdf11)], 77 | "gd32vf103".to_string() => vec![(0x28e9, 0x0189)], 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /udev.rules: -------------------------------------------------------------------------------- 1 | # gd32vf103 2 | SUBSYSTEMS=="usb" ATTRS{idVendor}=="28e9" ATTRS{idProduct}=="0189" MODE:="0666" 3 | --------------------------------------------------------------------------------