diff --git a/Cargo.lock b/Cargo.lock index 5c9864c..10746a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,20 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "b9a8f622bcf6ff3df478e9deba3e03e4e04b300f8e6a139e192c05fa3490afc7" + +[[package]] +name = "async-trait" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "autocfg" @@ -38,32 +49,195 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bluez-async" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e81db626818b179ab5fc3393b7ac77462335f716b302ef1ff1866473ab6ddb25" +dependencies = [ + "async-trait", + "bitflags", + "bluez-generated", + "dbus", + "dbus-tokio", + "futures", + "itertools", + "log", + "serde", + "serde-xml-rs", + "thiserror", + "tokio", + "uuid", +] + +[[package]] +name = "bluez-generated" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ad8f302dd79411881cd0181f3bd9fc91a959b71c3a13159bd8a07d2c40dc7f" +dependencies = [ + "dbus", +] + +[[package]] +name = "btleplug" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4a6513650aae4fbaeab7ed4e3ef14f8e095d156ecc687f2391f75741e788fa" +dependencies = [ + "async-trait", + "bitflags", + "bluez-async", + "cocoa", + "dashmap", + "dbus", + "futures", + "jni", + "jni-utils", + "libc", + "log", + "objc", + "once_cell", + "static_assertions", + "thiserror", + "tokio", + "tokio-stream", + "uuid", + "windows", +] + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + [[package]] name = "cc" version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + [[package]] name = "cppvtbl" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "574c8b3f359807d21c4e211e076a9084656971b5a0b7aeb4d464ba20a029c719" +checksum = "1730ce1c1ace2663aae6433ad316230868b4c111e11d61e1742f019016771906" dependencies = [ "cppvtbl-macros", ] [[package]] name = "cppvtbl-macros" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ab98c91f5b37bbac5de658fdbb22dd02a475106f829c0d567de46963ed4cb9" +checksum = "05081a934c57bb229a28a61ee9a343df2c0695d7d48113922aa82471b9172f05" dependencies = [ "proc-macro2", "quote", @@ -79,6 +253,53 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ctrlc" +version = "3.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173" +dependencies = [ + "nix", + "winapi", +] + +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dbus" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8bcdd56d2e5c4ed26a529c5a9029f5db8290d433497506f958eae3be148eb6" +dependencies = [ + "futures-channel", + "futures-util", + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "dbus-tokio" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12a1a74a0c53b22d7d994256cf3ecbeefa5eedce3cf9d362945ac523c4132180" +dependencies = [ + "dbus", + "libc", + "tokio", +] + [[package]] name = "driver-proxy" version = "0.1.0" @@ -92,39 +313,208 @@ dependencies = [ "process_path", "real_c_string", "thiserror", + "tokio", "tracing", "tracing-subscriber", + "valve-pm", "vive-hid", ] +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", "miniz_oxide", ] +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "futures" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" + +[[package]] +name = "futures-executor" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" + +[[package]] +name = "futures-macro" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" + +[[package]] +name = "futures-task" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" + +[[package]] +name = "futures-util" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hidapi" -version = "1.3.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd21b5ac4a597bf657ed92a5b078f46a011837bda14afb7a07a5c1157c33ac2" +checksum = "9d26e1151deaab68f34fbfd16d491a2a0170cf98d69d3efa23873b567a4199e1" dependencies = [ "cc", "libc", "pkg-config", ] +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jni-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d3a00638470bedd9bcbea85292bef2207e6db984079db0bd70148a449cdb457" +dependencies = [ + "dashmap", + "futures", + "jni", + "log", + "once_cell", + "static_assertions", + "uuid", +] [[package]] name = "lazy_static" @@ -169,9 +559,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.119" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "libdbus-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b" +dependencies = [ + "pkg-config", +] [[package]] name = "libloading" @@ -183,30 +582,97 @@ dependencies = [ "winapi", ] +[[package]] +name = "lock_api" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "nix" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +dependencies = [ "autocfg", + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", ] [[package]] name = "once_cell" -version = "1.10.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "openvr" @@ -216,32 +682,51 @@ dependencies = [ "real_c_string", ] +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "process_path" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe7f344db15ba012152680e204d5869ec60cb0d8acfda230069484f4fa3811b" +checksum = "f676f11eb0b3e2ea0fbaee218fa6b806689e2297b8c8adc5bf73df465c4f6171" dependencies = [ "libc", "winapi", @@ -249,9 +734,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -267,26 +752,62 @@ dependencies = [ "syn", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-xml-rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa" +dependencies = [ + "log", + "serde", + "thiserror", + "xml-rs", +] + [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -295,9 +816,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa", "ryu", @@ -313,37 +834,62 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" -version = "1.8.0" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "1.0.86" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" dependencies = [ "proc-macro2", "quote", @@ -359,11 +905,64 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tokio" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42" +dependencies = [ + "autocfg", + "libc", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "tracing" -version = "0.1.31" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if", "pin-project-lite", @@ -373,9 +972,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -384,19 +983,19 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.22" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ - "lazy_static", + "once_cell", "valuable", ] [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -405,9 +1004,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.9" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" dependencies = [ "ansi_term", "sharded-slab", @@ -418,10 +1017,16 @@ dependencies = [ ] [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "uuid" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" [[package]] name = "valuable" @@ -429,6 +1034,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "valve-pm" +version = "0.1.0" +dependencies = [ + "btleplug", + "ctrlc", + "futures-util", + "once_cell", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "uuid", +] + [[package]] name = "vive-hid" version = "0.1.0" @@ -439,8 +1059,27 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winapi" version = "0.3.9" @@ -457,8 +1096,109 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +dependencies = [ + "windows_aarch64_msvc 0.39.0", + "windows_i686_gnu 0.39.0", + "windows_i686_msvc 0.39.0", + "windows_x86_64_gnu 0.39.0", + "windows_x86_64_msvc 0.39.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/README.md b/README.md index a9f63ad..d17ae17 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,13 @@ Current implementation of driver intercepts some calls between SteamVR and commo - HMD image - standard interface (DP) used, however there are some things missing in kernel, see patches below - Audio output - standard interface used - Front facing camera - works, with minor noise/distortion, standard interface (UVC) used +- Lighthouse power management - Headset, controllers, Vive tracker (tracking) - part of original driver - Headset/controllers firmware updates - part of original driver ### TODO -- Configuration utilities - most of reconfiguration (resolution, noise cancelation, brightness) abilities are already reverse-engineered, they just aren't easly configurable, some GUI utility should be written +- Configuration utilities - most of reconfiguration (resolution, noise cancelation, brightness, lighthouse power management) abilities are already reverse-engineered, they just aren't easly configurable, some GUI utility should be written - Focus knob overlay (Some third-party may work though). Focusing does work, but there is no visual helper. - Audio output is not targeted to correct device yet (You need to manually switch it every time), it should be possible to implement this feature in this driver however - Front facing camera noise - can be solved with some kernel tinkering (UVC driver) @@ -58,9 +59,9 @@ Latest version of driver [automatically patches](https://github.com/CertainLach/ In `steamvr.vrsettings`: -`vivepro2.resolution`: `0-5` +`vivepro2.resolution`: `0-5`, 0 by default, to make it most compatible with every hardware -Reconfigures helmet before startup +Reconfigures helmet to specified resolution/framerate before startup - 0 - 2448x1224 90fps - 1 - 2448x1224 120fps @@ -71,17 +72,17 @@ Reconfigures helmet before startup Similar to original vive console utility -`vivepro2.brightness`: `1-130` +`vivepro2.brightness`: `1-130`, 130 by default Display brightness Original vive console seems to fade from 0 to 130 on start, and then no longer touch this setting -`vivepro2.noiseCancel`: `true/false` +`vivepro2.noiseCancel`: `true/false`, disabled by default Toggle built-in microphone noise canceling -Similar option exists in vive console, +Similar option exists in vive console ## Required kernel patches @@ -102,6 +103,8 @@ boot.kernelPatches = vivepro2-linux-driver.kernelPatches; If you use arch btw, then you can use this kernel package with all required patches applied (i have not tested it, and can't provide any guarantees about contents of this repo): https://github.com/santeri3700/vive-pro-2-on-linux +I don't recommend using other distributions, because it will be harder, because of usage of bleeding-edge kernel, but it should work, and I will fix any issues with them (I.e I have fixed usage of this driver on ubuntu) + ## Donate I dont have enough motivation making this thing work for everyone/adding features everyone wants/needs diff --git a/bin/driver-proxy/Cargo.toml b/bin/driver-proxy/Cargo.toml index 4b2cbd6..accfb0b 100644 --- a/bin/driver-proxy/Cargo.toml +++ b/bin/driver-proxy/Cargo.toml @@ -14,10 +14,12 @@ tracing-subscriber = "0.3.9" cppvtbl = "0.2.0" real_c_string = "1.0.0" +valve-pm = { path = "../../crates/valve-pm" } vive-hid = { path = "../../crates/vive-hid" } lens-client = { path = "../../crates/lens-client" } lens-protocol = { path = "../../crates/lens-protocol" } openvr = { path = "../../crates/openvr" } +tokio = { version = "1.21.0", features = ["rt", "rt-multi-thread"] } [lib] crate-type = ["cdylib"] diff --git a/bin/driver-proxy/src/camera.rs b/bin/driver-proxy/src/driver/camera.rs similarity index 100% rename from bin/driver-proxy/src/camera.rs rename to bin/driver-proxy/src/driver/camera.rs diff --git a/bin/driver-proxy/src/hmd.rs b/bin/driver-proxy/src/driver/hmd.rs similarity index 99% rename from bin/driver-proxy/src/hmd.rs rename to bin/driver-proxy/src/driver/hmd.rs index d71c2f0..5f87ba1 100644 --- a/bin/driver-proxy/src/hmd.rs +++ b/bin/driver-proxy/src/driver/hmd.rs @@ -140,7 +140,6 @@ impl IVRDisplayComponent for HmdDisplay { #[impl_vtables(ITrackedDeviceServerDriver)] pub struct HmdDriver { // pub steam: Rc, - // pub vive: Rc, pub lens: Rc>, pub real: &'static VtableRef, pub mode: Mode, diff --git a/bin/driver-proxy/src/driver/mod.rs b/bin/driver-proxy/src/driver/mod.rs new file mode 100644 index 0000000..e41e849 --- /dev/null +++ b/bin/driver-proxy/src/driver/mod.rs @@ -0,0 +1,3 @@ +pub mod camera; +pub mod hmd; +pub mod server_tracked_provider; diff --git a/bin/driver-proxy/src/driver/server_tracked_provider.rs b/bin/driver-proxy/src/driver/server_tracked_provider.rs new file mode 100644 index 0000000..07c6190 --- /dev/null +++ b/bin/driver-proxy/src/driver/server_tracked_provider.rs @@ -0,0 +1,138 @@ +use std::{ + cell::{Cell, RefCell}, + os::raw::c_char, + sync::Mutex, +}; + +use crate::{ + driver_context::{try_init_driver_context, DRIVER_CONTEXT}, + factory::{get_hmd_driver_factory, TOKIO_RUNTIME}, + setting, + settings::Setting, + try_vr, +}; +use cppvtbl::{impl_vtables, HasVtable, VtableRef, WithVtables}; +use once_cell::sync::Lazy; +use tokio::task::LocalSet; +use tracing::info; +use valve_pm::{StationCommand, StationControl, StationState}; + +use crate::openvr::{ + EVRInitError, IServerTrackedDeviceProvider, IServerTrackedDeviceProviderVtable, + IServerTrackedDeviceProvider_Version, IVRDriverContextVtable, +}; + +// (name ":" "BS2" ":" "0"/"1") ** "," +const BASE_STATIONS: Setting = setting!("driver_lighthouse", "PowerManagedBaseStations2"); +// 0 - disabled +// 1 - sleep +// 2 - standby +const POWER_MANAGEMENT: Setting = setting!("steamvr", "basestationPowerManagement"); + +#[impl_vtables(IServerTrackedDeviceProvider)] +pub struct ServerTrackedProvider { + real: &'static VtableRef, + stations: Mutex>, + standby_state: Mutex, +} +impl IServerTrackedDeviceProvider for ServerTrackedProvider { + fn Init( + &self, + pDriverContext: *const cppvtbl::VtableRef, + ) -> EVRInitError { + let _ = try_init_driver_context(unsafe { &*pDriverContext }); + let context = DRIVER_CONTEXT.get().expect("context just initialized"); + + let power_management = POWER_MANAGEMENT.get(); + *self.standby_state.lock().expect("lock") = match power_management { + 0 => StationState::Unknown, + 2 => StationState::Standby, + _ => StationState::Sleeping, + }; + + if *self.standby_state.lock().expect("lock") != StationState::Unknown { + let _runtime = TOKIO_RUNTIME.enter(); + let stations = BASE_STATIONS.get(); + let stations: Vec<_> = stations + .split(",") + .filter(|s| !s.is_empty()) + .filter_map(|line| { + let mut parts = line.split(":"); + let name = parts.next()?; + let _bs2 = parts.next()?; + let enabled = parts.next()?; + + if enabled == "1" { + Some(name.to_owned()) + } else { + None + } + }) + .map(|name| StationControl::new(name.to_owned(), StationState::On)) + .collect(); + info!("enabled power management for {} stations", stations.len()); + self.stations.lock().expect("lock").extend(stations); + }; + + self.real.Init( + VtableRef::into_raw(HasVtable::::get(&context)) as *const _, + ) + } + + fn Cleanup(&self) { + self.real.Cleanup(); + info!("disconnecting from base stations"); + let _runtime = TOKIO_RUNTIME.enter(); + let localset = LocalSet::new(); + for station in self.stations.lock().expect("lock").drain(..) { + localset.spawn_local(station.finish()); + } + TOKIO_RUNTIME.block_on(localset); + } + + fn GetInterfaceVersions(&self) -> *const *const c_char { + self.real.GetInterfaceVersions() + } + + fn RunFrame(&self) { + self.real.RunFrame() + } + + fn ShouldBlockStandbyMode(&self) -> bool { + false + } + + fn EnterStandby(&self) { + self.real.EnterStandby(); + info!("making station standby"); + for station in self.stations.lock().expect("lock").iter_mut() { + station.send(StationCommand::SetState( + *self.standby_state.lock().expect("lock"), + )) + } + } + + fn LeaveStandby(&self) { + self.real.LeaveStandby(); + info!("waking up base stations"); + for station in self.stations.lock().expect("lock").iter_mut() { + station.send(StationCommand::SetState(StationState::On)) + } + } +} + +pub static SERVER_TRACKED_DEVICE_PROVIDER: Lazy> = + Lazy::new(|| { + info!("intializing server tracker provider"); + let real = unsafe { + let factory = get_hmd_driver_factory().expect("factory should exist"); + try_vr!(factory(IServerTrackedDeviceProvider_Version)) + .expect("failed to obtain tracked device provider from factory") + }; + + WithVtables::new(ServerTrackedProvider { + real: unsafe { VtableRef::from_raw(real as *const _) }, + stations: Mutex::new(vec![]), + standby_state: Mutex::new(StationState::Unknown), + }) + }); diff --git a/bin/driver-proxy/src/factory.rs b/bin/driver-proxy/src/factory.rs index f099979..09ae5e9 100644 --- a/bin/driver-proxy/src/factory.rs +++ b/bin/driver-proxy/src/factory.rs @@ -4,17 +4,15 @@ use std::{ ptr::null, }; -use crate::{Error, Result}; +use crate::{server_tracked_provider::SERVER_TRACKED_DEVICE_PROVIDER, Error, Result}; use cppvtbl::{HasVtable, VtableRef}; use libloading::{Library, Symbol}; -use once_cell::sync::OnceCell; +use once_cell::sync::{Lazy, OnceCell}; +use tokio::runtime::Runtime; use tracing::info; -use crate::{ - openvr::{ - EVRInitError, IServerTrackedDeviceProviderVtable, IServerTrackedDeviceProvider_Version, - }, - server_tracked_provider::get_server_tracked_provider, +use crate::openvr::{ + EVRInitError, IServerTrackedDeviceProviderVtable, IServerTrackedDeviceProvider_Version, }; pub type HmdDriverFactory = @@ -33,6 +31,9 @@ pub fn get_hmd_driver_factory() -> Result<&'static Symbol<'static, HmdDriverFact }) } +pub static TOKIO_RUNTIME: Lazy = + Lazy::new(|| Runtime::new().expect("tokio init should not fail")); + fn HmdDriverFactory_impl(iface: *const c_char) -> Result<*const c_void> { // May be already installed if tracing_subscriber::fmt().without_time().try_init().is_ok() { @@ -44,10 +45,9 @@ fn HmdDriverFactory_impl(iface: *const c_char) -> Result<*const c_void> { info!("requested interface: {ifacen:?}"); if ifacen == unsafe { CStr::from_ptr(IServerTrackedDeviceProvider_Version) } { - let provider = get_server_tracked_provider()?; Ok( VtableRef::into_raw(HasVtable::::get( - &provider, + &SERVER_TRACKED_DEVICE_PROVIDER, )) as *const _ as *const c_void, ) } else { diff --git a/bin/driver-proxy/src/lib.rs b/bin/driver-proxy/src/lib.rs index 2810b2f..40e05a1 100644 --- a/bin/driver-proxy/src/lib.rs +++ b/bin/driver-proxy/src/lib.rs @@ -1,17 +1,20 @@ -#![feature(never_type, try_blocks)] +#![feature(never_type, try_blocks, thread_local)] #![allow(non_snake_case)] #[macro_use] extern crate openvr; -mod driver_context; -mod driver_host; +/// Wrappers for things, returned from original driver +mod driver; +pub use driver::{camera, hmd, server_tracked_provider}; + +/// Wrappers for things, passed from vrserver to original driver +mod server; +pub use server::{driver_context, driver_host}; + #[macro_use] mod error; -mod camera; mod factory; -mod hmd; -mod server_tracked_provider; #[macro_use] mod settings; mod log; diff --git a/bin/driver-proxy/src/driver_context.rs b/bin/driver-proxy/src/server/driver_context.rs similarity index 62% rename from bin/driver-proxy/src/driver_context.rs rename to bin/driver-proxy/src/server/driver_context.rs index f5f8918..1a65aad 100644 --- a/bin/driver-proxy/src/driver_context.rs +++ b/bin/driver-proxy/src/server/driver_context.rs @@ -1,13 +1,9 @@ use std::{ ffi::{c_void, CStr}, os::raw::c_char, - ptr::null_mut, }; -use crate::{ - driver_host::get_driver_host, openvr::IVRServerDriverHostVtable, try_vr, vr_result, Error, - Result, -}; +use crate::{driver_host::DRIVER_HOST, openvr::IVRServerDriverHostVtable, try_vr, Result}; use cppvtbl::{impl_vtables, HasVtable, VtableRef, WithVtables}; use once_cell::sync::OnceCell; use tracing::info; @@ -36,13 +32,8 @@ impl IVRDriverContext for DriverContext { let name = unsafe { CStr::from_ptr(pchInterfaceVersion) }; info!("get generic interface {name:?}"); if name == unsafe { CStr::from_ptr(IVRServerDriverHost_Version) } { - vr_result!( - result, - get_driver_host().map(|host| { - VtableRef::into_raw(HasVtable::::get(host)) as *mut _ - }), - null_mut() - ) + VtableRef::into_raw(HasVtable::::get(&*DRIVER_HOST)) + as *mut _ } else { self.real.GetGenericInterface(pchInterfaceVersion, result) } @@ -53,17 +44,15 @@ impl IVRDriverContext for DriverContext { } } -static DRIVER_CONTEXT: OnceCell> = OnceCell::new(); -pub fn try_init_driver_context(real: &'static VtableRef) -> Result<(), ()> { +pub static DRIVER_CONTEXT: OnceCell> = OnceCell::new(); + +pub fn try_init_driver_context(real: &'static VtableRef) { if DRIVER_CONTEXT.get().is_some() { - return Ok(()); + return; } - let context = WithVtables::new(DriverContext { real }); - DRIVER_CONTEXT.set(context).map_err(|_| ()) -} - -pub fn get_driver_context() -> Result<&'static WithVtables> { + let new_ctx = WithVtables::new(DriverContext { real }); DRIVER_CONTEXT - .get() - .ok_or_else(|| Error::Internal("driver context is not initialized yet")) + .set(new_ctx) + .map_err(|_| ()) + .expect("context is not set"); } diff --git a/bin/driver-proxy/src/driver_host.rs b/bin/driver-proxy/src/server/driver_host.rs similarity index 87% rename from bin/driver-proxy/src/driver_host.rs rename to bin/driver-proxy/src/server/driver_host.rs index b9f0ae4..107fcb2 100644 --- a/bin/driver-proxy/src/driver_host.rs +++ b/bin/driver-proxy/src/server/driver_host.rs @@ -1,14 +1,16 @@ use cppvtbl::{impl_vtables, HasVtable, VtableRef, WithVtables}; use lens_client::start_lens_server; -use once_cell::sync::OnceCell; +use once_cell::sync::Lazy; use std::cell::RefCell; use std::ffi::CStr; use std::os::raw::c_char; use std::rc::Rc; use tracing::{error, info}; +use valve_pm::{StationCommand, StationControl, StationState}; use vive_hid::{SteamDevice, ViveDevice}; -use crate::driver_context::get_driver_context; +use crate::driver_context::DRIVER_CONTEXT; +use crate::factory::TOKIO_RUNTIME; use crate::hmd::HmdDriver; use crate::openvr::{ Compositor_FrameTiming, DriverPose_t, ETrackedDeviceClass, EVREventType, HmdMatrix34_t, @@ -136,7 +138,11 @@ impl IVRServerDriverHost for DriverHost { } fn PollNextEvent(&self, pEvent: *mut VREvent_t, uncbVREvent: u32) -> bool { - self.real.PollNextEvent(pEvent, uncbVREvent) + let id = std::thread::current().id(); + info!("poll event start from {id:?}"); + let r = self.real.PollNextEvent(pEvent, uncbVREvent); + info!("poll event finish"); + r } fn GetRawTrackedDevicePoses( @@ -197,15 +203,15 @@ impl IVRServerDriverHost for DriverHost { } } -static DRIVER_HOST: OnceCell> = OnceCell::new(); - -pub fn get_driver_host() -> Result<&'static WithVtables> { - DRIVER_HOST.get_or_try_init(|| { - let context = get_driver_context()?; - let real = unsafe { - &*(context.get_generic_interface(IVRServerDriverHost_Version)? as *const _ - as *const VtableRef) - }; - Ok(WithVtables::new(DriverHost { real })) - }) -} +pub static DRIVER_HOST: Lazy> = Lazy::new(|| { + let context = DRIVER_CONTEXT + .get() + .expect("driver context should be initialized at this point"); + let real = unsafe { + &*(context + .get_generic_interface(IVRServerDriverHost_Version) + .expect("missing server driver host") as *const _ + as *const VtableRef) + }; + WithVtables::new(DriverHost { real }) +}); diff --git a/bin/driver-proxy/src/server/mod.rs b/bin/driver-proxy/src/server/mod.rs new file mode 100644 index 0000000..9859f55 --- /dev/null +++ b/bin/driver-proxy/src/server/mod.rs @@ -0,0 +1,2 @@ +pub mod driver_context; +pub mod driver_host; diff --git a/bin/driver-proxy/src/server_tracked_provider.rs b/bin/driver-proxy/src/server_tracked_provider.rs deleted file mode 100644 index 177d410..0000000 --- a/bin/driver-proxy/src/server_tracked_provider.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::os::raw::c_char; - -use crate::{ - driver_context::{get_driver_context, try_init_driver_context}, - factory::get_hmd_driver_factory, - Result, -}; -use cppvtbl::{impl_vtables, HasVtable, VtableRef, WithVtables}; -use once_cell::sync::OnceCell; -use tracing::info; - -use crate::openvr::{ - EVRInitError, IServerTrackedDeviceProvider, IServerTrackedDeviceProviderVtable, - IServerTrackedDeviceProvider_Version, IVRDriverContextVtable, -}; - -#[impl_vtables(IServerTrackedDeviceProvider)] -pub struct ServerTrackedProvider { - real: &'static VtableRef, -} -impl IServerTrackedDeviceProvider for ServerTrackedProvider { - fn Init( - &self, - pDriverContext: *const cppvtbl::VtableRef, - ) -> EVRInitError { - let _ = try_init_driver_context(unsafe { &*pDriverContext }); - let context = get_driver_context().expect("context just initialized"); - self.real.Init( - VtableRef::into_raw(HasVtable::::get(context)) as *const _, - ) - } - - fn Cleanup(&self) { - self.real.Cleanup() - } - - fn GetInterfaceVersions(&self) -> *const *const c_char { - self.real.GetInterfaceVersions() - } - - fn RunFrame(&self) { - self.real.RunFrame() - } - - fn ShouldBlockStandbyMode(&self) -> bool { - self.real.ShouldBlockStandbyMode() - } - - fn EnterStandby(&self) { - self.real.EnterStandby() - } - - fn LeaveStandby(&self) { - self.real.LeaveStandby() - } -} - -static SERVER_TRACKED_DEVICE_PROVIDER: OnceCell> = - OnceCell::new(); -pub fn get_server_tracked_provider() -> Result<&'static WithVtables> { - SERVER_TRACKED_DEVICE_PROVIDER.get_or_try_init(|| { - info!("intializing server tracker provider"); - let real = unsafe { - let factory = get_hmd_driver_factory()?; - try_vr!(factory(IServerTrackedDeviceProvider_Version))? - }; - Ok(WithVtables::new(ServerTrackedProvider { - real: unsafe { VtableRef::from_raw(real as *const _) }, - })) as Result<_> - }) -} diff --git a/bin/driver-proxy/src/settings.rs b/bin/driver-proxy/src/settings.rs index d64d2b7..f11b863 100644 --- a/bin/driver-proxy/src/settings.rs +++ b/bin/driver-proxy/src/settings.rs @@ -1,12 +1,13 @@ +use std::ffi::CString; use std::{marker::PhantomData, os::raw::c_char}; use cppvtbl::VtableRef; -use once_cell::sync::OnceCell; +use once_cell::sync::Lazy; use tracing::{error, instrument}; -use crate::driver_context::get_driver_context; +use crate::driver_context::DRIVER_CONTEXT; use crate::openvr::{EVRSettingsError, IVRSettings, IVRSettingsVtable, IVRSettings_Version}; -use crate::Result; +use crate::{Error, Result}; #[derive(Debug)] pub struct Setting(*const c_char, *const c_char, PhantomData); @@ -22,9 +23,8 @@ macro_rules! impl_setting { #[instrument] pub fn get(&self) -> $ty { let err: Result<()> = try { - let settings = get_settings()?; let mut err = EVRSettingsError::VRSettingsError_None; - return settings.$get_meth(self.0, self.1, &mut err); + return SETTINGS.$get_meth(self.0, self.1, &mut err); }; error!("failed: {}", err.err().unwrap()); $default @@ -32,9 +32,8 @@ macro_rules! impl_setting { #[instrument] pub fn set(&self, value: $ty) { let err: Result<()> = try { - let settings = get_settings()?; let mut err = EVRSettingsError::VRSettingsError_None; - settings.$set_meth(self.0, self.1, value, &mut err); + SETTINGS.$set_meth(self.0, self.1, value, &mut err); return; }; error!("failed: {}", err.err().unwrap()); @@ -45,6 +44,45 @@ macro_rules! impl_setting { impl_setting!(i32, GetInt32, SetInt32, 0); impl_setting!(bool, GetBool, SetBool, false); +const STRING_SIZE: usize = 65535; +impl Setting { + #[instrument] + pub fn get(&self) -> String { + let err: Result<()> = try { + let mut err = EVRSettingsError::VRSettingsError_None; + let mut buf = vec![0u8; STRING_SIZE]; + SETTINGS.GetString( + self.0, + self.1, + buf.as_mut_ptr().cast(), + STRING_SIZE as u32, + &mut err, + ); + + if err == EVRSettingsError::VRSettingsError_None { + buf.truncate(buf.iter().position(|&c| c == 0).unwrap_or(buf.len())); + + return String::from_utf8(buf) + .map_err(|_| Error::Internal("setting value is not utf-8"))?; + }; + Err(Error::Internal("failed to get string"))?; + }; + error!("failed: {}", err.err().unwrap()); + "".to_owned() + } + #[instrument] + pub fn set(&self, value: String) { + let err: Result<()> = try { + let cstring = + CString::new(value).map_err(|_| Error::Internal("setting value contains \\0"))?; + let mut err = EVRSettingsError::VRSettingsError_None; + SETTINGS.SetString(self.0, self.1, cstring.as_ptr(), &mut err); + return; + }; + error!("failed: {}", err.err().unwrap()); + } +} + #[macro_export] macro_rules! setting { ($section:expr, $name:expr) => { @@ -55,11 +93,12 @@ macro_rules! setting { }; } -static SETTINGS: OnceCell<&'static VtableRef> = OnceCell::new(); -pub fn get_settings() -> Result<&'static &'static VtableRef> { - SETTINGS.get_or_try_init(|| { - let ctx = get_driver_context()?; - let raw = ctx.get_generic_interface(IVRSettings_Version)?; - Ok(unsafe { VtableRef::from_raw(raw as *const VtableRef) }) - }) -} +pub static SETTINGS: Lazy<&'static VtableRef> = Lazy::new(|| { + let ctx = DRIVER_CONTEXT + .get() + .expect("context should be initialized at this point"); + let raw = ctx + .get_generic_interface(IVRSettings_Version) + .expect("there should be settings interface"); + unsafe { VtableRef::from_raw(raw as *const VtableRef) } +}); diff --git a/crates/valve-pm/Cargo.toml b/crates/valve-pm/Cargo.toml new file mode 100644 index 0000000..47176e1 --- /dev/null +++ b/crates/valve-pm/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "valve-pm" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# 0.7.3 used, because this is last sync version of this library +btleplug = "0.10.0" +# Same as used by old version of btleplug +uuid = "1.1.2" + +ctrlc = "3.2.3" +once_cell = "1.14.0" +thiserror = "1.0.33" +tracing = "0.1.36" +tokio = { version = "1.21.0", features = ["macros"] } +futures-util = "0.3.24" + +[dev-dependencies] +tracing-subscriber = "0.3.15" diff --git a/crates/valve-pm/src/lib.rs b/crates/valve-pm/src/lib.rs new file mode 100644 index 0000000..82bc042 --- /dev/null +++ b/crates/valve-pm/src/lib.rs @@ -0,0 +1,228 @@ +#![feature(try_blocks, let_else)] + +use btleplug::{ + api::{Central, Manager as _, Peripheral, ScanFilter, WriteType}, + platform::Manager, +}; +use futures_util::StreamExt; +use once_cell::sync::Lazy; +use std::{result, str::FromStr, time::Duration}; +use tokio::{select, sync::mpsc, time::sleep}; +use tracing::{error, info, warn, Instrument}; +use uuid::Uuid; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("bluetooth: {0}")] + Bt(#[from] btleplug::Error), + #[error("no adapter found")] + NoAdapterFound, + #[error("characteristic not found")] + CharacteristicNotFound, +} + +type Result = result::Result; + +const MODE_CHARACTERISTIC_ID: Lazy = + Lazy::new(|| Uuid::from_str("00001525-1212-efde-1523-785feabcd124").expect("uuid is valid")); + +#[allow(dead_code)] +const HTC_MAC_PREFIX: [u8; 3] = [0x74, 0xf6, 0x1c]; + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[repr(u8)] +pub enum StationState { + Sleeping = 0x00, + On = 0x01, + Standby = 0x02, + Unknown = 0xff, +} +impl StationState { + fn from_id(id: u8) -> Self { + match id { + 0x00 => Self::Sleeping, + 0x01 | 0x08 | 0x09 | 0x0a | 0x0b => Self::On, + 0x02 => Self::Standby, + _ => { + warn!("unknown status: 0x{id:02x}"); + Self::Unknown + } + } + } +} + +pub enum StationCommand { + SetState(StationState), +} + +pub struct StationControl { + handle: Option>, + ctx: Option>, +} +impl StationControl { + #[tracing::instrument(name = "station_control")] + pub fn new(station_sn: String, initial_state: StationState) -> Self { + let (ctx, mut crx) = mpsc::unbounded_channel(); + let handle = tokio::task::spawn( + async move { + let manager = match Manager::new().await { + Ok(manager) => manager, + Err(err) => { + error!("failed to create station manager: {err}"); + return; + } + }; + let adapters = match manager.adapters().await { + Ok(adapters) => adapters, + Err(err) => { + error!("failed to enumerate adapters: {err}"); + return; + } + }; + if adapters.is_empty() { + error!("no available bluetooth adapters"); + return; + } + + let adapter = adapters + .iter() + // Prefer HTC adapter, which is already embedded in link box + // .find(|a| { + // let addr = if let Ok(addr) = a.name() { + // addr + // } else { + // return false; + // }; + // !addr.address.starts_with(&HTC_MAC_PREFIX) + // }) + // TODO: Ability to select adapter? + // .or_else(|| adapters.first()) + .next() + .expect("len >= 1") + .clone(); + + info!( + "using adapter: {}", + adapter + .adapter_info() + .await + .unwrap_or_else(|_| "".to_owned()) + ); + + 'rescan: loop { + let res: Result<()> = try { + if let Err(e) = adapter.start_scan(ScanFilter::default()).await { + warn!("failed to start scan: {e}"); + } + + let peripherals = adapter.peripherals().await?; + + for peripheral in peripherals { + let props = match peripheral.properties().await { + Ok(props) => props, + Err(err) => { + warn!("failed to get peripheral properties: {err}"); + continue; + } + }; + let name = props.and_then(|p| p.local_name); + if name.as_ref() == Some(&station_sn) { + info!("station found"); + } else { + continue; + } + if !peripheral.is_connected().await? { + info!("connecting"); + peripheral.connect().await?; + } + if peripheral.characteristics().is_empty() { + info!("discovering characteristics"); + peripheral.discover_services().await?; + } + + let characteristics = peripheral + .characteristics(); + let characteristic = characteristics + .iter() + .find(|c| c.uuid == *MODE_CHARACTERISTIC_ID) + .ok_or(Error::CharacteristicNotFound)?; + + if let Err(e) = peripheral.write(&characteristic, &[initial_state as u8], WriteType::WithoutResponse).await { + error!("failed to set initial state: {e}"); + } + + peripheral.subscribe(characteristic).await?; + + let mut notifications = peripheral.notifications().await?; + info!("waiting for commands"); + loop { + select! { + notification = notifications.next() => { + let Some(notification) = notification else { + warn!("device was disconnected"); + continue 'rescan; + }; + if notification.uuid == *MODE_CHARACTERISTIC_ID { + let state = if notification.value.len() == 1 { + StationState::from_id(notification.value[0]) + } else { + StationState::Unknown + }; + info!("station state changed to {:?}", state); + } + } + command = crx.recv() => { + let Some(command) = command else { + warn!("command stream finished, moving device to sleep"); + if let Err(e) = peripheral.write(&characteristic, &[StationState::Sleeping as u8], WriteType::WithoutResponse).await { + error!("failed to make device sleep: {e}"); + } + if let Err(e) = peripheral.disconnect().await { + error!("failed to disconnect: {e}"); + } + break 'rescan; + }; + match command { + StationCommand::SetState(state) => { + info!("changing station state to {state:?}"); + if let Err(e) = peripheral.write(&characteristic, &[state as u8], WriteType::WithoutResponse).await { + error!("failed to write station state: {e}"); + } + }, + } + } + } + } + } + }; + if let Err(e) = res { + warn!("communication failed: {e}"); + } + sleep(Duration::from_secs(5)).await; + } + } + .in_current_span(), + ); + Self { + handle: Some(handle), + ctx: Some(ctx), + } + } + pub fn send(&mut self, command: StationCommand) { + self.ctx + .as_mut() + .expect("connection is not finished") + .send(command) + .ok() + .expect("task can't end earlier") + } + pub async fn finish(mut self) { + drop(self.ctx.take().expect("finish can only be called once")); + + self.handle + .take() + .expect("finish can only be called once") + .await + .expect("task should not fail"); + } +} diff --git a/crates/vive-hid/Cargo.toml b/crates/vive-hid/Cargo.toml index 2cb8550..072bf40 100644 --- a/crates/vive-hid/Cargo.toml +++ b/crates/vive-hid/Cargo.toml @@ -14,3 +14,5 @@ thiserror = "1.0.30" flate2 = "1.0.22" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" +tracing = "0.1.36" +tracing-subscriber = "0.3.15" diff --git a/crates/vive-hid/src/lib.rs b/crates/vive-hid/src/lib.rs index d2d3bab..a2a0ac8 100644 --- a/crates/vive-hid/src/lib.rs +++ b/crates/vive-hid/src/lib.rs @@ -5,6 +5,7 @@ use hidapi::{HidApi, HidDevice, HidError}; use once_cell::sync::OnceCell; use serde::Deserialize; use serde_json::Value; +use tracing::error; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -214,9 +215,14 @@ impl ViveDevice { let mut data = [0u8; 64]; self.0.read(&mut data)?; if data[0] != id { + error!("expected {id} but got {}\n{:02x?}", data[0], data); return Err(Error::ProtocolError("wrong report id")); } if &data[1..1 + strip_prefix.len()] != strip_prefix { + error!( + "expected {strip_prefix:x?}, got {:x?}", + &data[1..1 + strip_prefix.len()] + ); return Err(Error::ProtocolError("wrong prefix")); } let size = data[1 + strip_prefix.len()] as usize; @@ -239,7 +245,7 @@ impl ViveDevice { let mut out = [0u8; 62]; let size = self.read(0x02, &[], &mut out)?; Ok(std::str::from_utf8(&out[..size]) - .map_err(|_| Error::ProtocolError("devsn is not a string"))? + .map_err(|_| Error::ProtocolError("ipd is not a string"))? .to_string()) } pub fn read_config(&self) -> Result { diff --git a/dist-proxy/install.sh b/dist-proxy/install.sh index 6fccaa2..0d82e48 100755 --- a/dist-proxy/install.sh +++ b/dist-proxy/install.sh @@ -40,7 +40,7 @@ else fi echo "= Patching real driver" -sewer -v --backup $LIGHTHOUSE_DRIVER/driver_lighthouse_real.so.bak $LIGHTHOUSE_DRIVER/driver_lighthouse_real.so patch-file --partial driver_lighthouse_real.sew || true +sewer -v --backup $LIGHTHOUSE_DRIVER/driver_lighthouse_real.so.bak $LIGHTHOUSE_DRIVER/driver_lighthouse_real.so patch-file --partial $SCRIPTPATH/driver_lighthouse_real.sew || true echo "= Overriding current driver" rsync -a $SCRIPTPATH/driver_lighthouse.so $LIGHTHOUSE_DRIVER/driver_lighthouse.so diff --git a/flake.lock b/flake.lock index 11fbc6b..6cfbdd9 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ ] }, "locked": { - "lastModified": 1656730247, - "narHash": "sha256-UTQm1xRDBxbwIJ5bKIj+PNHsi0YPplvWjJLG5KPt0KU=", + "lastModified": 1662260299, + "narHash": "sha256-FYJk/Pn+VuSyl5Q3KXwTmOD7hprlv3CZPIRMGGT61IM=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "be0b8a7cbf95d43f23ef0bfa781d644a43c75396", + "rev": "fe73170ff8b29c4230c26b85e82c25c73c35481d", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a1aa29a..9b157e5 100644 --- a/flake.nix +++ b/flake.nix @@ -28,7 +28,7 @@ (final: prev: let rust = (final.buildPackages.rustChannelOf { - date = "2022-04-08"; + date = "2022-09-03"; channel = "nightly"; }).default.override { extensions = [ "rust-src" ]; @@ -60,7 +60,7 @@ let rust = (final.buildPackages.rustChannelOf { - date = "2022-04-08"; + date = "2022-09-03"; channel = "nightly"; }).default.override { targets = [ "x86_64-pc-windows-gnu" ]; @@ -116,7 +116,7 @@ inherit version src cargoLock; pname = "vivepro2-driver-proxy"; nativeBuildInputs = [ pkgconfig ]; - buildInputs = [ udev ]; + buildInputs = [ udev dbus.dev ]; }; sewer = with pkgs.pkgsStatic; rustPlatform.buildRustPackage { @@ -158,8 +158,13 @@ default = pkgs.mkShell { nativeBuildInputs = with pkgs; [ rustDev + cargo-edit pkg-config + lld + dbus.dev + udev ]; + LD_LIBRARY_PATH = "${pkgs.dbus.lib}/lib"; }; }; devShell = devShells.default;