feat: implement pro-controller mode
Some checks failed
Code quality / check (pull_request) Failing after 21s
Some checks failed
Code quality / check (pull_request) Failing after 21s
This commit is contained in:
parent
753cb59fe6
commit
2fa8779d90
9 changed files with 903 additions and 295 deletions
161
Cargo.lock
generated
161
Cargo.lock
generated
|
@ -2,6 +2,18 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
@ -77,6 +89,12 @@ version = "0.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitfield"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -109,9 +127,9 @@ checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.4.3"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
|
@ -136,7 +154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bare-metal",
|
"bare-metal",
|
||||||
"bitfield",
|
"bitfield 0.13.2",
|
||||||
"embedded-hal 0.2.7",
|
"embedded-hal 0.2.7",
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
@ -309,7 +327,8 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-embedded-hal"
|
name = "embassy-embedded-hal"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt",
|
"defmt",
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
|
@ -325,7 +344,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-executor"
|
name = "embassy-executor"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
@ -338,7 +358,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-executor-macros"
|
name = "embassy-executor-macros"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -349,13 +370,15 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-futures"
|
name = "embassy-futures"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt",
|
"defmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-hal-internal"
|
name = "embassy-hal-internal"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
@ -366,10 +389,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-net-driver"
|
name = "embassy-net-driver"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-net-driver-channel"
|
name = "embassy-net-driver-channel"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-net-driver",
|
"embassy-net-driver",
|
||||||
|
@ -378,7 +403,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-rp"
|
name = "embassy-rp"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-polyfill",
|
"atomic-polyfill",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -403,7 +429,6 @@ dependencies = [
|
||||||
"embedded-storage",
|
"embedded-storage",
|
||||||
"embedded-storage-async",
|
"embedded-storage-async",
|
||||||
"fixed",
|
"fixed",
|
||||||
"futures",
|
|
||||||
"nb 1.1.0",
|
"nb 1.1.0",
|
||||||
"pio",
|
"pio",
|
||||||
"pio-proc",
|
"pio-proc",
|
||||||
|
@ -414,7 +439,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-sync"
|
name = "embassy-sync"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
@ -426,7 +452,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time"
|
name = "embassy-time"
|
||||||
version = "0.3.0"
|
version = "0.3.2"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
@ -444,6 +471,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time-driver"
|
name = "embassy-time-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
]
|
]
|
||||||
|
@ -451,10 +479,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time-queue-driver"
|
name = "embassy-time-queue-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb"
|
name = "embassy-usb"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt",
|
"defmt",
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
|
@ -469,6 +499,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb-driver"
|
name = "embassy-usb-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt",
|
"defmt",
|
||||||
]
|
]
|
||||||
|
@ -630,59 +661,12 @@ version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-channel"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-io"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-macro"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.52",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-sink"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -696,8 +680,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-macro",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
@ -733,6 +715,15 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
|
@ -768,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.14.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1453,15 +1444,19 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usb-device"
|
name = "usb-device"
|
||||||
version = "0.2.9"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6"
|
||||||
|
dependencies = [
|
||||||
|
"heapless",
|
||||||
|
"portable-atomic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usbd-hid"
|
name = "usbd-hid"
|
||||||
version = "0.6.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "975bd411f4a939986751ea09992a24fa47c4d25c6ed108d04b4c2999a4fd0132"
|
checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"ssmarshal",
|
"ssmarshal",
|
||||||
|
@ -1471,20 +1466,22 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usbd-hid-descriptors"
|
name = "usbd-hid-descriptors"
|
||||||
version = "0.1.2"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcbee8c6735e90894fba04770bc41e11fd3c5256018856e15dc4dd1e6c8a3dd1"
|
checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitfield",
|
"bitfield 0.14.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usbd-hid-macros"
|
name = "usbd-hid-macros"
|
||||||
version = "0.6.0"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "261079a9ada015fa1acac7cc73c98559f3a92585e15f508034beccf6a2ab75a2"
|
checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"hashbrown 0.13.2",
|
||||||
|
"log",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -1687,3 +1684,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tap",
|
"tap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.52",
|
||||||
|
]
|
||||||
|
|
39
Cargo.toml
39
Cargo.toml
|
@ -9,33 +9,33 @@ edition = "2021"
|
||||||
embassy-time = { version = "0.3.0", features = [
|
embassy-time = { version = "0.3.0", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
"defmt-timestamp-uptime",
|
"defmt-timestamp-uptime",
|
||||||
], path = "lib/embassy-rs/embassy-time" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
embassy-embedded-hal = { version = "0.1.0", features = [
|
embassy-embedded-hal = { version = "0.2.0", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
], path = "lib/embassy-rs/embassy-embedded-hal" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
embassy-sync = { version = "0.5.0", features = [
|
embassy-sync = { version = "0.6.0", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
], path = "lib/embassy-rs/embassy-sync" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
embassy-executor = { version = "0.5.0", features = [
|
embassy-executor = { version = "0.6.0", features = [
|
||||||
"task-arena-size-32768",
|
"task-arena-size-32768",
|
||||||
"arch-cortex-m",
|
"arch-cortex-m",
|
||||||
"executor-thread",
|
"executor-thread",
|
||||||
"executor-interrupt",
|
"executor-interrupt",
|
||||||
"defmt",
|
"defmt",
|
||||||
"integrated-timers",
|
"integrated-timers",
|
||||||
], path = "lib/embassy-rs/embassy-executor" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
embassy-rp = { version = "0.1.0", features = [
|
embassy-rp = { version = "0.2.0", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
"unstable-pac",
|
"unstable-pac",
|
||||||
"time-driver",
|
"time-driver",
|
||||||
"critical-section-impl",
|
"critical-section-impl",
|
||||||
], path = "lib/embassy-rs/embassy-rp" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
embassy-usb = { version = "0.1.0", features = [
|
embassy-usb = { version = "0.3.0", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
], path = "lib/embassy-rs/embassy-usb" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
embassy-futures = { version = "0.1.0", features = [
|
embassy-futures = { version = "0.1.0", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
], path = "lib/embassy-rs/embassy-futures" }
|
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
defmt-rtt = "0.4"
|
defmt-rtt = "0.4"
|
||||||
fixed = "1.23.1"
|
fixed = "1.23.1"
|
||||||
|
@ -48,7 +48,7 @@ libm = { version = "0.2.8" }
|
||||||
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
||||||
cortex-m-rt = "0.7.0"
|
cortex-m-rt = "0.7.0"
|
||||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||||
packed_struct = { version = "0.10.1", default_features = false }
|
packed_struct = { version = "0.10.1", default-features = false }
|
||||||
format_no_std = "1.0.2"
|
format_no_std = "1.0.2"
|
||||||
rand = { version = "0.8.5", default-features = false }
|
rand = { version = "0.8.5", default-features = false }
|
||||||
|
|
||||||
|
@ -79,14 +79,14 @@ overflow-checks = false
|
||||||
codegen-units = 8
|
codegen-units = 8
|
||||||
debug = false
|
debug = false
|
||||||
debug-assertions = false
|
debug-assertions = false
|
||||||
opt-level = 0
|
opt-level = 3
|
||||||
overflow-checks = false
|
overflow-checks = false
|
||||||
|
|
||||||
[profile.release.build-override]
|
[profile.release.build-override]
|
||||||
codegen-units = 8
|
codegen-units = 8
|
||||||
debug = false
|
debug = false
|
||||||
debug-assertions = false
|
debug-assertions = false
|
||||||
opt-level = 0
|
opt-level = 3
|
||||||
overflow-checks = false
|
overflow-checks = false
|
||||||
|
|
||||||
# cargo test
|
# cargo test
|
||||||
|
@ -106,12 +106,3 @@ debug-assertions = false
|
||||||
incremental = false
|
incremental = false
|
||||||
lto = 'fat'
|
lto = 'fat'
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
# [patch.crates-io]
|
|
||||||
# embassy-rp = { path = "lib/embassy-rs/embassy-rp" }
|
|
||||||
# embassy-time = { path = "lib/embassy-rs/embassy-time" }
|
|
||||||
# embassy-embedded-hal = { path = "lib/embassy-rs/embassy-embedded-hal" }
|
|
||||||
# embassy-usb = { path = "lib/embassy-rs/embassy-usb" }
|
|
||||||
# embassy-sync = { path = "lib/embassy-rs/embassy-sync" }
|
|
||||||
# embassy-executor = { path = "lib/embassy-rs/embassy-executor" }
|
|
||||||
# embassy-futures = { path = "lib/embassy-rs/embassy-futures" }
|
|
||||||
|
|
46
flake.lock
46
flake.lock
|
@ -35,24 +35,6 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils_2": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1705309234,
|
|
||||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"naersk": {
|
"naersk": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
@ -91,11 +73,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1706487304,
|
"lastModified": 1718428119,
|
||||||
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
|
"narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
|
"rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -116,15 +98,14 @@
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_2",
|
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710382258,
|
"lastModified": 1728700003,
|
||||||
"narHash": "sha256-2FW1q+o34VBweYQiEkRaSEkNMq3ecrn83VzETeGiVbY=",
|
"narHash": "sha256-Ox1pvEHxLK6lAdaKQW21Zvk65SPDag+cD8YA444R/og=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "8ce81e71ab04a7e906fae62da086d6ee5d6cfc21",
|
"rev": "fc1e58ebabe0cef4442eedea07556ff0c9eafcfe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -147,21 +128,6 @@
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"systems_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
|
@ -16,10 +16,6 @@ use packed_struct::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
gcc_hid::{
|
|
||||||
GcButtons1, GcButtons2, MUTEX_CONTROLLER_MODE, MUTEX_INPUT_CONSISTENCY_MODE,
|
|
||||||
SIGNAL_CHANGE_RUMBLE_STRENGTH,
|
|
||||||
},
|
|
||||||
helpers::{PackedFloat, ToPackedFloatArray, ToRegularArray, XyValuePair},
|
helpers::{PackedFloat, ToPackedFloatArray, ToRegularArray, XyValuePair},
|
||||||
input::{
|
input::{
|
||||||
read_ext_adc, Stick, StickAxis, FLOAT_ORIGIN, SPI_ACS_SHARED, SPI_CCS_SHARED, SPI_SHARED,
|
read_ext_adc, Stick, StickAxis, FLOAT_ORIGIN, SPI_ACS_SHARED, SPI_CCS_SHARED, SPI_SHARED,
|
||||||
|
@ -29,6 +25,10 @@ use crate::{
|
||||||
LinearizedCalibration, NotchCalibration, NotchStatus, CALIBRATION_ORDER,
|
LinearizedCalibration, NotchCalibration, NotchStatus, CALIBRATION_ORDER,
|
||||||
NOTCH_ADJUSTMENT_ORDER, NO_OF_ADJ_NOTCHES, NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES,
|
NOTCH_ADJUSTMENT_ORDER, NO_OF_ADJ_NOTCHES, NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES,
|
||||||
},
|
},
|
||||||
|
usb_comms::{
|
||||||
|
GcButtons1, GcButtons2, MUTEX_CONTROLLER_MODE, MUTEX_INPUT_CONSISTENCY_MODE,
|
||||||
|
SIGNAL_CHANGE_RUMBLE_STRENGTH,
|
||||||
|
},
|
||||||
ADDR_OFFSET, FLASH_SIZE,
|
ADDR_OFFSET, FLASH_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ use embassy_sync::{
|
||||||
};
|
};
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
|
|
||||||
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
|
use crate::{input::CHANNEL_GCC_STATE, usb_comms::GcState};
|
||||||
|
|
||||||
/// Whether we are currently calibrating the sticks. Updates are dispatched when the status changes.
|
/// Whether we are currently calibrating the sticks. Updates are dispatched when the status changes.
|
||||||
/// Initial status is assumed to be false.
|
/// Initial status is assumed to be false.
|
||||||
|
@ -81,7 +81,7 @@ const MAX_ANALOG_SCALER: u8 = 125;
|
||||||
/// a certain mode.
|
/// a certain mode.
|
||||||
#[derive(Default, Debug, Clone, Format)]
|
#[derive(Default, Debug, Clone, Format)]
|
||||||
pub struct OverrideGcReportInstruction {
|
pub struct OverrideGcReportInstruction {
|
||||||
pub report: GcReport,
|
pub report: GcState,
|
||||||
pub duration_ms: u64,
|
pub duration_ms: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,6 +566,7 @@ pub enum InputConsistencyMode {
|
||||||
PC = 3,
|
PC = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Not saved, but set upon plugging in the controller.
|
||||||
#[derive(Debug, Clone, Copy, Format, PrimitiveEnum_u8, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Format, PrimitiveEnum_u8, PartialEq, Eq)]
|
||||||
pub enum ControllerMode {
|
pub enum ControllerMode {
|
||||||
/// Advertise itself as a GCC adapter with 1 controller (itself) connected.
|
/// Advertise itself as a GCC adapter with 1 controller (itself) connected.
|
||||||
|
@ -591,8 +592,6 @@ pub struct ControllerConfig {
|
||||||
pub astick_config: StickConfig,
|
pub astick_config: StickConfig,
|
||||||
#[packed_field(size_bytes = "328")]
|
#[packed_field(size_bytes = "328")]
|
||||||
pub cstick_config: StickConfig,
|
pub cstick_config: StickConfig,
|
||||||
#[packed_field(size_bits = "8", ty = "enum")]
|
|
||||||
pub controller_mode: ControllerMode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ControllerConfig {
|
impl Default for ControllerConfig {
|
||||||
|
@ -603,7 +602,6 @@ impl Default for ControllerConfig {
|
||||||
astick_config: StickConfig::default(),
|
astick_config: StickConfig::default(),
|
||||||
rumble_strength: 9,
|
rumble_strength: 9,
|
||||||
cstick_config: StickConfig::default(),
|
cstick_config: StickConfig::default(),
|
||||||
controller_mode: ControllerMode::GcAdapter,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -651,6 +649,8 @@ impl ControllerConfig {
|
||||||
/// Trait for providing button presses, used in the calibration process.
|
/// Trait for providing button presses, used in the calibration process.
|
||||||
trait ButtonPressProvider {
|
trait ButtonPressProvider {
|
||||||
/// Wait for a single button press.
|
/// Wait for a single button press.
|
||||||
|
// TODO: remove allow once this is used somewhere
|
||||||
|
#[allow(dead_code)]
|
||||||
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons);
|
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons);
|
||||||
|
|
||||||
/// Wait for a single button release.
|
/// Wait for a single button release.
|
||||||
|
@ -684,7 +684,7 @@ trait ButtonPressProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: RawMutex, const I: usize, const J: usize, const K: usize> ButtonPressProvider
|
impl<'a, T: RawMutex, const I: usize, const J: usize, const K: usize> ButtonPressProvider
|
||||||
for Subscriber<'a, T, GcReport, I, J, K>
|
for Subscriber<'a, T, GcState, I, J, K>
|
||||||
{
|
{
|
||||||
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons) {
|
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons) {
|
||||||
loop {
|
loop {
|
||||||
|
@ -784,7 +784,7 @@ impl<'a, T: RawMutex, const I: usize, const J: usize, const K: usize> ButtonPres
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_awaitable_button_pressed(
|
pub fn is_awaitable_button_pressed(
|
||||||
report: &GcReport,
|
report: &GcState,
|
||||||
button_to_wait_for: &AwaitableButtons,
|
button_to_wait_for: &AwaitableButtons,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match button_to_wait_for {
|
match button_to_wait_for {
|
||||||
|
@ -1150,7 +1150,7 @@ async fn configuration_main_loop<
|
||||||
>(
|
>(
|
||||||
current_config: &ControllerConfig,
|
current_config: &ControllerConfig,
|
||||||
flash: &mut Flash<'static, FLASH, Async, FLASH_SIZE>,
|
flash: &mut Flash<'static, FLASH, Async, FLASH_SIZE>,
|
||||||
gcc_subscriber: &mut Subscriber<'a, M, GcReport, C, S, P>,
|
gcc_subscriber: &mut Subscriber<'a, M, GcState, C, S, P>,
|
||||||
) -> ControllerConfig {
|
) -> ControllerConfig {
|
||||||
let mut final_config = current_config.clone();
|
let mut final_config = current_config.clone();
|
||||||
let config_options = [
|
let config_options = [
|
||||||
|
@ -1208,7 +1208,7 @@ async fn configuration_main_loop<
|
||||||
// exit
|
// exit
|
||||||
0 => {
|
0 => {
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1236,7 +1236,7 @@ async fn configuration_main_loop<
|
||||||
// calibrate lstick
|
// calibrate lstick
|
||||||
1 => {
|
1 => {
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1265,7 +1265,7 @@ async fn configuration_main_loop<
|
||||||
// calibrate rstick
|
// calibrate rstick
|
||||||
2 => {
|
2 => {
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1324,7 +1324,7 @@ async fn configuration_main_loop<
|
||||||
.clamp(-ABS_MAX_SNAPBACK, ABS_MAX_SNAPBACK);
|
.clamp(-ABS_MAX_SNAPBACK, ABS_MAX_SNAPBACK);
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1410,7 +1410,7 @@ async fn configuration_main_loop<
|
||||||
.clamp(0, MAX_WAVESHAPING) as u8;
|
.clamp(0, MAX_WAVESHAPING) as u8;
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1496,7 +1496,7 @@ async fn configuration_main_loop<
|
||||||
.clamp(0, MAX_SMOOTHING) as u8;
|
.clamp(0, MAX_SMOOTHING) as u8;
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1571,7 +1571,7 @@ async fn configuration_main_loop<
|
||||||
.clamp(-1, MAX_CARDINAL_SNAP);
|
.clamp(-1, MAX_CARDINAL_SNAP);
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1627,7 +1627,7 @@ async fn configuration_main_loop<
|
||||||
as u8;
|
as u8;
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1675,7 +1675,7 @@ async fn configuration_main_loop<
|
||||||
SIGNAL_CHANGE_RUMBLE_STRENGTH.signal(*to_adjust);
|
SIGNAL_CHANGE_RUMBLE_STRENGTH.signal(*to_adjust);
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1711,7 +1711,7 @@ async fn configuration_main_loop<
|
||||||
};
|
};
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1745,7 +1745,7 @@ async fn configuration_main_loop<
|
||||||
// display waveshaping values on both sticks
|
// display waveshaping values on both sticks
|
||||||
38 => {
|
38 => {
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1771,7 +1771,7 @@ async fn configuration_main_loop<
|
||||||
// display stick smoothing values on both sticks
|
// display stick smoothing values on both sticks
|
||||||
39 => {
|
39 => {
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1797,7 +1797,7 @@ async fn configuration_main_loop<
|
||||||
// display snapback values on both sticks
|
// display snapback values on both sticks
|
||||||
40 => {
|
40 => {
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
@ -1854,11 +1854,6 @@ pub async fn config_task(mut flash: Flash<'static, FLASH, Async, FLASH_SIZE>) {
|
||||||
*m_input_consistency = Some(current_config.input_consistency_mode);
|
*m_input_consistency = Some(current_config.input_consistency_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
let mut m_is_procon = MUTEX_CONTROLLER_MODE.lock().await;
|
|
||||||
*m_is_procon = Some(current_config.controller_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
SIGNAL_CHANGE_RUMBLE_STRENGTH.signal(current_config.rumble_strength);
|
SIGNAL_CHANGE_RUMBLE_STRENGTH.signal(current_config.rumble_strength);
|
||||||
SIGNAL_CONFIG_CHANGE.signal(current_config.clone());
|
SIGNAL_CONFIG_CHANGE.signal(current_config.clone());
|
||||||
|
|
||||||
|
@ -1873,7 +1868,7 @@ pub async fn config_task(mut flash: Flash<'static, FLASH, Async, FLASH_SIZE>) {
|
||||||
info!("Entering config mode.");
|
info!("Entering config mode.");
|
||||||
|
|
||||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||||
report: GcReport {
|
report: GcState {
|
||||||
trigger_r: 255,
|
trigger_r: 255,
|
||||||
trigger_l: 255,
|
trigger_l: 255,
|
||||||
buttons_2: GcButtons2 {
|
buttons_2: GcButtons2 {
|
||||||
|
|
99
src/input.rs
99
src/input.rs
|
@ -1,7 +1,7 @@
|
||||||
use defmt::{debug, info, trace, Format};
|
use defmt::{debug, info, trace, Format};
|
||||||
use embassy_futures::yield_now;
|
use embassy_futures::yield_now;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
gpio::{AnyPin, Input, Output, Pin},
|
gpio::{Input, Output},
|
||||||
peripherals::SPI0,
|
peripherals::SPI0,
|
||||||
spi::{Blocking, Spi},
|
spi::{Blocking, Spi},
|
||||||
};
|
};
|
||||||
|
@ -16,19 +16,19 @@ use libm::{fmaxf, fminf};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
ControllerConfig, InputConsistencyMode, OverrideGcReportInstruction, OverrideStickState,
|
ControllerConfig, ControllerMode, InputConsistencyMode, OverrideGcReportInstruction,
|
||||||
SIGNAL_CONFIG_CHANGE, SIGNAL_IS_CALIBRATING, SIGNAL_OVERRIDE_GCC_STATE,
|
OverrideStickState, SIGNAL_CONFIG_CHANGE, SIGNAL_IS_CALIBRATING, SIGNAL_OVERRIDE_GCC_STATE,
|
||||||
SIGNAL_OVERRIDE_STICK_STATE,
|
SIGNAL_OVERRIDE_STICK_STATE,
|
||||||
},
|
},
|
||||||
filter::{run_waveshaping, FilterGains, KalmanState, WaveshapingValues, FILTER_GAINS},
|
filter::{run_waveshaping, FilterGains, KalmanState, WaveshapingValues, FILTER_GAINS},
|
||||||
gcc_hid::{GcReport, MUTEX_INPUT_CONSISTENCY_MODE},
|
|
||||||
helpers::XyValuePair,
|
helpers::XyValuePair,
|
||||||
input_filter::{DummyFilter, InputFilter},
|
input_filter::{DummyFilter, InputFilter},
|
||||||
stick::{linearize, notch_remap, StickParams},
|
stick::{linearize, notch_remap, StickParams},
|
||||||
|
usb_comms::{GcState, MUTEX_CONTROLLER_MODE, MUTEX_INPUT_CONSISTENCY_MODE},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Used to send the button state to the usb task and the calibration task
|
/// Used to send the button state to the usb task and the calibration task
|
||||||
pub static CHANNEL_GCC_STATE: PubSubChannel<CriticalSectionRawMutex, GcReport, 1, 4, 1> =
|
pub static CHANNEL_GCC_STATE: PubSubChannel<CriticalSectionRawMutex, GcState, 1, 4, 1> =
|
||||||
PubSubChannel::new();
|
PubSubChannel::new();
|
||||||
|
|
||||||
/// Used to send the stick state from the stick task to the main input task
|
/// Used to send the stick state from the stick task to the main input task
|
||||||
|
@ -36,10 +36,8 @@ static SIGNAL_STICK_STATE: Signal<CriticalSectionRawMutex, StickState> = Signal:
|
||||||
|
|
||||||
pub static SPI_SHARED: Mutex<ThreadModeRawMutex, Option<Spi<'static, SPI0, Blocking>>> =
|
pub static SPI_SHARED: Mutex<ThreadModeRawMutex, Option<Spi<'static, SPI0, Blocking>>> =
|
||||||
Mutex::new(None);
|
Mutex::new(None);
|
||||||
pub static SPI_ACS_SHARED: Mutex<ThreadModeRawMutex, Option<Output<'static, AnyPin>>> =
|
pub static SPI_ACS_SHARED: Mutex<ThreadModeRawMutex, Option<Output<'static>>> = Mutex::new(None);
|
||||||
Mutex::new(None);
|
pub static SPI_CCS_SHARED: Mutex<ThreadModeRawMutex, Option<Output<'static>>> = Mutex::new(None);
|
||||||
pub static SPI_CCS_SHARED: Mutex<ThreadModeRawMutex, Option<Output<'static, AnyPin>>> =
|
|
||||||
Mutex::new(None);
|
|
||||||
|
|
||||||
const STICK_HYST_VAL: f32 = 0.3;
|
const STICK_HYST_VAL: f32 = 0.3;
|
||||||
pub const FLOAT_ORIGIN: f32 = 127.5;
|
pub const FLOAT_ORIGIN: f32 = 127.5;
|
||||||
|
@ -84,18 +82,12 @@ pub enum StickAxis {
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[link_section = ".time_critical.read_ext_adc"]
|
#[link_section = ".time_critical.read_ext_adc"]
|
||||||
pub fn read_ext_adc<
|
pub fn read_ext_adc<'a, I: embassy_rp::spi::Instance, M: embassy_rp::spi::Mode>(
|
||||||
'a,
|
|
||||||
Acs: Pin,
|
|
||||||
Ccs: Pin,
|
|
||||||
I: embassy_rp::spi::Instance,
|
|
||||||
M: embassy_rp::spi::Mode,
|
|
||||||
>(
|
|
||||||
which_stick: Stick,
|
which_stick: Stick,
|
||||||
which_axis: StickAxis,
|
which_axis: StickAxis,
|
||||||
spi: &mut Spi<'a, I, M>,
|
spi: &mut Spi<'a, I, M>,
|
||||||
spi_acs: &mut Output<'a, Acs>,
|
spi_acs: &mut Output<'a>,
|
||||||
spi_ccs: &mut Output<'a, Ccs>,
|
spi_ccs: &mut Output<'a>,
|
||||||
) -> u16 {
|
) -> u16 {
|
||||||
let mut buf = [0b11010000; 3];
|
let mut buf = [0b11010000; 3];
|
||||||
|
|
||||||
|
@ -352,19 +344,19 @@ async fn update_stick_states(
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn update_button_states(
|
fn update_button_states(
|
||||||
gcc_state: &mut GcReport,
|
gcc_state: &mut GcState,
|
||||||
btn_a: &Input<'_, AnyPin>,
|
btn_a: &Input<'_>,
|
||||||
btn_b: &Input<'_, AnyPin>,
|
btn_b: &Input<'_>,
|
||||||
btn_x: &Input<'_, AnyPin>,
|
btn_x: &Input<'_>,
|
||||||
btn_y: &Input<'_, AnyPin>,
|
btn_y: &Input<'_>,
|
||||||
btn_start: &Input<'_, AnyPin>,
|
btn_start: &Input<'_>,
|
||||||
btn_l: &Input<'_, AnyPin>,
|
btn_l: &Input<'_>,
|
||||||
btn_r: &Input<'_, AnyPin>,
|
btn_r: &Input<'_>,
|
||||||
btn_z: &Input<'_, AnyPin>,
|
btn_z: &Input<'_>,
|
||||||
btn_dleft: &Input<'_, AnyPin>,
|
btn_dleft: &Input<'_>,
|
||||||
btn_dright: &Input<'_, AnyPin>,
|
btn_dright: &Input<'_>,
|
||||||
btn_dup: &Input<'_, AnyPin>,
|
btn_dup: &Input<'_>,
|
||||||
btn_ddown: &Input<'_, AnyPin>,
|
btn_ddown: &Input<'_>,
|
||||||
) {
|
) {
|
||||||
gcc_state.buttons_1.button_a = btn_a.is_low();
|
gcc_state.buttons_1.button_a = btn_a.is_low();
|
||||||
gcc_state.buttons_1.button_b = btn_b.is_low();
|
gcc_state.buttons_1.button_b = btn_b.is_low();
|
||||||
|
@ -393,7 +385,7 @@ pub async fn input_integrity_benchmark() {
|
||||||
loop {
|
loop {
|
||||||
SIGNAL_OVERRIDE_GCC_STATE.signal(OverrideGcReportInstruction {
|
SIGNAL_OVERRIDE_GCC_STATE.signal(OverrideGcReportInstruction {
|
||||||
report: {
|
report: {
|
||||||
let mut report = GcReport::default();
|
let mut report = GcState::default();
|
||||||
report.buttons_1.dpad_up = true;
|
report.buttons_1.dpad_up = true;
|
||||||
report
|
report
|
||||||
},
|
},
|
||||||
|
@ -409,18 +401,18 @@ pub async fn input_integrity_benchmark() {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn update_button_state_task(
|
pub async fn update_button_state_task(
|
||||||
btn_z: Input<'static, AnyPin>,
|
btn_z: Input<'static>,
|
||||||
btn_a: Input<'static, AnyPin>,
|
btn_a: Input<'static>,
|
||||||
btn_b: Input<'static, AnyPin>,
|
btn_b: Input<'static>,
|
||||||
btn_dright: Input<'static, AnyPin>,
|
btn_dright: Input<'static>,
|
||||||
btn_dup: Input<'static, AnyPin>,
|
btn_dup: Input<'static>,
|
||||||
btn_ddown: Input<'static, AnyPin>,
|
btn_ddown: Input<'static>,
|
||||||
btn_dleft: Input<'static, AnyPin>,
|
btn_dleft: Input<'static>,
|
||||||
btn_l: Input<'static, AnyPin>,
|
btn_l: Input<'static>,
|
||||||
btn_r: Input<'static, AnyPin>,
|
btn_r: Input<'static>,
|
||||||
btn_x: Input<'static, AnyPin>,
|
btn_x: Input<'static>,
|
||||||
btn_y: Input<'static, AnyPin>,
|
btn_y: Input<'static>,
|
||||||
btn_start: Input<'static, AnyPin>,
|
btn_start: Input<'static>,
|
||||||
) {
|
) {
|
||||||
// upon loop entry, we check for the reset combo once
|
// upon loop entry, we check for the reset combo once
|
||||||
if btn_a.is_low() && btn_x.is_low() && btn_y.is_low() {
|
if btn_a.is_low() && btn_x.is_low() && btn_y.is_low() {
|
||||||
|
@ -431,6 +423,15 @@ pub async fn update_button_state_task(
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut m = MUTEX_CONTROLLER_MODE.lock().await;
|
||||||
|
*m = if btn_start.is_low() {
|
||||||
|
Some(ControllerMode::Procon)
|
||||||
|
} else {
|
||||||
|
Some(ControllerMode::GcAdapter)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let input_consistency_mode = {
|
let input_consistency_mode = {
|
||||||
while MUTEX_INPUT_CONSISTENCY_MODE.lock().await.is_none() {
|
while MUTEX_INPUT_CONSISTENCY_MODE.lock().await.is_none() {
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
@ -438,9 +439,9 @@ pub async fn update_button_state_task(
|
||||||
MUTEX_INPUT_CONSISTENCY_MODE.lock().await.unwrap()
|
MUTEX_INPUT_CONSISTENCY_MODE.lock().await.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut previous_state = GcReport::default();
|
let mut previous_state = GcState::default();
|
||||||
|
|
||||||
let mut gcc_state = GcReport::default();
|
let mut gcc_state = GcState::default();
|
||||||
|
|
||||||
let gcc_publisher = CHANNEL_GCC_STATE.publisher().unwrap();
|
let gcc_publisher = CHANNEL_GCC_STATE.publisher().unwrap();
|
||||||
|
|
||||||
|
@ -546,8 +547,8 @@ pub async fn update_button_state_task(
|
||||||
#[link_section = ".time_critical.update_stick_states_task"]
|
#[link_section = ".time_critical.update_stick_states_task"]
|
||||||
pub async fn update_stick_states_task(
|
pub async fn update_stick_states_task(
|
||||||
spi: Spi<'static, SPI0, embassy_rp::spi::Blocking>,
|
spi: Spi<'static, SPI0, embassy_rp::spi::Blocking>,
|
||||||
spi_acs: Output<'static, AnyPin>,
|
spi_acs: Output<'static>,
|
||||||
spi_ccs: Output<'static, AnyPin>,
|
spi_ccs: Output<'static>,
|
||||||
) {
|
) {
|
||||||
Timer::after_secs(1).await;
|
Timer::after_secs(1).await;
|
||||||
*SPI_SHARED.lock().await = Some(spi);
|
*SPI_SHARED.lock().await = Some(spi);
|
||||||
|
@ -608,7 +609,7 @@ pub async fn update_stick_states_task(
|
||||||
let n = Instant::now();
|
let n = Instant::now();
|
||||||
|
|
||||||
match (n - last_loop_time).as_micros() {
|
match (n - last_loop_time).as_micros() {
|
||||||
a if a > 1666 => debug!("Loop took {} us", a),
|
a if a > 800 => debug!("Loop took {} us", a),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
last_loop_time = n;
|
last_loop_time = n;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use defmt::warn;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{is_awaitable_button_pressed, AwaitableButtons},
|
config::{is_awaitable_button_pressed, AwaitableButtons},
|
||||||
gcc_hid::GcReport,
|
usb_comms::GcState,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub trait InputFilter: Sized {
|
pub trait InputFilter: Sized {
|
||||||
fn apply_filter(&mut self, gcc_state: &mut GcReport);
|
fn apply_filter(&mut self, gcc_state: &mut GcState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Presses a single button if another button is pressed.
|
/// Presses a single button if another button is pressed.
|
||||||
|
@ -26,7 +26,7 @@ pub struct SingleButtonMacroFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputFilter for SingleButtonMacroFilter {
|
impl InputFilter for SingleButtonMacroFilter {
|
||||||
fn apply_filter(&mut self, gcc_state: &mut GcReport) {
|
fn apply_filter(&mut self, gcc_state: &mut GcState) {
|
||||||
if is_awaitable_button_pressed(gcc_state, &self.btn_instigator) {
|
if is_awaitable_button_pressed(gcc_state, &self.btn_instigator) {
|
||||||
match self.btn_to_press {
|
match self.btn_to_press {
|
||||||
AwaitableButtons::A => {
|
AwaitableButtons::A => {
|
||||||
|
@ -83,7 +83,7 @@ impl InputFilter for SingleButtonMacroFilter {
|
||||||
pub struct CStickUpTiltFilter;
|
pub struct CStickUpTiltFilter;
|
||||||
|
|
||||||
impl InputFilter for CStickUpTiltFilter {
|
impl InputFilter for CStickUpTiltFilter {
|
||||||
fn apply_filter(&mut self, gcc_state: &mut GcReport) {
|
fn apply_filter(&mut self, gcc_state: &mut GcState) {
|
||||||
if gcc_state.cstick_y > 157 {
|
if gcc_state.cstick_y > 157 {
|
||||||
if (137..=201).contains(&gcc_state.cstick_x) {
|
if (137..=201).contains(&gcc_state.cstick_x) {
|
||||||
gcc_state.cstick_x = 201;
|
gcc_state.cstick_x = 201;
|
||||||
|
@ -110,7 +110,7 @@ impl InputFilter for CStickUpTiltFilter {
|
||||||
pub struct CStickAngledFTiltFilter;
|
pub struct CStickAngledFTiltFilter;
|
||||||
|
|
||||||
impl InputFilter for CStickAngledFTiltFilter {
|
impl InputFilter for CStickAngledFTiltFilter {
|
||||||
fn apply_filter(&mut self, gcc_state: &mut GcReport) {
|
fn apply_filter(&mut self, gcc_state: &mut GcState) {
|
||||||
if gcc_state.cstick_y > 147 {
|
if gcc_state.cstick_y > 147 {
|
||||||
if (147..=225).contains(&gcc_state.cstick_x) {
|
if (147..=225).contains(&gcc_state.cstick_x) {
|
||||||
gcc_state.cstick_x = 205;
|
gcc_state.cstick_x = 205;
|
||||||
|
@ -136,5 +136,5 @@ impl InputFilter for CStickAngledFTiltFilter {
|
||||||
pub struct DummyFilter;
|
pub struct DummyFilter;
|
||||||
|
|
||||||
impl InputFilter for DummyFilter {
|
impl InputFilter for DummyFilter {
|
||||||
fn apply_filter(&mut self, _gcc_state: &mut GcReport) {}
|
fn apply_filter(&mut self, _gcc_state: &mut GcState) {}
|
||||||
}
|
}
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -1,19 +1,16 @@
|
||||||
//! This example test the RP Pico on board LED.
|
|
||||||
//!
|
|
||||||
//! It does not work with the RP Pico W board. See wifi_blinky.rs.
|
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
mod config;
|
mod config;
|
||||||
mod filter;
|
mod filter;
|
||||||
mod gcc_hid;
|
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod input;
|
mod input;
|
||||||
mod input_filter;
|
mod input_filter;
|
||||||
|
mod procon_hid;
|
||||||
mod stick;
|
mod stick;
|
||||||
|
mod usb_comms;
|
||||||
|
|
||||||
use config::config_task;
|
use config::config_task;
|
||||||
use defmt::{debug, info};
|
use defmt::info;
|
||||||
use embassy_executor::Executor;
|
use embassy_executor::Executor;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
bind_interrupts,
|
bind_interrupts,
|
||||||
|
@ -24,14 +21,14 @@ use embassy_rp::{
|
||||||
spi::{self, Spi},
|
spi::{self, Spi},
|
||||||
usb::{Driver, InterruptHandler},
|
usb::{Driver, InterruptHandler},
|
||||||
};
|
};
|
||||||
use gcc_hid::usb_transfer_task;
|
|
||||||
use gpio::{Level, Output};
|
use gpio::{Level, Output};
|
||||||
|
use usb_comms::usb_transfer_task;
|
||||||
|
|
||||||
use input::{update_button_state_task, update_stick_states_task};
|
use input::{update_button_state_task, update_stick_states_task};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
use crate::config::enter_config_mode_task;
|
use crate::config::enter_config_mode_task;
|
||||||
use crate::gcc_hid::rumble_task;
|
use crate::usb_comms::rumble_task;
|
||||||
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
@ -77,12 +74,11 @@ fn main() -> ! {
|
||||||
|
|
||||||
spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
|
spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
|
||||||
let executor1 = EXECUTOR1.init(Executor::new());
|
let executor1 = EXECUTOR1.init(Executor::new());
|
||||||
debug!("Mana");
|
|
||||||
executor1.run(|spawner| {
|
executor1.run(|spawner| {
|
||||||
spawner.spawn(usb_transfer_task(uid, driver)).unwrap();
|
spawner.spawn(usb_transfer_task(uid, driver)).unwrap();
|
||||||
spawner.spawn(enter_config_mode_task()).unwrap();
|
spawner.spawn(enter_config_mode_task()).unwrap();
|
||||||
spawner
|
spawner
|
||||||
.spawn(rumble_task(p.PIN_25, p.PIN_29, p.PWM_CH4, p.PWM_CH6))
|
.spawn(rumble_task(p.PIN_25, p.PIN_29, p.PWM_SLICE4, p.PWM_SLICE6))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// spawner.spawn(input_integrity_benchmark()).unwrap();
|
// spawner.spawn(input_integrity_benchmark()).unwrap();
|
||||||
spawner
|
spawner
|
||||||
|
|
614
src/procon_hid.rs
Normal file
614
src/procon_hid.rs
Normal file
|
@ -0,0 +1,614 @@
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use defmt::{info, trace, Format};
|
||||||
|
use embassy_rp::clocks::RoscRng;
|
||||||
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
|
||||||
|
use embassy_time::Instant;
|
||||||
|
use embassy_usb::{
|
||||||
|
class::hid::{ReportId, RequestHandler},
|
||||||
|
control::OutResponse,
|
||||||
|
};
|
||||||
|
use packed_struct::{derive::PackedStruct, PackedStruct};
|
||||||
|
use rand::RngCore;
|
||||||
|
|
||||||
|
use crate::usb_comms::{GcState, HidReportBuilder};
|
||||||
|
|
||||||
|
const SW_INFO_SET_MAC: u8 = 0x01;
|
||||||
|
|
||||||
|
const SW_CMD_SET_INPUT_MODE: u8 = 0x03;
|
||||||
|
const SW_CMD_GET_DEVINFO: u8 = 0x02;
|
||||||
|
const SW_CMD_SET_SHIPMODE: u8 = 0x08;
|
||||||
|
const SW_CMD_GET_SPI: u8 = 0x10;
|
||||||
|
const SW_CMD_SET_PAIRING: u8 = 0x01;
|
||||||
|
const SW_CMD_GET_TRIGGERET: u8 = 0x04;
|
||||||
|
|
||||||
|
const ACK_GET_DEVINFO: u8 = 0x82;
|
||||||
|
const ACK_GET_SPI: u8 = 0x90;
|
||||||
|
const ACK_SET_PAIRING: u8 = 0x81;
|
||||||
|
const ACK_GET_TRIGERET: u8 = 0x83;
|
||||||
|
|
||||||
|
const ACK_GENERIC: u8 = 0x80;
|
||||||
|
|
||||||
|
const RM_SEND_STATE: u8 = 0x30;
|
||||||
|
|
||||||
|
const PRO_CONTROLLER_STRING: [u8; 24] = [
|
||||||
|
0x00, 0x25, 0x08, 0x50, 0x72, 0x6F, 0x20, 0x43, 0x6F, 0x6E, 0x74, 0x72, 0x6F, 0x6C, 0x6C, 0x65,
|
||||||
|
0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug, Format, Clone, Copy)]
|
||||||
|
struct ProconRequestInfo {
|
||||||
|
report_id: ProconRequestId,
|
||||||
|
response_id: ProconResponseId,
|
||||||
|
command_id: u8,
|
||||||
|
raw_data: [u8; 64],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Format, Clone, Copy)]
|
||||||
|
enum ProconRequestId {
|
||||||
|
GetInfo = 0x80,
|
||||||
|
Command = 0x01,
|
||||||
|
Rumble = 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Format, Clone, Copy)]
|
||||||
|
enum ProconResponseId {
|
||||||
|
GetInfo = 0x81,
|
||||||
|
GetState = 0x30,
|
||||||
|
Command = 0x21,
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIGNAL_PROCON_REQUEST: Signal<CriticalSectionRawMutex, ProconRequestInfo> = Signal::new();
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub const PROCON_REPORT_DESCRIPTOR: &[u8] = &[
|
||||||
|
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
|
||||||
|
0x09, 0x04, // Usage (Joystick)
|
||||||
|
0xA1, 0x01, // Collection (Application)
|
||||||
|
|
||||||
|
0x85, 0x30, // Report ID (48)
|
||||||
|
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||||
|
0x05, 0x09, // Usage Page (Button)
|
||||||
|
0x19, 0x01, // Usage Minimum (0x01)
|
||||||
|
0x29, 0x0A, // Usage Maximum (0x0A)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x25, 0x01, // Logical Maximum (1)
|
||||||
|
0x75, 0x01, // Report Size (1)
|
||||||
|
0x95, 0x0A, // Report Count (10)
|
||||||
|
0x55, 0x00, // Unit Exponent (0)
|
||||||
|
0x65, 0x00, // Unit (None)
|
||||||
|
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
0x05, 0x09, // Usage Page (Button)
|
||||||
|
0x19, 0x0B, // Usage Minimum (0x0B)
|
||||||
|
0x29, 0x0E, // Usage Maximum (0x0E)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x25, 0x01, // Logical Maximum (1)
|
||||||
|
0x75, 0x01, // Report Size (1)
|
||||||
|
0x95, 0x04, // Report Count (4)
|
||||||
|
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
0x75, 0x01, // Report Size (1)
|
||||||
|
0x95, 0x02, // Report Count (2)
|
||||||
|
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
|
||||||
|
0x0B, 0x01, 0x00, 0x01, 0x00, // Usage (0x010001)
|
||||||
|
0xA1, 0x00, // Collection (Physical)
|
||||||
|
0x0B, 0x30, 0x00, 0x01, 0x00, // Usage (0x010030)
|
||||||
|
0x0B, 0x31, 0x00, 0x01, 0x00, // Usage (0x010031)
|
||||||
|
0x0B, 0x32, 0x00, 0x01, 0x00, // Usage (0x010032)
|
||||||
|
0x0B, 0x35, 0x00, 0x01, 0x00, // Usage (0x010035)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534)
|
||||||
|
0x75, 0x10, // Report Size (16)
|
||||||
|
0x95, 0x04, // Report Count (4)
|
||||||
|
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
0xC0, // End Collection
|
||||||
|
|
||||||
|
0x0B, 0x39, 0x00, 0x01, 0x00, // Usage (0x010039)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x25, 0x07, // Logical Maximum (7)
|
||||||
|
0x35, 0x00, // Physical Minimum (0)
|
||||||
|
0x46, 0x3B, 0x01, // Physical Maximum (315)
|
||||||
|
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
|
||||||
|
0x75, 0x04, // Report Size (4)
|
||||||
|
0x95, 0x01, // Report Count (1)
|
||||||
|
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
0x05, 0x09, // Usage Page (Button)
|
||||||
|
0x19, 0x0F, // Usage Minimum (0x0F)
|
||||||
|
0x29, 0x12, // Usage Maximum (0x12)
|
||||||
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
|
0x25, 0x01, // Logical Maximum (1)
|
||||||
|
0x75, 0x01, // Report Size (1)
|
||||||
|
0x95, 0x04, // Report Count (4)
|
||||||
|
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x34, // Report Count (52)
|
||||||
|
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
|
||||||
|
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
|
||||||
|
0x85, 0x21, // Report ID (33)
|
||||||
|
0x09, 0x01, // Usage (0x01)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x3F, // Report Count (63)
|
||||||
|
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
|
||||||
|
0x85, 0x81, // Report ID (-127)
|
||||||
|
0x09, 0x02, // Usage (0x02)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x3F, // Report Count (63)
|
||||||
|
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
|
||||||
|
0x85, 0x01, // Report ID (1)
|
||||||
|
0x09, 0x03, // Usage (0x03)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x3F, // Report Count (63)
|
||||||
|
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
|
||||||
|
|
||||||
|
0x85, 0x10, // Report ID (16)
|
||||||
|
0x09, 0x04, // Usage (0x04)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x3F, // Report Count (63)
|
||||||
|
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
|
||||||
|
|
||||||
|
0x85, 0x80, // Report ID (-128)
|
||||||
|
0x09, 0x05, // Usage (0x05)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x3F, // Report Count (63)
|
||||||
|
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
|
||||||
|
|
||||||
|
0x85, 0x82, // Report ID (-126)
|
||||||
|
0x09, 0x06, // Usage (0x06)
|
||||||
|
0x75, 0x08, // Report Size (8)
|
||||||
|
0x95, 0x3F, // Report Count (63)
|
||||||
|
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
|
||||||
|
|
||||||
|
0xC0, // End Collection
|
||||||
|
|
||||||
|
// 203 bytes
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Format)]
|
||||||
|
struct ProconByteReport([u8; 64]);
|
||||||
|
|
||||||
|
impl Deref for ProconByteReport {
|
||||||
|
type Target = [u8; 64];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ProconByteReport {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProconByteReport {
|
||||||
|
fn set_report_id(&mut self, id: u8) {
|
||||||
|
self[0] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_battery_status(&mut self) {
|
||||||
|
self[2] = BatteryStatus::default()
|
||||||
|
.pack()
|
||||||
|
.expect("Failed to pack fake procon battery status")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_timer(&mut self) {
|
||||||
|
self[1] = Instant::now().as_millis() as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ack(&mut self, ack: u8) {
|
||||||
|
self[13] = ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_subcommand(&mut self, cmd: u8) {
|
||||||
|
self[14] = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_devinfo(&mut self) {
|
||||||
|
self[15] = 0x04; // NS Firmware primary (4.x)
|
||||||
|
self[16] = 0x33; // NS Firmware secondary (x.21)
|
||||||
|
|
||||||
|
self[17] = 0x03; // Controller ID primary (Pro Controller)
|
||||||
|
self[18] = 0x02; // Controller ID secondary
|
||||||
|
|
||||||
|
self[25] = 0x01;
|
||||||
|
self[26] = 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sw_spi_readfromaddress(&mut self, offset_address: u8, address: u8, length: u8) {
|
||||||
|
let read_info = [address, offset_address, 0x00, 0x00, length];
|
||||||
|
self[15..(15 + read_info.len())].copy_from_slice(&read_info);
|
||||||
|
|
||||||
|
let mut output_spi_data = [0u8; 30];
|
||||||
|
|
||||||
|
output_spi_data
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, e)| *e = sw_spi_getaddressdata(offset_address, address + i as u8));
|
||||||
|
|
||||||
|
self[19..(19 + length as usize)].copy_from_slice(&output_spi_data[..(length as usize)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_trigerret(&mut self, time_10_ms: u16) {
|
||||||
|
let [upper_ms, lower_ms] = time_10_ms.to_be_bytes();
|
||||||
|
|
||||||
|
for i in 0..14 {
|
||||||
|
self[15 + i] = upper_ms;
|
||||||
|
self[16 + i] = lower_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sw_spi_getaddressdata(_offset_address: u8, _address: u8) -> u8 {
|
||||||
|
// TODO
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||||
|
pub struct ProconButtonsRight {
|
||||||
|
#[packed_field(bits = "0")]
|
||||||
|
pub button_y: bool,
|
||||||
|
#[packed_field(bits = "1")]
|
||||||
|
pub button_x: bool,
|
||||||
|
#[packed_field(bits = "2")]
|
||||||
|
pub button_b: bool,
|
||||||
|
#[packed_field(bits = "3")]
|
||||||
|
pub button_a: bool,
|
||||||
|
#[packed_field(bits = "4")]
|
||||||
|
pub trigger_r_sr: bool,
|
||||||
|
#[packed_field(bits = "5")]
|
||||||
|
pub trigger_r_sl: bool,
|
||||||
|
#[packed_field(bits = "6")]
|
||||||
|
pub trigger_r: bool,
|
||||||
|
#[packed_field(bits = "7")]
|
||||||
|
pub trigger_zr: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||||
|
pub struct ProconButtonsShared {
|
||||||
|
#[packed_field(bits = "0")]
|
||||||
|
pub button_minus: bool,
|
||||||
|
#[packed_field(bits = "1")]
|
||||||
|
pub button_plus: bool,
|
||||||
|
#[packed_field(bits = "2")]
|
||||||
|
pub button_sb_right: bool,
|
||||||
|
#[packed_field(bits = "3")]
|
||||||
|
pub button_sb_left: bool,
|
||||||
|
#[packed_field(bits = "4")]
|
||||||
|
pub button_home: bool,
|
||||||
|
#[packed_field(bits = "5")]
|
||||||
|
pub button_capture: bool,
|
||||||
|
#[packed_field(bits = "6")]
|
||||||
|
pub none: bool,
|
||||||
|
#[packed_field(bits = "7")]
|
||||||
|
pub change_grip_active: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||||
|
pub struct ProconButtonsLeft {
|
||||||
|
#[packed_field(bits = "0")]
|
||||||
|
pub dpad_down: bool,
|
||||||
|
#[packed_field(bits = "1")]
|
||||||
|
pub dpad_up: bool,
|
||||||
|
#[packed_field(bits = "2")]
|
||||||
|
pub dpad_right: bool,
|
||||||
|
#[packed_field(bits = "3")]
|
||||||
|
pub dped_left: bool,
|
||||||
|
#[packed_field(bits = "4")]
|
||||||
|
pub trigger_l_sr: bool,
|
||||||
|
#[packed_field(bits = "5")]
|
||||||
|
pub trigger_l_sl: bool,
|
||||||
|
#[packed_field(bits = "6")]
|
||||||
|
pub trigger_l: bool,
|
||||||
|
#[packed_field(bits = "7")]
|
||||||
|
pub trigger_zl: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "msb0", endian = "msb", size_bytes = "9")]
|
||||||
|
pub struct ProconState {
|
||||||
|
#[packed_field(bits = "0..=7")]
|
||||||
|
pub buttons_right: ProconButtonsRight,
|
||||||
|
#[packed_field(bits = "8..=15")]
|
||||||
|
pub buttons_shared: ProconButtonsShared,
|
||||||
|
#[packed_field(bits = "16..=23")]
|
||||||
|
pub buttons_left: ProconButtonsLeft,
|
||||||
|
#[packed_field(bits = "24..=39")]
|
||||||
|
pub lstick_x: u16,
|
||||||
|
#[packed_field(bits = "40..=47")]
|
||||||
|
pub lstick_y: u8,
|
||||||
|
#[packed_field(bits = "48..=60")]
|
||||||
|
pub rstick_x: u16,
|
||||||
|
#[packed_field(bits = "64..=71")]
|
||||||
|
pub rstick_y: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "lsb0", endian = "msb", size_bytes = "1")]
|
||||||
|
struct BatteryStatus {
|
||||||
|
#[packed_field(bits = "0..=3")]
|
||||||
|
connection: u8,
|
||||||
|
#[packed_field(bits = "4..=7")]
|
||||||
|
battery_level: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BatteryStatus {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
connection: 1,
|
||||||
|
battery_level: 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&GcState> for ProconState {
|
||||||
|
fn from(value: &GcState) -> Self {
|
||||||
|
Self {
|
||||||
|
buttons_left: ProconButtonsLeft {
|
||||||
|
dpad_down: value.buttons_1.dpad_down,
|
||||||
|
dpad_right: value.buttons_1.dpad_right,
|
||||||
|
dpad_up: value.buttons_1.dpad_up,
|
||||||
|
dped_left: value.buttons_1.dpad_left,
|
||||||
|
trigger_l: value.buttons_2.button_l,
|
||||||
|
trigger_zl: value.buttons_2.button_l,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
buttons_right: ProconButtonsRight {
|
||||||
|
button_a: value.buttons_1.button_a,
|
||||||
|
button_b: value.buttons_1.button_b,
|
||||||
|
button_x: value.buttons_1.button_x,
|
||||||
|
button_y: value.buttons_1.button_y,
|
||||||
|
trigger_r: value.buttons_2.button_r,
|
||||||
|
trigger_zr: value.buttons_2.button_z,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
buttons_shared: ProconButtonsShared {
|
||||||
|
button_plus: value.buttons_2.button_start && !value.buttons_2.button_z,
|
||||||
|
button_home: value.buttons_2.button_start && value.buttons_2.button_z,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lstick_x: value.stick_x as u16 * 257,
|
||||||
|
lstick_y: value.stick_y,
|
||||||
|
rstick_x: value.cstick_x as u16 * 257,
|
||||||
|
rstick_y: value.cstick_y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProconReportBuilder {
|
||||||
|
switch_reporting_mode: u8,
|
||||||
|
switch_mac_address: [u8; 6],
|
||||||
|
switch_ltk: [u8; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ProconReportBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
switch_reporting_mode: 0,
|
||||||
|
switch_mac_address: [0u8; 6],
|
||||||
|
switch_ltk: gen_switch_ltk(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_switch_ltk() -> [u8; 16] {
|
||||||
|
let mut switch_ltk = [0u8; 16];
|
||||||
|
|
||||||
|
switch_ltk.iter_mut().for_each(|e| {
|
||||||
|
*e = RoscRng.next_u64() as u8;
|
||||||
|
});
|
||||||
|
|
||||||
|
switch_ltk
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProconReportBuilder {
|
||||||
|
fn get_info_report(&self, current_report_info: &ProconRequestInfo) -> [u8; 64] {
|
||||||
|
let mut report = ProconByteReport([0u8; 64]);
|
||||||
|
|
||||||
|
report.set_report_id(ProconResponseId::GetInfo as u8);
|
||||||
|
|
||||||
|
if current_report_info.command_id == SW_INFO_SET_MAC {
|
||||||
|
report[1] = SW_INFO_SET_MAC;
|
||||||
|
report[3] = 0x03;
|
||||||
|
|
||||||
|
self.switch_mac_address
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, e)| {
|
||||||
|
report[4 + i] = *e;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
report[1] = current_report_info.command_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
*report
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_state_report(&self, state: &ProconState) -> [u8; 64] {
|
||||||
|
static mut UNKNOWN: u8 = 0xA;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
UNKNOWN = match UNKNOWN {
|
||||||
|
0xA => 0xB,
|
||||||
|
0xB => 0xC,
|
||||||
|
_ => 0xA,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut report = ProconByteReport([0u8; 64]);
|
||||||
|
|
||||||
|
let data = state
|
||||||
|
.pack()
|
||||||
|
.expect("Failed to pack pro controller input data");
|
||||||
|
|
||||||
|
report.set_report_id(ProconResponseId::GetState as u8);
|
||||||
|
report.set_timer();
|
||||||
|
report.set_battery_status();
|
||||||
|
|
||||||
|
report[3..=11].copy_from_slice(&data);
|
||||||
|
report[12] = unsafe { UNKNOWN };
|
||||||
|
|
||||||
|
*report
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_command_report(&mut self, current_report_info: &ProconRequestInfo) -> [u8; 64] {
|
||||||
|
let mut report = ProconByteReport([0u8; 64]);
|
||||||
|
|
||||||
|
report.set_report_id(ProconResponseId::Command as u8);
|
||||||
|
report.set_timer();
|
||||||
|
report.set_battery_status();
|
||||||
|
report.set_subcommand(current_report_info.command_id);
|
||||||
|
|
||||||
|
match current_report_info.command_id {
|
||||||
|
SW_CMD_SET_INPUT_MODE => {
|
||||||
|
report.set_ack(ACK_GENERIC);
|
||||||
|
self.switch_reporting_mode = current_report_info.raw_data[11];
|
||||||
|
info!(
|
||||||
|
"Switch reporting mode is now {:x}",
|
||||||
|
self.switch_reporting_mode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SW_CMD_GET_DEVINFO => {
|
||||||
|
report.set_ack(ACK_GET_DEVINFO);
|
||||||
|
report.set_devinfo();
|
||||||
|
}
|
||||||
|
SW_CMD_GET_SPI => {
|
||||||
|
report.set_ack(ACK_GET_SPI);
|
||||||
|
report.sw_spi_readfromaddress(
|
||||||
|
current_report_info.raw_data[12],
|
||||||
|
current_report_info.raw_data[11],
|
||||||
|
current_report_info.raw_data[15],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SW_CMD_SET_SHIPMODE => {
|
||||||
|
report.set_ack(ACK_GENERIC);
|
||||||
|
}
|
||||||
|
SW_CMD_SET_PAIRING => {
|
||||||
|
report.set_ack(ACK_SET_PAIRING);
|
||||||
|
self.perform_pairing(&mut report, current_report_info);
|
||||||
|
}
|
||||||
|
SW_CMD_GET_TRIGGERET => {
|
||||||
|
report.set_ack(ACK_GET_TRIGERET);
|
||||||
|
report.set_trigerret(100);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
report.set_ack(ACK_GENERIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*report
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perform_pairing(
|
||||||
|
&mut self,
|
||||||
|
report: &mut ProconByteReport,
|
||||||
|
current_report_info: &ProconRequestInfo,
|
||||||
|
) {
|
||||||
|
let pairing_phase = current_report_info.raw_data[11];
|
||||||
|
let host_address = ¤t_report_info.raw_data[12..];
|
||||||
|
|
||||||
|
match pairing_phase {
|
||||||
|
1 => {
|
||||||
|
self.switch_mac_address
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, e)| *e = host_address[5 - i]);
|
||||||
|
|
||||||
|
self.switch_mac_address
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, e)| {
|
||||||
|
report[16 + i] = *e;
|
||||||
|
});
|
||||||
|
|
||||||
|
report[22..(22 + PRO_CONTROLLER_STRING.len())]
|
||||||
|
.copy_from_slice(&PRO_CONTROLLER_STRING);
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
report[15] = 2;
|
||||||
|
report[16..(16 + self.switch_ltk.len())].copy_from_slice(&self.switch_ltk);
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
report[15] = 3;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HidReportBuilder<64> for ProconReportBuilder {
|
||||||
|
async fn get_hid_report(&mut self, state: &GcState) -> [u8; 64] {
|
||||||
|
let current_report_info = if self.switch_reporting_mode == RM_SEND_STATE {
|
||||||
|
SIGNAL_PROCON_REQUEST.try_take()
|
||||||
|
} else {
|
||||||
|
Some(SIGNAL_PROCON_REQUEST.wait().await)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(current_report_info) = current_report_info {
|
||||||
|
match current_report_info.report_id {
|
||||||
|
ProconRequestId::GetInfo => self.get_info_report(¤t_report_info),
|
||||||
|
ProconRequestId::Command => self.get_command_report(¤t_report_info),
|
||||||
|
ProconRequestId::Rumble => self.get_state_report(&ProconState::from(state)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.get_state_report(&ProconState::from(state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProconRequestHandler;
|
||||||
|
|
||||||
|
impl RequestHandler for ProconRequestHandler {
|
||||||
|
fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
|
||||||
|
info!("Get report for {:?}", id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
|
||||||
|
trace!("Set report for {:?}: {:x}", id, data);
|
||||||
|
|
||||||
|
let mut buf = [0u8; 64];
|
||||||
|
let len_to_copy = buf.len().min(data.len());
|
||||||
|
buf[..len_to_copy].copy_from_slice(&data[..len_to_copy]);
|
||||||
|
|
||||||
|
if let ReportId::Out(id) = id {
|
||||||
|
if id == ProconRequestId::GetInfo as u8 {
|
||||||
|
SIGNAL_PROCON_REQUEST.signal(ProconRequestInfo {
|
||||||
|
command_id: buf[1],
|
||||||
|
report_id: ProconRequestId::GetInfo,
|
||||||
|
response_id: ProconResponseId::GetInfo,
|
||||||
|
raw_data: buf,
|
||||||
|
});
|
||||||
|
} else if id == ProconRequestId::Command as u8 {
|
||||||
|
SIGNAL_PROCON_REQUEST.signal(ProconRequestInfo {
|
||||||
|
command_id: buf[10],
|
||||||
|
report_id: ProconRequestId::Command,
|
||||||
|
response_id: ProconResponseId::Command,
|
||||||
|
raw_data: buf,
|
||||||
|
});
|
||||||
|
} else if id == ProconRequestId::Rumble as u8 {
|
||||||
|
// TODO: handle rumble
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutResponse::Accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
|
||||||
|
info!("Set idle rate for {:?} to {:?}", id, dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
|
||||||
|
info!("Get idle rate for {:?}", id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ use core::{default::Default, future::Future};
|
||||||
use defmt::{debug, info, trace, warn, Format};
|
use defmt::{debug, info, trace, warn, Format};
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
peripherals::{PIN_25, PIN_29, PWM_CH4, PWM_CH6, USB},
|
peripherals::{PIN_25, PIN_29, PWM_SLICE4, PWM_SLICE6, USB},
|
||||||
pwm::Pwm,
|
pwm::Pwm,
|
||||||
usb::Driver as EmbassyDriver,
|
usb::Driver as EmbassyDriver,
|
||||||
};
|
};
|
||||||
|
@ -27,6 +27,7 @@ use packed_struct::{derive::PackedStruct, PackedStruct};
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{ControllerMode, InputConsistencyMode},
|
config::{ControllerMode, InputConsistencyMode},
|
||||||
input::CHANNEL_GCC_STATE,
|
input::CHANNEL_GCC_STATE,
|
||||||
|
procon_hid::{ProconReportBuilder, ProconRequestHandler, PROCON_REPORT_DESCRIPTOR},
|
||||||
};
|
};
|
||||||
|
|
||||||
static SIGNAL_RUMBLE: Signal<CriticalSectionRawMutex, bool> = Signal::new();
|
static SIGNAL_RUMBLE: Signal<CriticalSectionRawMutex, bool> = Signal::new();
|
||||||
|
@ -105,8 +106,8 @@ pub const GCC_REPORT_DESCRIPTOR: &[u8] = &[
|
||||||
0xC0, // End Collection
|
0xC0, // End Collection
|
||||||
];
|
];
|
||||||
|
|
||||||
trait HidReportable<const LEN: usize> {
|
pub trait HidReportBuilder<const LEN: usize> {
|
||||||
fn get_hid_report(&self) -> [u8; LEN];
|
async fn get_hid_report(&mut self, state: &GcState) -> [u8; LEN];
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UsbConfig {
|
struct UsbConfig {
|
||||||
|
@ -153,7 +154,7 @@ pub struct GcButtons2 {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct, Format)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct, Format)]
|
||||||
#[packed_struct(bit_numbering = "msb0", size_bytes = "8")]
|
#[packed_struct(bit_numbering = "msb0", size_bytes = "8")]
|
||||||
pub struct GcReport {
|
pub struct GcState {
|
||||||
#[packed_field(bits = "0..=7")]
|
#[packed_field(bits = "0..=7")]
|
||||||
pub buttons_1: GcButtons1,
|
pub buttons_1: GcButtons1,
|
||||||
#[packed_field(bits = "8..=15")]
|
#[packed_field(bits = "8..=15")]
|
||||||
|
@ -172,7 +173,7 @@ pub struct GcReport {
|
||||||
pub trigger_r: u8,
|
pub trigger_r: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GcReport {
|
impl Default for GcState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
buttons_1: GcButtons1::default(),
|
buttons_1: GcButtons1::default(),
|
||||||
|
@ -187,50 +188,58 @@ impl Default for GcReport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HidReportable<37> for GcReport {
|
#[derive(Default)]
|
||||||
fn get_hid_report(&self) -> [u8; 37] {
|
struct GcReportBuilder {
|
||||||
static mut GC_FIRST: bool = false;
|
gc_first: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HidReportBuilder<37> for GcReportBuilder {
|
||||||
|
async fn get_hid_report(&mut self, state: &GcState) -> [u8; 37] {
|
||||||
let mut buffer = [0u8; 37];
|
let mut buffer = [0u8; 37];
|
||||||
|
|
||||||
buffer[0] = 0x21;
|
buffer[0] = 0x21;
|
||||||
buffer[1] |= 0x14;
|
buffer[1] |= 0x14;
|
||||||
|
|
||||||
let data = self.pack().expect("Failed to pack GC input data");
|
let data = state.pack().expect("Failed to pack GC input data");
|
||||||
|
|
||||||
if unsafe { !GC_FIRST } {
|
if !self.gc_first {
|
||||||
buffer[1] |= 0x04;
|
buffer[1] |= 0x04;
|
||||||
buffer[10] |= 0x04;
|
buffer[10] |= 0x04;
|
||||||
buffer[19] |= 0x04;
|
buffer[19] |= 0x04;
|
||||||
buffer[28] |= 0x04;
|
buffer[28] |= 0x04;
|
||||||
unsafe { GC_FIRST = true };
|
self.gc_first = true;
|
||||||
} else {
|
} else {
|
||||||
// controller in "port 1"
|
// controller in "port 1"
|
||||||
buffer[2..=9].copy_from_slice(&data[0..=7]);
|
buffer[2..=9].copy_from_slice(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GccRequestHandler {}
|
struct GccRequestHandler;
|
||||||
|
|
||||||
impl RequestHandler for GccRequestHandler {
|
impl RequestHandler for GccRequestHandler {
|
||||||
fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
|
fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
|
||||||
info!("Get report for {:?}", id);
|
info!("Get report for {:?}", id);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
|
fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
|
||||||
info!("Set report for {:?}: {=[u8]}", id, data);
|
trace!("Set report for {:?}: {:x}", id, data);
|
||||||
|
|
||||||
|
if data.len() > 1 {
|
||||||
|
SIGNAL_RUMBLE.signal((data[1] & 0x01) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
OutResponse::Accepted
|
OutResponse::Accepted
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
|
fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
|
||||||
info!("Set idle rate for {:?} to {:?}", id, dur);
|
info!("Set idle rate for {:?} to {:?}", id, dur);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
|
fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
|
||||||
info!("Get idle rate for {:?}", id);
|
info!("Get idle rate for {:?}", id);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -281,13 +290,12 @@ impl Handler for MyDeviceHandler {
|
||||||
fn mk_hid_reader_writer<'d, D: Driver<'d>, const R: usize, const W: usize>(
|
fn mk_hid_reader_writer<'d, D: Driver<'d>, const R: usize, const W: usize>(
|
||||||
input_consistency_mode: InputConsistencyMode,
|
input_consistency_mode: InputConsistencyMode,
|
||||||
report_descriptor: &'d [u8],
|
report_descriptor: &'d [u8],
|
||||||
request_handler: &'d GccRequestHandler,
|
|
||||||
mut builder: Builder<'d, D>,
|
mut builder: Builder<'d, D>,
|
||||||
state: &'d mut State<'d>,
|
state: &'d mut State<'d>,
|
||||||
) -> (UsbDevice<'d, D>, HidReader<'d, D, R>, HidWriter<'d, D, W>) {
|
) -> (UsbDevice<'d, D>, HidReader<'d, D, R>, HidWriter<'d, D, W>) {
|
||||||
let hid_config = embassy_usb::class::hid::Config {
|
let hid_config = embassy_usb::class::hid::Config {
|
||||||
report_descriptor,
|
report_descriptor,
|
||||||
request_handler: Some(request_handler),
|
request_handler: None,
|
||||||
poll_ms: match input_consistency_mode {
|
poll_ms: match input_consistency_mode {
|
||||||
InputConsistencyMode::Original => 8,
|
InputConsistencyMode::Original => 8,
|
||||||
InputConsistencyMode::ConsistencyHack
|
InputConsistencyMode::ConsistencyHack
|
||||||
|
@ -308,13 +316,13 @@ fn mk_hid_reader_writer<'d, D: Driver<'d>, const R: usize, const W: usize>(
|
||||||
(usb, reader, writer)
|
(usb, reader, writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_usb_transfer_futures<'d, D, F, H, const R: usize, const W: usize>(
|
fn mk_usb_transfer_futures<'d, D, H, Rq, const R: usize, const W: usize>(
|
||||||
input_consistency_mode: InputConsistencyMode,
|
input_consistency_mode: InputConsistencyMode,
|
||||||
usb_config: UsbConfig,
|
usb_config: &UsbConfig,
|
||||||
request_handler: &'d GccRequestHandler,
|
request_handler: &'d mut Rq,
|
||||||
builder: Builder<'d, D>,
|
builder: Builder<'d, D>,
|
||||||
state: &'d mut State<'d>,
|
state: &'d mut State<'d>,
|
||||||
preprocess_report: F,
|
mut hid_report_builder: H,
|
||||||
) -> (
|
) -> (
|
||||||
impl Future<Output = ()> + 'd,
|
impl Future<Output = ()> + 'd,
|
||||||
impl Future<Output = ()> + 'd,
|
impl Future<Output = ()> + 'd,
|
||||||
|
@ -322,13 +330,12 @@ fn mk_usb_transfer_futures<'d, D, F, H, const R: usize, const W: usize>(
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
D: Driver<'d> + 'd,
|
D: Driver<'d> + 'd,
|
||||||
F: Fn(GcReport) -> H + 'd,
|
H: HidReportBuilder<W> + 'd,
|
||||||
H: HidReportable<W>,
|
Rq: RequestHandler,
|
||||||
{
|
{
|
||||||
let (mut usb, mut reader, mut writer) = mk_hid_reader_writer::<_, R, W>(
|
let (mut usb, reader, mut writer) = mk_hid_reader_writer::<_, R, W>(
|
||||||
input_consistency_mode,
|
input_consistency_mode,
|
||||||
usb_config.report_descriptor,
|
usb_config.report_descriptor,
|
||||||
request_handler,
|
|
||||||
builder,
|
builder,
|
||||||
state,
|
state,
|
||||||
);
|
);
|
||||||
|
@ -368,9 +375,9 @@ where
|
||||||
|
|
||||||
writer.ready().await;
|
writer.ready().await;
|
||||||
|
|
||||||
let state = preprocess_report(gcc_subscriber.next_message_pure().await);
|
let state = gcc_subscriber.next_message_pure().await;
|
||||||
|
|
||||||
let report = state.get_hid_report();
|
let report = hid_report_builder.get_hid_report(&state).await;
|
||||||
|
|
||||||
trace!("Writing report: {:08b}", report);
|
trace!("Writing report: {:08b}", report);
|
||||||
|
|
||||||
|
@ -395,19 +402,8 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let out_fut = async move {
|
let out_fut = async move {
|
||||||
loop {
|
|
||||||
trace!("Readery loop");
|
trace!("Readery loop");
|
||||||
let mut buf = [0u8; R];
|
reader.run(true, request_handler).await;
|
||||||
match reader.read(&mut buf).await {
|
|
||||||
Ok(_e) => {
|
|
||||||
debug!("READ SOMETHIN: {:08b}", buf);
|
|
||||||
SIGNAL_RUMBLE.signal((buf[1] & 0x01) != 0);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Failed to read: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let usb_fut_wrapped = async {
|
let usb_fut_wrapped = async {
|
||||||
|
@ -420,12 +416,6 @@ where
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: EmbassyDriver<'static, USB>) {
|
pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: EmbassyDriver<'static, USB>) {
|
||||||
let config = UsbConfig {
|
|
||||||
vid: 0x057e,
|
|
||||||
pid: 0x0337,
|
|
||||||
report_descriptor: GCC_REPORT_DESCRIPTOR,
|
|
||||||
};
|
|
||||||
|
|
||||||
let input_consistency_mode = {
|
let input_consistency_mode = {
|
||||||
while MUTEX_INPUT_CONSISTENCY_MODE.lock().await.is_none() {
|
while MUTEX_INPUT_CONSISTENCY_MODE.lock().await.is_none() {
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
@ -433,6 +423,27 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: EmbassyDriver<'stati
|
||||||
MUTEX_INPUT_CONSISTENCY_MODE.lock().await.unwrap()
|
MUTEX_INPUT_CONSISTENCY_MODE.lock().await.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let controller_mode = {
|
||||||
|
while MUTEX_CONTROLLER_MODE.lock().await.is_none() {
|
||||||
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTEX_CONTROLLER_MODE.lock().await.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = match controller_mode {
|
||||||
|
ControllerMode::GcAdapter => UsbConfig {
|
||||||
|
vid: 0x057e,
|
||||||
|
pid: 0x0337,
|
||||||
|
report_descriptor: GCC_REPORT_DESCRIPTOR,
|
||||||
|
},
|
||||||
|
ControllerMode::Procon => UsbConfig {
|
||||||
|
vid: 0x57e,
|
||||||
|
pid: 0x2009,
|
||||||
|
report_descriptor: PROCON_REPORT_DESCRIPTOR,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut serial_buffer = [0u8; 64];
|
let mut serial_buffer = [0u8; 64];
|
||||||
|
|
||||||
let serial = format_no_std::show(
|
let serial = format_no_std::show(
|
||||||
|
@ -471,13 +482,11 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: EmbassyDriver<'stati
|
||||||
usb_config.device_sub_class = 0;
|
usb_config.device_sub_class = 0;
|
||||||
usb_config.supports_remote_wakeup = true;
|
usb_config.supports_remote_wakeup = true;
|
||||||
|
|
||||||
let mut device_descriptor = [0; 256];
|
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
let mut msos_descriptor = [0; 256];
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
|
|
||||||
let request_handler = GccRequestHandler {};
|
|
||||||
let mut device_handler = MyDeviceHandler::new();
|
let mut device_handler = MyDeviceHandler::new();
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
|
@ -485,7 +494,6 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: EmbassyDriver<'stati
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
driver,
|
driver,
|
||||||
usb_config,
|
usb_config,
|
||||||
&mut device_descriptor,
|
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
&mut msos_descriptor,
|
&mut msos_descriptor,
|
||||||
|
@ -503,17 +511,37 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: EmbassyDriver<'stati
|
||||||
|
|
||||||
builder.handler(&mut device_handler);
|
builder.handler(&mut device_handler);
|
||||||
|
|
||||||
|
match controller_mode {
|
||||||
|
ControllerMode::GcAdapter => {
|
||||||
|
let mut request_handler = GccRequestHandler;
|
||||||
|
|
||||||
let (usb_fut_wrapped, in_fut, out_fut) = mk_usb_transfer_futures::<_, _, _, 5, 37>(
|
let (usb_fut_wrapped, in_fut, out_fut) = mk_usb_transfer_futures::<_, _, _, 5, 37>(
|
||||||
input_consistency_mode,
|
input_consistency_mode,
|
||||||
config,
|
&config,
|
||||||
&request_handler,
|
&mut request_handler,
|
||||||
builder,
|
builder,
|
||||||
&mut state,
|
&mut state,
|
||||||
|state| state,
|
GcReportBuilder::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
join(usb_fut_wrapped, join(in_fut, out_fut)).await;
|
join(usb_fut_wrapped, join(in_fut, out_fut)).await;
|
||||||
}
|
}
|
||||||
|
ControllerMode::Procon => {
|
||||||
|
let mut request_handler = ProconRequestHandler;
|
||||||
|
|
||||||
|
let (usb_fut_wrapped, in_fut, out_fut) = mk_usb_transfer_futures::<_, _, _, 64, 64>(
|
||||||
|
input_consistency_mode,
|
||||||
|
&config,
|
||||||
|
&mut request_handler,
|
||||||
|
builder,
|
||||||
|
&mut state,
|
||||||
|
ProconReportBuilder::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
join(usb_fut_wrapped, join(in_fut, out_fut)).await;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn calc_rumble_power(strength: u8) -> u16 {
|
fn calc_rumble_power(strength: u8) -> u16 {
|
||||||
if strength > 0 {
|
if strength > 0 {
|
||||||
|
@ -527,8 +555,8 @@ fn calc_rumble_power(strength: u8) -> u16 {
|
||||||
pub async fn rumble_task(
|
pub async fn rumble_task(
|
||||||
pin_rumble: PIN_25,
|
pin_rumble: PIN_25,
|
||||||
pin_brake: PIN_29,
|
pin_brake: PIN_29,
|
||||||
pwm_ch_rumble: PWM_CH4,
|
pwm_ch_rumble: PWM_SLICE4,
|
||||||
pwm_ch_brake: PWM_CH6,
|
pwm_ch_brake: PWM_SLICE6,
|
||||||
) {
|
) {
|
||||||
let mut rumble_config: embassy_rp::pwm::Config = Default::default();
|
let mut rumble_config: embassy_rp::pwm::Config = Default::default();
|
||||||
rumble_config.top = 255;
|
rumble_config.top = 255;
|
Loading…
Reference in a new issue