Initial commit
This commit is contained in:
commit
64574bd2fa
12 changed files with 954 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
/.idea
|
558
Cargo.lock
generated
Normal file
558
Cargo.lock
generated
Normal file
|
@ -0,0 +1,558 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"color-spantrace",
|
||||
"eyre",
|
||||
"indenter",
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
"tracing-core",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deckster"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"loupedeck_serial",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-ordinalize"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5"
|
||||
dependencies = [
|
||||
"enum-ordinalize-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-ordinalize-derive"
|
||||
version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d"
|
||||
dependencies = [
|
||||
"enumset_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset_derive"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "io-kit-sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4769cb30e5dcf1710fc6730d3e94f78c47723a014a567de385e113c737394640"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"mach2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "libudev"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libudev-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libudev-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "loupedeck_serial"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"enum-ordinalize",
|
||||
"enumset",
|
||||
"serialport",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serialport"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f5a15d0be940df84846264b09b51b10b931fb2f275becb80934e3568a016828"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
"io-kit-sys",
|
||||
"libudev",
|
||||
"mach2",
|
||||
"nix",
|
||||
"regex",
|
||||
"scopeguard",
|
||||
"unescaper",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-error"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"sharded-slab",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unescaper"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f0f68e58d297ba8b22b8b5a96a87b863ba6bb46aaf51e19a4b02c5a6dd5b7f"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"deckster",
|
||||
"loupedeck_serial"
|
||||
]
|
||||
|
||||
resolver = "2"
|
55
LICENSE.md
Normal file
55
LICENSE.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Blue Oak Model License
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This license gives everyone as much permission to work with
|
||||
this software as possible, while protecting contributors
|
||||
from liability.
|
||||
|
||||
## Acceptance
|
||||
|
||||
In order to receive this license, you must agree to its
|
||||
rules. The rules of this license are both obligations
|
||||
under that agreement and conditions to your license.
|
||||
You must not do anything with this software that triggers
|
||||
a rule that you cannot or will not follow.
|
||||
|
||||
## Copyright
|
||||
|
||||
Each contributor licenses you to do everything with this
|
||||
software that would otherwise infringe that contributor's
|
||||
copyright in it.
|
||||
|
||||
## Notices
|
||||
|
||||
You must ensure that everyone who gets a copy of
|
||||
any part of this software from you, with or without
|
||||
changes, also gets the text of this license or a link to
|
||||
<https://blueoakcouncil.org/license/1.0.0>.
|
||||
|
||||
## Excuse
|
||||
|
||||
If anyone notifies you in writing that you have not
|
||||
complied with [Notices](#notices), you can keep your
|
||||
license by taking all practical steps to comply within 30
|
||||
days after the notice. If you do not do so, your license
|
||||
ends immediately.
|
||||
|
||||
## Patent
|
||||
|
||||
Each contributor licenses you to do everything with this
|
||||
software that would otherwise infringe any patent claims
|
||||
they can license or become able to license.
|
||||
|
||||
## Reliability
|
||||
|
||||
No contributor can revoke this license.
|
||||
|
||||
## No Liability
|
||||
|
||||
***As far as the law allows, this software comes as is,
|
||||
without any warranty or condition, and no contributor
|
||||
will be liable to anyone for any damages related to this
|
||||
software or this license, under any kind of legal claim.***
|
6
README.md
Normal file
6
README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Deckster
|
||||
|
||||
## Attribution
|
||||
[foxxyz’s `loupedeck` library for JavaScript](https://github.com/foxxyz/loupedeck)
|
||||
(licensed under the [MIT license](https://github.com/foxxyz/loupedeck/blob/e41e5d920130d9ef651e47173c68450b9c832b96/LICENSE))
|
||||
was used as a reference for and inspired the design of `loupedeck_serial`.
|
8
deckster/Cargo.toml
Normal file
8
deckster/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "deckster"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
loupedeck_serial = { path = "../loupedeck_serial" }
|
||||
color-eyre = "0.6.2"
|
14
deckster/src/main.rs
Normal file
14
deckster/src/main.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use color_eyre::eyre::ContextCompat;
|
||||
use color_eyre::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let available_devices = loupedeck_serial::device::LoupedeckDevice::discover()?;
|
||||
|
||||
let mut device = available_devices.first()
|
||||
.wrap_err("at least one device should be connected")?
|
||||
.open()?;
|
||||
|
||||
device.connect()?;
|
||||
|
||||
Ok(())
|
||||
}
|
11
loupedeck_serial/Cargo.toml
Normal file
11
loupedeck_serial/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "loupedeck_serial"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serialport = "4.3.0"
|
||||
enum-ordinalize = "4.3.0"
|
||||
enumset = "1.1.3"
|
||||
bytes = "1.5.0"
|
||||
thiserror = "1.0.52"
|
112
loupedeck_serial/src/characteristics.rs
Normal file
112
loupedeck_serial/src/characteristics.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
use enum_ordinalize::Ordinalize;
|
||||
use enumset::{enum_set, EnumSet, EnumSetType};
|
||||
|
||||
#[derive(Debug, Ordinalize, EnumSetType)]
|
||||
#[repr(u16)]
|
||||
pub enum LoupedeckDeviceKnob {
|
||||
KnobTopLeft = 0x01,
|
||||
KnobCenterLeft = 0x02,
|
||||
KnobBottomLeft = 0x03,
|
||||
KnobTopRight = 0x04,
|
||||
KnobCenterRight = 0x05,
|
||||
KnobBottomRight = 0x06,
|
||||
}
|
||||
|
||||
#[derive(Debug, Ordinalize, EnumSetType)]
|
||||
#[repr(u16)]
|
||||
pub enum LoupedeckDeviceButton {
|
||||
KnobTopLeft = 0x01,
|
||||
KnobCenterLeft = 0x02,
|
||||
KnobBottomLeft = 0x03,
|
||||
KnobTopRight = 0x04,
|
||||
KnobCenterRight = 0x05,
|
||||
KnobBottomRight = 0x06,
|
||||
N0 = 0x07,
|
||||
N1 = 0x08,
|
||||
N2 = 0x09,
|
||||
N3 = 0x0a,
|
||||
N4 = 0x0b,
|
||||
N5 = 0x0c,
|
||||
N6 = 0x0d,
|
||||
N7 = 0x0e,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoupedeckDeviceDisplayEndianness {
|
||||
BigEndian,
|
||||
LittleEndian
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoupedeckDeviceDisplayConfiguration {
|
||||
pub id: u8,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub offset: (usize, usize),
|
||||
pub endianness: LoupedeckDeviceDisplayEndianness
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoupedeckDeviceCharacteristics {
|
||||
pub vendor_id: u16,
|
||||
pub product_id: u16,
|
||||
pub name: &'static str,
|
||||
pub available_knobs: EnumSet<LoupedeckDeviceKnob>,
|
||||
pub available_buttons: EnumSet<LoupedeckDeviceButton>,
|
||||
pub key_grid_dimensions: (usize, usize),
|
||||
pub displays: &'static [LoupedeckDeviceDisplayConfiguration]
|
||||
}
|
||||
|
||||
static LOUPEDECK_LIVE_CHARACTERISTIC: LoupedeckDeviceCharacteristics = LoupedeckDeviceCharacteristics {
|
||||
vendor_id: 0x2ec2,
|
||||
product_id: 0x0004,
|
||||
name: "Loupedeck Live",
|
||||
available_knobs: enum_set!(LoupedeckDeviceKnob::KnobTopLeft
|
||||
| LoupedeckDeviceKnob::KnobCenterLeft
|
||||
| LoupedeckDeviceKnob::KnobBottomLeft
|
||||
| LoupedeckDeviceKnob::KnobTopRight
|
||||
| LoupedeckDeviceKnob::KnobCenterRight
|
||||
| LoupedeckDeviceKnob::KnobBottomRight),
|
||||
available_buttons: enum_set!(LoupedeckDeviceButton::KnobTopLeft
|
||||
| LoupedeckDeviceButton::KnobCenterLeft
|
||||
| LoupedeckDeviceButton::KnobBottomLeft
|
||||
| LoupedeckDeviceButton::KnobTopRight
|
||||
| LoupedeckDeviceButton::KnobCenterRight
|
||||
| LoupedeckDeviceButton::KnobBottomRight
|
||||
| LoupedeckDeviceButton::N0
|
||||
| LoupedeckDeviceButton::N1
|
||||
| LoupedeckDeviceButton::N2
|
||||
| LoupedeckDeviceButton::N3
|
||||
| LoupedeckDeviceButton::N4
|
||||
| LoupedeckDeviceButton::N5
|
||||
| LoupedeckDeviceButton::N6
|
||||
| LoupedeckDeviceButton::N7),
|
||||
key_grid_dimensions: (4, 3),
|
||||
displays: &[
|
||||
LoupedeckDeviceDisplayConfiguration { // Left
|
||||
id: 0x4d,
|
||||
width: 60,
|
||||
height: 270,
|
||||
offset: (0, 0),
|
||||
endianness: LoupedeckDeviceDisplayEndianness::LittleEndian,
|
||||
},
|
||||
LoupedeckDeviceDisplayConfiguration { // Center
|
||||
id: 0x4d,
|
||||
width: 360,
|
||||
height: 270,
|
||||
offset: (60, 0),
|
||||
endianness: LoupedeckDeviceDisplayEndianness::LittleEndian,
|
||||
},
|
||||
LoupedeckDeviceDisplayConfiguration { // Right
|
||||
id: 0x4d,
|
||||
width: 60,
|
||||
height: 270,
|
||||
offset: (420, 0),
|
||||
endianness: LoupedeckDeviceDisplayEndianness::LittleEndian,
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
pub static CHARACTERISTICS: [&LoupedeckDeviceCharacteristics; 1] = [
|
||||
&LOUPEDECK_LIVE_CHARACTERISTIC
|
||||
];
|
145
loupedeck_serial/src/device.rs
Normal file
145
loupedeck_serial/src/device.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
use std::io;
|
||||
use std::io::{BufReader, Read, Write};
|
||||
use std::io::ErrorKind::TimedOut;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{Sender, sync_channel, SyncSender};
|
||||
use std::thread::spawn;
|
||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
use serialport::{SerialPort, SerialPortType};
|
||||
use thiserror::Error;
|
||||
use crate::characteristics::{CHARACTERISTICS, LoupedeckDeviceCharacteristics};
|
||||
use crate::discovery::AvailableLoupedeckDevice;
|
||||
|
||||
const WS_UPGRADE_REQUEST: &str = r#"GET /index.html
|
||||
HTTP/1.1
|
||||
Connection: Upgrade
|
||||
Upgrade: websocket
|
||||
Sec-WebSocket-Key: 123abc
|
||||
|
||||
"#;
|
||||
|
||||
const WS_UPGRADE_RESPONSE_START: &str = "HTTP/1.1 101 Switching Protocols\r\n\
|
||||
Upgrade: websocket\r\n\
|
||||
Connection: Upgrade\r\n\
|
||||
Sec-WebSocket-Accept: ALtlZo9FMEUEQleXJmq++ukUQ1s=";
|
||||
|
||||
const MESSAGE_START_BYTE: u8 = 0x82;
|
||||
const MAX_MESSAGE_LENGTH: usize = u8::MAX as usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoupedeckDevice {
|
||||
pub(crate) port: Option<Box<dyn SerialPort>>,
|
||||
pub characteristics: &'static LoupedeckDeviceCharacteristics,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConnectError {
|
||||
#[error("IO Error: {0}")]
|
||||
IO(#[from] io::Error),
|
||||
|
||||
#[error("The device did not respond with the expected handshake response.")]
|
||||
WrongHandshakeResponse,
|
||||
}
|
||||
|
||||
impl LoupedeckDevice {
|
||||
pub fn new_unchecked(port: Box<dyn SerialPort>, characteristics: &'static LoupedeckDeviceCharacteristics) -> LoupedeckDevice {
|
||||
LoupedeckDevice {
|
||||
port: Some(port),
|
||||
characteristics,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn discover() -> Result<Vec<AvailableLoupedeckDevice>, serialport::Error> {
|
||||
let ports = serialport::available_ports()?;
|
||||
|
||||
Ok(ports.iter().filter_map(|port| {
|
||||
if let SerialPortType::UsbPort(info) = &port.port_type {
|
||||
let characteristics = CHARACTERISTICS.iter()
|
||||
.find(|c| c.vendor_id == info.vid && c.product_id == info.pid);
|
||||
|
||||
if let Some(characteristics) = characteristics {
|
||||
return Some(AvailableLoupedeckDevice {
|
||||
port_name: port.port_name.clone(),
|
||||
characteristics,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn connect(&mut self) -> Result<(), ConnectError> {
|
||||
let mut port = self.port.take().expect("already connected");
|
||||
port.write_all(WS_UPGRADE_REQUEST.as_bytes())?;
|
||||
port.flush()?;
|
||||
|
||||
let mut buf = [0; WS_UPGRADE_RESPONSE_START.len()];
|
||||
port.read_exact(&mut buf)?;
|
||||
|
||||
if buf != WS_UPGRADE_RESPONSE_START.as_bytes() {
|
||||
return Err(ConnectError::WrongHandshakeResponse);
|
||||
}
|
||||
|
||||
let (sender, receiver) = sync_channel::<Bytes>(8);
|
||||
let handle = spawn(move || {
|
||||
LoupedeckDevice::handle_messages(port, sender);
|
||||
});
|
||||
|
||||
for x in receiver {
|
||||
dbg!(&x[1]);
|
||||
}
|
||||
|
||||
handle.join().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_messages(mut port: Box<dyn SerialPort>, sender: SyncSender<Bytes>) {
|
||||
let mut buffer = BytesMut::new();
|
||||
|
||||
loop {
|
||||
let mut chunk = BytesMut::zeroed(MAX_MESSAGE_LENGTH);
|
||||
let read_result = port.read(&mut chunk);
|
||||
|
||||
if let Err(err) = &read_result {
|
||||
if err.kind() == TimedOut {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let len = read_result.unwrap();
|
||||
if len == 0 {
|
||||
panic!("read 0 bytes");
|
||||
}
|
||||
|
||||
chunk.truncate(len);
|
||||
buffer.put(chunk);
|
||||
|
||||
loop {
|
||||
let start_index = buffer.iter().position(|b| *b == MESSAGE_START_BYTE);
|
||||
|
||||
if let Some(start_index) = start_index {
|
||||
if start_index > 0 {
|
||||
buffer.advance(start_index);
|
||||
|
||||
if buffer.remaining() == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let length = buffer[1] as usize + 2;
|
||||
if length > buffer.remaining() {
|
||||
break;
|
||||
} else {
|
||||
let mut message = buffer.split_to(length);
|
||||
message.advance(2);
|
||||
sender.send(message.freeze()).unwrap();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
loupedeck_serial/src/discovery.rs
Normal file
33
loupedeck_serial/src/discovery.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use std::time::Duration;
|
||||
use serialport::{DataBits, FlowControl, Parity, StopBits};
|
||||
use crate::characteristics::LoupedeckDeviceCharacteristics;
|
||||
use crate::device::LoupedeckDevice;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AvailableLoupedeckDevice {
|
||||
pub(crate) port_name: String,
|
||||
pub(crate) characteristics: &'static LoupedeckDeviceCharacteristics,
|
||||
}
|
||||
|
||||
impl AvailableLoupedeckDevice {
|
||||
pub fn port_name(&self) -> &str {
|
||||
&self.port_name
|
||||
}
|
||||
|
||||
pub fn characteristics(&self) -> &'static LoupedeckDeviceCharacteristics {
|
||||
self.characteristics
|
||||
}
|
||||
|
||||
pub fn open(&self) -> Result<LoupedeckDevice, serialport::Error> {
|
||||
Ok(LoupedeckDevice {
|
||||
port: Some(serialport::new(&self.port_name, 256000)
|
||||
.data_bits(DataBits::Eight)
|
||||
.stop_bits(StopBits::One)
|
||||
.parity(Parity::None)
|
||||
.flow_control(FlowControl::None)
|
||||
.timeout(Duration::from_secs(10))
|
||||
.open()?),
|
||||
characteristics: self.characteristics,
|
||||
})
|
||||
}
|
||||
}
|
3
loupedeck_serial/src/lib.rs
Normal file
3
loupedeck_serial/src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod characteristics;
|
||||
pub mod device;
|
||||
pub mod discovery;
|
Loading…
Add table
Reference in a new issue