From 346c65fc9c943592844727d7d216084a879eeff0 Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Thu, 27 Jun 2024 21:03:02 +0200 Subject: [PATCH] libftdi support --- sw/deployer/Cargo.lock | 790 +++++++++++++++++++++++++++------ sw/deployer/Cargo.toml | 19 +- sw/deployer/src/main.rs | 8 +- sw/deployer/src/sc64/error.rs | 7 + sw/deployer/src/sc64/ftdi.rs | 227 ++++++++++ sw/deployer/src/sc64/link.rs | 430 ++++++++++-------- sw/deployer/src/sc64/mod.rs | 1 + sw/deployer/src/sc64/server.rs | 366 ++++++++------- 8 files changed, 1339 insertions(+), 509 deletions(-) create mode 100644 sw/deployer/src/sc64/ftdi.rs diff --git a/sw/deployer/Cargo.lock b/sw/deployer/Cargo.lock index 29aa09d..8c81fd2 100644 --- a/sw/deployer/Cargo.lock +++ b/sw/deployer/Cargo.lock @@ -27,13 +27,19 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -51,57 +57,110 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "anyhow" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] [[package]] name = "bit_field" @@ -117,21 +176,33 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitstream-io" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "415f8399438eb5e4b2f73ed3152a3448b98149dda642a957ee704e1daa5cf1d8" + +[[package]] +name = "built" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17" [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" [[package]] name = "byteorder" @@ -140,10 +211,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "cc" -version = "1.0.90" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] [[package]] name = "cfg-if" @@ -159,23 +251,23 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] name = "clap" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -192,9 +284,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -204,21 +296,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.68", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "color_quant" @@ -228,9 +320,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "colored" @@ -250,9 +342,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -278,9 +370,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -306,19 +398,25 @@ checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "exr" version = "1.72.0" @@ -346,9 +444,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -365,9 +463,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -386,9 +484,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -404,10 +502,16 @@ dependencies = [ ] [[package]] -name = "heck" -version = "0.4.1" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex" @@ -440,22 +544,43 @@ dependencies = [ [[package]] name = "image" -version = "0.24.9" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" dependencies = [ "bytemuck", "byteorder", "color_quant", "exr", "gif", - "jpeg-decoder", + "image-webp", "num-traits", "png", "qoi", + "ravif", + "rayon", + "rgb", "tiff", + "zune-core", + "zune-jpeg", ] +[[package]] +name = "image-webp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d" +dependencies = [ + "byteorder-lite", + "thiserror", +] + +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + [[package]] name = "include-flate" version = "0.2.0" @@ -491,23 +616,65 @@ dependencies = [ ] [[package]] -name = "io-kit-sys" -version = "0.4.0" +name = "indexmap" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4769cb30e5dcf1710fc6730d3e94f78c47723a014a567de385e113c737394640" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "io-kit-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" dependencies = [ "core-foundation-sys", "mach2", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + [[package]] name = "jpeg-decoder" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" -dependencies = [ - "rayon", -] [[package]] name = "js-sys" @@ -520,9 +687,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lebe" @@ -532,9 +699,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libflate" @@ -556,6 +723,29 @@ dependencies = [ "rle-decode-fast", ] +[[package]] +name = "libftdi1-sys" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575286f9af093f56c7805f4f94874871b84216d1545f499d2cbad9e370000fe7" +dependencies = [ + "cfg-if", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + [[package]] name = "libudev" version = "0.3.0" @@ -578,9 +768,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -592,6 +782,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "mach2" version = "0.4.2" @@ -601,6 +800,16 @@ dependencies = [ "libc", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "md5" version = "0.7.0" @@ -609,20 +818,32 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "simd-adler32", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.26.4" @@ -640,17 +861,74 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", ] [[package]] -name = "num-traits" -version = "0.2.18" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -668,7 +946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -677,6 +955,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384e52fd8fbd4cbe3c317e8216260c21a0f9134de108cea8a4dd4e7e152c472d" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pkg-config" version = "0.3.30" @@ -710,13 +994,32 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn 2.0.68", +] + [[package]] name = "qoi" version = "0.4.1" @@ -727,10 +1030,16 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.35" +name = "quick-error" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -766,10 +1075,60 @@ dependencies = [ ] [[package]] -name = "rayon" -version = "1.9.0" +name = "rav1e" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67376f469e7e7840d0040bbf4b9b3334005bb167f814621326e4c7ab8cd6e944" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -787,9 +1146,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -799,9 +1158,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -810,9 +1169,18 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] [[package]] name = "rle-decode-fast" @@ -844,6 +1212,7 @@ dependencies = [ "hex", "image", "include-flate", + "libftdi1-sys", "md5", "panic-message", "rand", @@ -859,10 +1228,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "serial2" -version = "0.2.20" +name = "serde" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532d7a51dc8416e952987dbd39dd5e24fb9d1cbe86f1263521ec5032cb7ff0fb" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "serial2" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f39915da34f43a64c66d53c228b8ba9a4e21fed4894af24304e47f96996acafd" dependencies = [ "cfg-if", "libc", @@ -875,7 +1273,7 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5a15d0be940df84846264b09b51b10b931fb2f275becb80934e3568a016828" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "cfg-if", "core-foundation-sys", "io-kit-sys", @@ -895,10 +1293,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] -name = "smallvec" -version = "1.13.1" +name = "simd_helpers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "spin" @@ -911,9 +1318,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" @@ -928,9 +1335,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -938,23 +1345,42 @@ dependencies = [ ] [[package]] -name = "thiserror" -version = "1.0.58" +name = "system-deps" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.68", ] [[package]] @@ -968,6 +1394,40 @@ dependencies = [ "weezl", ] +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unescaper" version = "0.1.4" @@ -985,9 +1445,32 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "version_check" @@ -1022,7 +1505,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -1044,7 +1527,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1089,7 +1572,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1107,7 +1590,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1127,17 +1610,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -1148,9 +1632,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1160,9 +1644,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1172,9 +1656,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1184,9 +1674,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1196,9 +1686,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -1208,9 +1698,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1220,9 +1710,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" [[package]] name = "zune-inflate" @@ -1232,3 +1737,12 @@ checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", ] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", +] diff --git a/sw/deployer/Cargo.toml b/sw/deployer/Cargo.toml index 7eac40d..cf6b54d 100644 --- a/sw/deployer/Cargo.toml +++ b/sw/deployer/Cargo.toml @@ -7,21 +7,22 @@ description = "SummerCart64 loader and control software" documentation = "https://github.com/Polprzewodnikowy/SummerCart64" [dependencies] -chrono = "0.4.23" -clap = { version = "4.1.6", features = ["derive"] } -clap-num = "1.0.2" -colored = "2.0.0" -crc32fast = "1.3.2" -ctrlc = "3.2.5" -encoding_rs = "0.8.32" +chrono = "0.4.38" +clap = { version = "4.5.7", features = ["derive"] } +clap-num = "1.1.1" +colored = "2.1.0" +crc32fast = "1.4.2" +ctrlc = "3.4.4" +encoding_rs = "0.8.34" hex = "0.4.3" -image = "0.24.5" +image = "0.25.1" include-flate = { version = "0.2.0", features = ["stable"] } +libftdi1-sys = "1.1.3" md5 = "0.7.0" panic-message = "0.3.0" rand = "0.8.5" rust-ini = "0.18.0" -serial2 = "0.2.20" +serial2 = "0.2.26" serialport = "4.3.0" [profile.release] diff --git a/sw/deployer/src/main.rs b/sw/deployer/src/main.rs index a346caa..06ae718 100644 --- a/sw/deployer/src/main.rs +++ b/sw/deployer/src/main.rs @@ -350,7 +350,13 @@ fn handle_list_command() -> Result<(), sc64::Error> { println!("{}", "Found devices:".bold()); for (i, d) in devices.iter().enumerate() { - println!(" {i}: [{}] at port [{}]", d.serial_number, d.port); + let index = i + 1; + println!( + " {index}: [{}] at port [{}] (using \"{}\" backend)", + d.serial.bold(), + d.port.bold(), + d.backend.to_string().bold() + ); } Ok(()) diff --git a/sw/deployer/src/sc64/error.rs b/sw/deployer/src/sc64/error.rs index 416bebb..a554267 100644 --- a/sw/deployer/src/sc64/error.rs +++ b/sw/deployer/src/sc64/error.rs @@ -1,3 +1,4 @@ +use super::ftdi::FtdiError; use std::fmt::{Display, Formatter, Result}; #[derive(Debug, Clone)] @@ -32,3 +33,9 @@ impl From for Error { Error::new(format!("SerialPort error: {}", value.description).as_str()) } } + +impl From for Error { + fn from(value: FtdiError) -> Self { + Error::new(format!("libftdi error: {}", value.description).as_str()) + } +} diff --git a/sw/deployer/src/sc64/ftdi.rs b/sw/deployer/src/sc64/ftdi.rs new file mode 100644 index 0000000..fa99f46 --- /dev/null +++ b/sw/deployer/src/sc64/ftdi.rs @@ -0,0 +1,227 @@ +pub struct FtdiError { + pub description: String, +} + +impl FtdiError { + fn malloc() -> FtdiError { + FtdiError { + description: format!("Couldn't allocate memory for the context"), + } + } + + fn libftdi(context: *mut libftdi1_sys::ftdi_context) -> FtdiError { + let raw = unsafe { std::ffi::CStr::from_ptr(libftdi1_sys::ftdi_get_error_string(context)) }; + FtdiError { + description: format!("{}", raw.to_str().unwrap_or("Unknown error")), + } + } +} + +impl From for std::io::Error { + fn from(value: FtdiError) -> Self { + return Self::new(std::io::ErrorKind::Other, value.description); + } +} + +struct Context { + context: *mut libftdi1_sys::ftdi_context, +} + +impl Context { + fn new() -> Result { + let ctx = unsafe { libftdi1_sys::ftdi_new() }; + if ctx.is_null() { + return Err(FtdiError::malloc()); + } + let context = Context { context: ctx }; + let result = unsafe { + libftdi1_sys::ftdi_set_interface( + context.get(), + libftdi1_sys::ftdi_interface::INTERFACE_A, + ) + }; + context.check_result(result)?; + Ok(context) + } + + fn get(&self) -> *mut libftdi1_sys::ftdi_context { + return self.context; + } + + fn check_result(&self, result: i32) -> Result<(), FtdiError> { + if result < 0 { + return Err(FtdiError::libftdi(self.get())); + } + Ok(()) + } +} + +impl Drop for Context { + fn drop(&mut self) { + unsafe { libftdi1_sys::ftdi_free(self.get()) } + } +} + +pub struct FtdiDevice { + context: Context, + read_timeout: std::time::Duration, + write_timeout: std::time::Duration, +} + +impl FtdiDevice { + pub fn open( + port: &str, + read_timeout: std::time::Duration, + write_timeout: std::time::Duration, + ) -> Result { + let context = Context::new()?; + unsafe { + let mode = libftdi1_sys::ftdi_module_detach_mode::AUTO_DETACH_REATACH_SIO_MODULE; + (*context.get()).module_detach_mode = mode; + } + let description = std::ffi::CString::new(port).unwrap_or_default().into_raw(); + let result = unsafe { libftdi1_sys::ftdi_usb_open_string(context.get(), description) }; + context.check_result(result)?; + let result = unsafe { libftdi1_sys::ftdi_set_latency_timer(context.get(), 1) }; + context.check_result(result)?; + Ok(FtdiDevice { + context, + read_timeout, + write_timeout, + }) + } + + pub fn set_dtr(&self, value: bool) -> Result<(), FtdiError> { + let state = if value { 1 } else { 0 }; + let result = unsafe { libftdi1_sys::ftdi_setdtr(self.context.get(), state) }; + self.context.check_result(result)?; + Ok(()) + } + + pub fn read_dsr(&self) -> Result { + const DSR_BIT: u16 = 1 << 5; + let mut status: u16 = 0; + let result = unsafe { + libftdi1_sys::ftdi_poll_modem_status( + self.context.get(), + std::slice::from_mut(&mut status).as_mut_ptr(), + ) + }; + self.context.check_result(result)?; + Ok((status & DSR_BIT) != 0) + } + + pub fn read(&self, data: &mut [u8]) -> std::io::Result { + let timeout = std::time::Instant::now(); + loop { + let result = unsafe { + libftdi1_sys::ftdi_read_data( + self.context.get(), + data.as_mut_ptr(), + data.len() as i32, + ) + }; + self.context.check_result(result)?; + if result > 0 { + return Ok(result as usize); + } + if timeout.elapsed() > self.read_timeout { + return Err(std::io::ErrorKind::TimedOut.into()); + } + } + } + + pub fn write(&self, data: &[u8]) -> std::io::Result { + let timeout = std::time::Instant::now(); + loop { + let result = unsafe { + libftdi1_sys::ftdi_write_data(self.context.get(), data.as_ptr(), data.len() as i32) + }; + self.context.check_result(result)?; + if result > 0 { + return Ok(result as usize); + } + if timeout.elapsed() > self.write_timeout { + return Err(std::io::ErrorKind::TimedOut.into()); + } + } + } + + pub fn write_all(&self, data: &[u8]) -> std::io::Result<()> { + let mut data = data; + while !data.is_empty() { + let written = self.write(data)?; + data = &data[written..]; + } + Ok(()) + } + + pub fn discard_buffers(&self) -> std::io::Result<()> { + let result = unsafe { libftdi1_sys::ftdi_tcioflush(self.context.get()) }; + self.context.check_result(result)?; + Ok(()) + } +} + +impl Drop for FtdiDevice { + fn drop(&mut self) { + unsafe { libftdi1_sys::ftdi_usb_close(self.context.get()) }; + } +} + +pub struct FtdiDeviceInfo { + pub port: String, + pub serial: String, +} + +pub fn list_ftdi_devices(vendor: u16, product: u16) -> Result, FtdiError> { + let context = Context::new()?; + + let mut device_list: *mut libftdi1_sys::ftdi_device_list = std::ptr::null_mut(); + let result = unsafe { + libftdi1_sys::ftdi_usb_find_all( + context.get(), + &mut device_list, + vendor as i32, + product as i32, + ) + }; + context.check_result(result)?; + + let mut list: Vec = vec![]; + + let mut serial = [0i8; 128]; + + let mut device = device_list; + let mut index = 0; + while !device.is_null() { + let result = unsafe { + libftdi1_sys::ftdi_usb_get_strings( + context.get(), + (*device).dev, + std::ptr::null_mut(), + 0, + std::ptr::null_mut(), + 0, + serial.as_mut_ptr(), + serial.len() as i32, + ) + }; + + if let Ok(()) = context.check_result(result) { + list.push(FtdiDeviceInfo { + port: format!("i:0x{vendor:04X}:0x{product:04X}:{index}"), + serial: unsafe { std::ffi::CStr::from_ptr(serial.as_ptr()) } + .to_string_lossy() + .into_owned(), + }); + } + + device = unsafe { (*device).next }; + index += 1; + } + + unsafe { libftdi1_sys::ftdi_list_free(&mut device_list) } + + Ok(list) +} diff --git a/sw/deployer/src/sc64/link.rs b/sw/deployer/src/sc64/link.rs index 88fe748..245d587 100644 --- a/sw/deployer/src/sc64/link.rs +++ b/sw/deployer/src/sc64/link.rs @@ -1,10 +1,13 @@ -use super::error::Error; +use super::{ + error::Error, + ftdi::{list_ftdi_devices, FtdiDevice, FtdiError}, +}; use serial2::SerialPort; use std::{ collections::VecDeque, + fmt::Display, io::{BufReader, BufWriter, ErrorKind, Read, Write}, net::TcpStream, - thread, time::{Duration, Instant}, }; @@ -56,74 +59,54 @@ pub struct Packet { pub data: Vec, } -pub struct Serial { - serial: SerialPort, -} +const SERIAL_PREFIX: &str = "serial://"; +const FTDI_PREFIX: &str = "ftdi://"; -impl Serial { - fn reset(&self) -> Result<(), Error> { - const RESET_WAIT_DURATION: Duration = Duration::from_millis(10); - const RESET_RETRY_COUNT: i32 = 100; - const FLUSH_TIMEOUT: Duration = Duration::from_secs(1); +const RESET_TIMEOUT: Duration = Duration::from_secs(1); +const POLL_TIMEOUT: Duration = Duration::from_millis(1); +const READ_TIMEOUT: Duration = Duration::from_secs(5); +const WRITE_TIMEOUT: Duration = Duration::from_secs(5); - self.serial.set_dtr(true)?; - for n in 0..=RESET_RETRY_COUNT { - self.serial.discard_buffers()?; - thread::sleep(RESET_WAIT_DURATION); - if self.serial.read_dsr()? { - break; - } - if n == RESET_RETRY_COUNT { - return Err(Error::new("Couldn't reset SC64 device (on)")); - } - } +pub trait Backend { + fn reset(&mut self) -> Result<(), Error>; - let flush_timeout = Instant::now(); + fn close(&self); + fn read(&mut self, buffer: &mut [u8]) -> std::io::Result; + + fn write(&mut self, buffer: &[u8]) -> std::io::Result<()>; + + fn flush(&mut self) -> std::io::Result<()>; + + fn purge_incoming_data(&mut self) -> std::io::Result<()> { + let timeout = Instant::now(); loop { - match self.serial.read(&mut vec![0; 1]) { + match self.read(&mut vec![0; 1]) { Ok(length) => match length { - 0 => break, + 0 => return Ok(()), _ => {} }, Err(error) => match error.kind() { - ErrorKind::TimedOut => break, - _ => { - return Err(Error::new( - format!("Couldn't flush SC64 serial buffer: {error}").as_str(), - )) - } + ErrorKind::TimedOut => return Ok(()), + _ => return Err(error), }, } - if flush_timeout.elapsed() >= FLUSH_TIMEOUT { - return Err(Error::new("SC64 serial buffer flush took too long")); + if timeout.elapsed() >= RESET_TIMEOUT { + return Err(std::io::Error::new( + ErrorKind::TimedOut, + "SC64 read buffer flush took too long", + )); } } - - self.serial.set_dtr(false)?; - for n in 0..=RESET_RETRY_COUNT { - thread::sleep(RESET_WAIT_DURATION); - if !self.serial.read_dsr()? { - break; - } - if n == RESET_RETRY_COUNT { - return Err(Error::new("Couldn't reset SC64 device (off)")); - } - } - - Ok(()) } - fn read_data(&self, buffer: &mut [u8], block: bool) -> Result, Error> { - let timeout = Instant::now(); + fn try_read(&mut self, buffer: &mut [u8], block: bool) -> Result, Error> { let mut position = 0; let length = buffer.len(); + let timeout = Instant::now(); while position < length { - if timeout.elapsed() > Duration::from_secs(10) { - return Err(Error::new("Serial read timeout")); - } - match self.serial.read(&mut buffer[position..length]) { - Ok(0) => return Err(Error::new("Unexpected end of serial data")), + match self.read(&mut buffer[position..length]) { + Ok(0) => return Err(Error::new("Unexpected end of stream data")), Ok(bytes) => position += bytes, Err(error) => match error.kind() { ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => { @@ -134,42 +117,47 @@ impl Serial { _ => return Err(error.into()), }, } + if timeout.elapsed() > READ_TIMEOUT { + return Err(Error::new("Read timeout")); + } } Ok(Some(())) } - fn read_exact(&self, buffer: &mut [u8]) -> Result<(), Error> { - match self.read_data(buffer, true)? { + fn try_read_header(&mut self, block: bool) -> Result, Error> { + let mut header = [0u8; 4]; + Ok(self.try_read(&mut header, block)?.map(|_| header)) + } + + fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + match self.try_read(buffer, true)? { Some(()) => Ok(()), - None => Err(Error::new("Unexpected end of serial data")), + None => Err(Error::new("Unexpected end of data")), } } - fn read_header(&self, block: bool) -> Result, Error> { - let mut header = [0u8; 4]; - Ok(self.read_data(&mut header, block)?.map(|_| header)) - } + fn send_command(&mut self, command: &Command) -> Result<(), Error> { + self.write(b"CMD")?; + self.write(&command.id.to_be_bytes())?; - pub fn send_command(&self, command: &Command) -> Result<(), Error> { - self.serial.write_all(b"CMD")?; - self.serial.write_all(&command.id.to_be_bytes())?; - self.serial.write_all(&command.args[0].to_be_bytes())?; - self.serial.write_all(&command.args[1].to_be_bytes())?; + self.write(&command.args[0].to_be_bytes())?; + self.write(&command.args[1].to_be_bytes())?; - self.serial.write_all(&command.data)?; + self.write(&command.data)?; - self.serial.flush()?; + self.flush()?; Ok(()) } - pub fn process_incoming_data( - &self, + fn process_incoming_data( + &mut self, data_type: DataType, packets: &mut VecDeque, ) -> Result, Error> { let block = matches!(data_type, DataType::Response); - while let Some(header) = self.read_header(block)? { + + while let Some(header) = self.try_read_header(block)? { let (packet_token, error) = (match &header[0..3] { b"CMP" => Ok((false, false)), b"PKT" => Ok((true, false)), @@ -200,48 +188,115 @@ impl Serial { } } -pub fn new_serial(port: &str) -> Result { - let mut serial = SerialPort::open(port, 115_200)?; - serial.set_write_timeout(Duration::from_secs(10))?; - serial.set_read_timeout(Duration::from_millis(10))?; - let backend = Serial { serial }; - backend.reset()?; - Ok(backend) -} - -trait Backend { - fn send_command(&mut self, command: &Command) -> Result<(), Error>; - fn process_incoming_data( - &mut self, - data_type: DataType, - packets: &mut VecDeque, - ) -> Result, Error>; - fn close(&self) {} -} - -struct SerialBackend { - inner: Serial, +pub struct SerialBackend { + device: SerialPort, } impl Backend for SerialBackend { - fn send_command(&mut self, command: &Command) -> Result<(), Error> { - self.inner.send_command(command) + fn reset(&mut self) -> Result<(), Error> { + self.device.set_dtr(true)?; + let timeout = Instant::now(); + loop { + self.device.discard_buffers()?; + if self.device.read_dsr()? { + break; + } + if timeout.elapsed() > RESET_TIMEOUT { + return Err(Error::new("Couldn't reset SC64 device (on)")); + } + } + + self.purge_incoming_data()?; + + self.device.set_dtr(false)?; + let timeout = Instant::now(); + loop { + if !self.device.read_dsr()? { + break; + } + if timeout.elapsed() > RESET_TIMEOUT { + return Err(Error::new("Couldn't reset SC64 device (off)")); + } + } + + Ok(()) } - fn process_incoming_data( - &mut self, - data_type: DataType, - packets: &mut VecDeque, - ) -> Result, Error> { - self.inner.process_incoming_data(data_type, packets) + fn close(&self) {} + + fn read(&mut self, buffer: &mut [u8]) -> std::io::Result { + self.device.read(buffer) + } + + fn write(&mut self, buffer: &[u8]) -> std::io::Result<()> { + self.device.write_all(buffer) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.device.flush() } } -fn new_serial_backend(port: &str) -> Result { - let backend = SerialBackend { - inner: new_serial(port)?, - }; - Ok(backend) +fn new_serial_backend(port: &str) -> std::io::Result { + let mut serial = SerialPort::open(port, 115_200)?; + serial.set_read_timeout(POLL_TIMEOUT)?; + serial.set_write_timeout(WRITE_TIMEOUT)?; + Ok(SerialBackend { device: serial }) +} + +struct FtdiBackend { + device: FtdiDevice, +} + +impl Backend for FtdiBackend { + fn reset(&mut self) -> Result<(), Error> { + self.device.set_dtr(true)?; + let timeout = Instant::now(); + loop { + self.device.discard_buffers()?; + if self.device.read_dsr()? { + break; + } + if timeout.elapsed() > RESET_TIMEOUT { + return Err(Error::new("Couldn't reset SC64 device (on)")); + } + } + + self.purge_incoming_data()?; + + self.device.set_dtr(false)?; + let timeout = Instant::now(); + loop { + if !self.device.read_dsr()? { + break; + } + if timeout.elapsed() > RESET_TIMEOUT { + return Err(Error::new("Couldn't reset SC64 device (off)")); + } + } + + Ok(()) + } + + fn close(&self) {} + + fn read(&mut self, buffer: &mut [u8]) -> std::io::Result { + self.device.read(buffer) + } + + fn write(&mut self, buffer: &[u8]) -> std::io::Result<()> { + self.device.write_all(buffer) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +fn new_ftdi_backend(port: &str) -> Result { + Ok(FtdiBackend { + device: FtdiDevice::open(port, POLL_TIMEOUT, WRITE_TIMEOUT)?, + }) } struct TcpBackend { @@ -250,58 +305,40 @@ struct TcpBackend { writer: BufWriter, } -impl TcpBackend { - fn read_data(&mut self, buffer: &mut [u8], block: bool) -> Result, Error> { - let timeout = Instant::now(); - let mut position = 0; - let length = buffer.len(); - while position < length { - if timeout.elapsed() > Duration::from_secs(10) { - return Err(Error::new("Stream read timeout")); - } - match self.reader.read(&mut buffer[position..length]) { - Ok(0) => return Err(Error::new("Unexpected end of stream data")), - Ok(bytes) => position += bytes, - Err(error) => match error.kind() { - ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => { - if !block && position == 0 { - return Ok(None); - } - } - _ => return Err(error.into()), - }, - } - } - Ok(Some(())) - } - - fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - match self.read_data(buffer, true)? { - Some(()) => Ok(()), - None => Err(Error::new("Unexpected end of stream data")), - } - } - - fn read_header(&mut self, block: bool) -> Result, Error> { - let mut header = [0u8; 4]; - Ok(self.read_data(&mut header, block)?.map(|_| header)) - } -} - impl Backend for TcpBackend { + fn reset(&mut self) -> Result<(), Error> { + Ok(()) + } + + fn close(&self) { + self.stream.shutdown(std::net::Shutdown::Both).ok(); + } + + fn read(&mut self, buffer: &mut [u8]) -> std::io::Result { + self.reader.read(buffer) + } + + fn write(&mut self, buffer: &[u8]) -> std::io::Result<()> { + self.writer.write_all(buffer) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.writer.flush() + } + fn send_command(&mut self, command: &Command) -> Result<(), Error> { let payload_data_type: u32 = DataType::Command.into(); - self.writer.write_all(&payload_data_type.to_be_bytes())?; + self.write(&payload_data_type.to_be_bytes())?; - self.writer.write_all(&command.id.to_be_bytes())?; - self.writer.write_all(&command.args[0].to_be_bytes())?; - self.writer.write_all(&command.args[1].to_be_bytes())?; + self.write(&command.id.to_be_bytes())?; + self.write(&command.args[0].to_be_bytes())?; + self.write(&command.args[1].to_be_bytes())?; let command_data_length = command.data.len() as u32; - self.writer.write_all(&command_data_length.to_be_bytes())?; - self.writer.write_all(&command.data)?; + self.write(&command_data_length.to_be_bytes())?; + self.write(&command.data)?; - self.writer.flush()?; + self.flush()?; Ok(()) } @@ -312,7 +349,7 @@ impl Backend for TcpBackend { packets: &mut VecDeque, ) -> Result, Error> { let block = matches!(data_type, DataType::Response); - while let Some(header) = self.read_header(block)? { + while let Some(header) = self.try_read_header(block)? { let payload_data_type: DataType = u32::from_be_bytes(header).try_into()?; let mut buffer = [0u8; 4]; match payload_data_type { @@ -357,17 +394,13 @@ impl Backend for TcpBackend { Ok(None) } - - fn close(&self) { - self.stream.shutdown(std::net::Shutdown::Both).ok(); - } } fn new_tcp_backend(address: &str) -> Result { let stream = match TcpStream::connect(address) { Ok(stream) => { - stream.set_write_timeout(Some(Duration::from_secs(10)))?; - stream.set_read_timeout(Some(Duration::from_millis(10)))?; + stream.set_write_timeout(Some(WRITE_TIMEOUT))?; + stream.set_read_timeout(Some(POLL_TIMEOUT))?; stream } Err(error) => { @@ -385,8 +418,28 @@ fn new_tcp_backend(address: &str) -> Result { }) } +fn new_local_backend(port: &str) -> Result, Error> { + let mut backend: Box = if port.starts_with(SERIAL_PREFIX) { + Box::new(new_serial_backend( + port.strip_prefix(SERIAL_PREFIX).unwrap_or_default(), + )?) + } else if port.starts_with(FTDI_PREFIX) { + Box::new(new_ftdi_backend( + port.strip_prefix(FTDI_PREFIX).unwrap_or_default(), + )?) + } else { + return Err(Error::new("Invalid port prefix provided")); + }; + backend.reset()?; + Ok(backend) +} + +fn new_remote_backend(address: &str) -> Result, Error> { + Ok(Box::new(new_tcp_backend(address)?)) +} + pub struct Link { - backend: Box, + pub backend: Box, packets: VecDeque, } @@ -451,45 +504,76 @@ impl Drop for Link { pub fn new_local(port: &str) -> Result { Ok(Link { - backend: Box::new(new_serial_backend(port)?), + backend: new_local_backend(port)?, packets: VecDeque::new(), }) } pub fn new_remote(address: &str) -> Result { Ok(Link { - backend: Box::new(new_tcp_backend(address)?), + backend: new_remote_backend(address)?, packets: VecDeque::new(), }) } -pub struct LocalDevice { - pub port: String, - pub serial_number: String, +pub enum BackendType { + Serial, + Ftdi, } -pub fn list_local_devices() -> Result, Error> { +impl Display for BackendType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Serial => "serial", + Self::Ftdi => "libftdi", + }) + } +} + +pub struct DeviceInfo { + pub backend: BackendType, + pub port: String, + pub serial: String, +} + +pub fn list_local_devices() -> Result, Error> { const SC64_VID: u16 = 0x0403; const SC64_PID: u16 = 0x6014; const SC64_SID: &str = "SC64"; - let mut serial_devices: Vec = Vec::new(); + let mut devices: Vec = Vec::new(); - for device in serialport::available_ports()?.into_iter() { - if let serialport::SerialPortType::UsbPort(info) = device.port_type { - let serial_number = info.serial_number.unwrap_or("".to_string()); - if info.vid == SC64_VID && info.pid == SC64_PID && serial_number.starts_with(SC64_SID) { - serial_devices.push(LocalDevice { - port: device.port_name, - serial_number, - }); + if let Ok(list) = list_ftdi_devices(SC64_VID, SC64_PID) { + for device in list.into_iter() { + if device.serial.starts_with(SC64_SID) { + devices.push(DeviceInfo { + backend: BackendType::Ftdi, + port: format!("{FTDI_PREFIX}{}", device.port), + serial: device.serial, + }) } } } - if serial_devices.len() == 0 { + if let Ok(list) = serialport::available_ports() { + for device in list.into_iter() { + if let serialport::SerialPortType::UsbPort(i) = device.port_type { + if let Some(serial) = i.serial_number { + if i.vid == SC64_VID && i.pid == SC64_PID && serial.starts_with(SC64_SID) { + devices.push(DeviceInfo { + backend: BackendType::Serial, + port: format!("{SERIAL_PREFIX}{}", device.port_name), + serial, + }); + } + } + } + } + } + + if devices.len() == 0 { return Err(Error::new("No SC64 devices found")); } - return Ok(serial_devices); + return Ok(devices); } diff --git a/sw/deployer/src/sc64/mod.rs b/sw/deployer/src/sc64/mod.rs index a1ac764..9bb83dc 100644 --- a/sw/deployer/src/sc64/mod.rs +++ b/sw/deployer/src/sc64/mod.rs @@ -1,6 +1,7 @@ mod cic; mod error; pub mod firmware; +mod ftdi; mod link; pub mod server; mod time; diff --git a/sw/deployer/src/sc64/server.rs b/sw/deployer/src/sc64/server.rs index ae52a15..7cce340 100644 --- a/sw/deployer/src/sc64/server.rs +++ b/sw/deployer/src/sc64/server.rs @@ -1,19 +1,5 @@ -use super::{ - error::Error, - link::{list_local_devices, new_serial, Command, DataType, Packet, Response, Serial}, -}; -use std::{ - collections::VecDeque, - io::{BufReader, BufWriter, ErrorKind, Read, Write}, - net::{TcpListener, TcpStream}, - sync::{ - atomic::{AtomicBool, Ordering}, - mpsc::{channel, Receiver, Sender}, - Arc, - }, - thread, - time::{Duration, Instant}, -}; +use super::{error::Error, link::list_local_devices}; +use std::net::{TcpListener, TcpStream}; pub enum ServerEvent { Listening(String), @@ -55,204 +41,208 @@ pub fn run( Ok(()) } -enum Event { - Command(Command), - Response(Response), - Packet(Packet), - KeepAlive, - Closed(Option), -} +// enum Event { +// Command(Command), +// Response(Response), +// Packet(Packet), +// KeepAlive, +// Closed(Option), +// } -fn server_accept_connection(port: String, stream: &mut TcpStream) -> Result<(), Error> { - let (event_sender, event_receiver) = channel::(); - let exit_flag = Arc::new(AtomicBool::new(false)); +fn server_accept_connection(_port: String, _stream: &mut TcpStream) -> Result<(), Error> { + // let (event_sender, event_receiver) = channel::(); + // let exit_flag = Arc::new(AtomicBool::new(false)); - let mut stream_writer = BufWriter::new(stream.try_clone()?); - let mut stream_reader = stream.try_clone()?; + // let mut stream_writer = BufWriter::new(stream.try_clone()?); + // let mut stream_reader = stream.try_clone()?; - let serial = Arc::new(new_serial(&port)?); - let serial_writer = serial.clone(); - let serial_reader = serial.clone(); + // let serial = Arc::new(new_local(&port)?); + // let serial_writer = serial.clone(); + // let serial_reader = serial.clone(); - let stream_event_sender = event_sender.clone(); - let stream_exit_flag = exit_flag.clone(); - let stream_thread = thread::spawn(move || { - let closed_sender = stream_event_sender.clone(); - match server_stream_thread(&mut stream_reader, stream_event_sender, stream_exit_flag) { - Ok(()) => closed_sender.send(Event::Closed(None)), - Err(error) => closed_sender.send(Event::Closed(Some(error))), - } - .ok(); - }); + // let stream_event_sender = event_sender.clone(); + // let stream_exit_flag = exit_flag.clone(); + // let stream_thread = thread::spawn(move || { + // let closed_sender = stream_event_sender.clone(); + // match server_stream_thread(&mut stream_reader, stream_event_sender, stream_exit_flag) { + // Ok(()) => closed_sender.send(Event::Closed(None)), + // Err(error) => closed_sender.send(Event::Closed(Some(error))), + // } + // .ok(); + // }); - let serial_event_sender = event_sender.clone(); - let serial_exit_flag = exit_flag.clone(); - let serial_thread = thread::spawn(move || { - let closed_sender = serial_event_sender.clone(); - match server_serial_thread(serial_reader, serial_event_sender, serial_exit_flag) { - Ok(()) => closed_sender.send(Event::Closed(None)), - Err(error) => closed_sender.send(Event::Closed(Some(error))), - } - .ok(); - }); + // let serial_event_sender = event_sender.clone(); + // let serial_exit_flag = exit_flag.clone(); + // let serial_thread = thread::spawn(move || { + // let closed_sender = serial_event_sender.clone(); + // match server_serial_thread(serial_reader, serial_event_sender, serial_exit_flag) { + // Ok(()) => closed_sender.send(Event::Closed(None)), + // Err(error) => closed_sender.send(Event::Closed(Some(error))), + // } + // .ok(); + // }); - let keepalive_event_sender = event_sender.clone(); - let keepalive_exit_flag = exit_flag.clone(); - let keepalive_thread = thread::spawn(move || { - server_keepalive_thread(keepalive_event_sender, keepalive_exit_flag); - }); + // let keepalive_event_sender = event_sender.clone(); + // let keepalive_exit_flag = exit_flag.clone(); + // let keepalive_thread = thread::spawn(move || { + // server_keepalive_thread(keepalive_event_sender, keepalive_exit_flag); + // }); - let result = server_process_events(&mut stream_writer, serial_writer, event_receiver); + // let result = server_process_events(&mut stream_writer, serial_writer, event_receiver); - exit_flag.store(true, Ordering::Relaxed); - stream_thread.join().ok(); - serial_thread.join().ok(); - keepalive_thread.join().ok(); - - result -} - -fn server_process_events( - stream_writer: &mut BufWriter, - serial_writer: Arc, - event_receiver: Receiver, -) -> Result<(), Error> { - for event in event_receiver.into_iter() { - match event { - Event::Command(command) => { - serial_writer.send_command(&command)?; - } - Event::Response(response) => { - stream_writer.write_all(&u32::to_be_bytes(DataType::Response.into()))?; - stream_writer.write_all(&[response.id])?; - stream_writer.write_all(&[response.error as u8])?; - stream_writer.write_all(&(response.data.len() as u32).to_be_bytes())?; - stream_writer.write_all(&response.data)?; - stream_writer.flush()?; - } - Event::Packet(packet) => { - stream_writer.write_all(&u32::to_be_bytes(DataType::Packet.into()))?; - stream_writer.write_all(&[packet.id])?; - stream_writer.write_all(&(packet.data.len() as u32).to_be_bytes())?; - stream_writer.write_all(&packet.data)?; - stream_writer.flush()?; - } - Event::KeepAlive => { - stream_writer.write_all(&u32::to_be_bytes(DataType::KeepAlive.into()))?; - stream_writer.flush()?; - } - Event::Closed(result) => match result { - Some(error) => return Err(error), - None => { - break; - } - }, - } - } + // exit_flag.store(true, Ordering::Relaxed); + // stream_thread.join().ok(); + // serial_thread.join().ok(); + // keepalive_thread.join().ok(); + // result Ok(()) } -fn server_stream_thread( - stream: &mut TcpStream, - event_sender: Sender, - exit_flag: Arc, -) -> Result<(), Error> { - let mut stream_reader = BufReader::new(stream.try_clone()?); +// fn server_process_events( +// stream_writer: &mut BufWriter, +// link: &mut Link, +// event_receiver: Receiver, +// ) -> Result<(), Error> { +// for event in event_receiver.into_iter() { +// match event { +// Event::Command(command) => { +// // serial_writer.send_command(&command)?; +// // serial_writer. +// // link.execute_command(&command)?; +// link.execute_command(&command)?; +// } +// Event::Response(response) => { +// stream_writer.write_all(&u32::to_be_bytes(DataType::Response.into()))?; +// stream_writer.write_all(&[response.id])?; +// stream_writer.write_all(&[response.error as u8])?; +// stream_writer.write_all(&(response.data.len() as u32).to_be_bytes())?; +// stream_writer.write_all(&response.data)?; +// stream_writer.flush()?; +// } +// Event::Packet(packet) => { +// stream_writer.write_all(&u32::to_be_bytes(DataType::Packet.into()))?; +// stream_writer.write_all(&[packet.id])?; +// stream_writer.write_all(&(packet.data.len() as u32).to_be_bytes())?; +// stream_writer.write_all(&packet.data)?; +// stream_writer.flush()?; +// } +// Event::KeepAlive => { +// stream_writer.write_all(&u32::to_be_bytes(DataType::KeepAlive.into()))?; +// stream_writer.flush()?; +// } +// Event::Closed(result) => match result { +// Some(error) => return Err(error), +// None => { +// break; +// } +// }, +// } +// } - let mut header = [0u8; 4]; - let header_length = header.len(); +// Ok(()) +// } - loop { - let mut header_position = 0; +// fn server_stream_thread( +// stream: &mut TcpStream, +// event_sender: Sender, +// exit_flag: Arc, +// ) -> Result<(), Error> { +// let mut stream_reader = BufReader::new(stream.try_clone()?); - let timeout = stream.read_timeout()?; - stream.set_read_timeout(Some(Duration::from_millis(10)))?; - while header_position < header_length { - if exit_flag.load(Ordering::Relaxed) { - return Ok(()); - } - match stream_reader.read(&mut header[header_position..header_length]) { - Ok(0) => return Ok(()), - Ok(bytes) => header_position += bytes, - Err(error) => match error.kind() { - ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => {} - _ => return Err(error.into()), - }, - } - } - stream.set_read_timeout(timeout)?; +// let mut header = [0u8; 4]; +// let header_length = header.len(); - let data_type: DataType = u32::from_be_bytes(header).try_into()?; - if !matches!(data_type, DataType::Command) { - return Err(Error::new("Received data type was not a command data type")); - } +// loop { +// let mut header_position = 0; - let mut buffer = [0u8; 4]; - let mut id_buffer = [0u8; 1]; - let mut args = [0u32; 2]; +// let timeout = stream.read_timeout()?; +// stream.set_read_timeout(Some(Duration::from_millis(10)))?; +// while header_position < header_length { +// if exit_flag.load(Ordering::Relaxed) { +// return Ok(()); +// } +// match stream_reader.read(&mut header[header_position..header_length]) { +// Ok(0) => return Ok(()), +// Ok(bytes) => header_position += bytes, +// Err(error) => match error.kind() { +// ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => {} +// _ => return Err(error.into()), +// }, +// } +// } +// stream.set_read_timeout(timeout)?; - stream_reader.read_exact(&mut id_buffer)?; - let id = id_buffer[0]; +// let data_type: DataType = u32::from_be_bytes(header).try_into()?; +// if !matches!(data_type, DataType::Command) { +// return Err(Error::new("Received data type was not a command data type")); +// } - stream_reader.read_exact(&mut buffer)?; - args[0] = u32::from_be_bytes(buffer); - stream_reader.read_exact(&mut buffer)?; - args[1] = u32::from_be_bytes(buffer); +// let mut buffer = [0u8; 4]; +// let mut id_buffer = [0u8; 1]; +// let mut args = [0u32; 2]; - stream_reader.read_exact(&mut buffer)?; - let command_data_length = u32::from_be_bytes(buffer) as usize; - let mut data = vec![0u8; command_data_length]; - stream_reader.read_exact(&mut data)?; +// stream_reader.read_exact(&mut id_buffer)?; +// let id = id_buffer[0]; - if event_sender - .send(Event::Command(Command { id, args, data })) - .is_err() - { - break; - } - } +// stream_reader.read_exact(&mut buffer)?; +// args[0] = u32::from_be_bytes(buffer); +// stream_reader.read_exact(&mut buffer)?; +// args[1] = u32::from_be_bytes(buffer); - Ok(()) -} +// stream_reader.read_exact(&mut buffer)?; +// let command_data_length = u32::from_be_bytes(buffer) as usize; +// let mut data = vec![0u8; command_data_length]; +// stream_reader.read_exact(&mut data)?; -fn server_serial_thread( - serial_reader: Arc, - event_sender: Sender, - exit_flag: Arc, -) -> Result<(), Error> { - let mut packets: VecDeque = VecDeque::new(); +// if event_sender +// .send(Event::Command(Command { id, args, data })) +// .is_err() +// { +// break; +// } +// } - while !exit_flag.load(Ordering::Relaxed) { - let response = serial_reader.process_incoming_data(DataType::Packet, &mut packets)?; +// Ok(()) +// } - if let Some(response) = response { - if event_sender.send(Event::Response(response)).is_err() { - break; - } - } +// fn server_serial_thread( +// link: &mut Link, +// event_sender: Sender, +// exit_flag: Arc, +// ) -> Result<(), Error> { +// let mut packets: VecDeque = VecDeque::new(); - if let Some(packet) = packets.pop_front() { - if event_sender.send(Event::Packet(packet)).is_err() { - break; - } - } - } +// while !exit_flag.load(Ordering::Relaxed) { +// let response = link.backend.process_incoming_data(DataType::Packet, &mut packets)?; - Ok(()) -} +// if let Some(response) = response { +// if event_sender.send(Event::Response(response)).is_err() { +// break; +// } +// } -fn server_keepalive_thread(event_sender: Sender, exit_flag: Arc) { - let mut keepalive = Instant::now(); +// if let Some(packet) = packets.pop_front() { +// if event_sender.send(Event::Packet(packet)).is_err() { +// break; +// } +// } +// } - while !exit_flag.load(Ordering::Relaxed) { - if keepalive.elapsed() >= Duration::from_secs(5) { - keepalive = Instant::now(); - if event_sender.send(Event::KeepAlive).is_err() { - break; - } - } else { - thread::sleep(Duration::from_millis(10)); - } - } -} +// Ok(()) +// } + +// fn server_keepalive_thread(event_sender: Sender, exit_flag: Arc) { +// let mut keepalive = Instant::now(); + +// while !exit_flag.load(Ordering::Relaxed) { +// if keepalive.elapsed() >= Duration::from_secs(5) { +// keepalive = Instant::now(); +// if event_sender.send(Event::KeepAlive).is_err() { +// break; +// } +// } else { +// thread::sleep(Duration::from_millis(100)); +// } +// } +// }