feat: implement "Pro-Controller" mode (#26)
Based on the pro-controller code from https://github.com/HandHeldLegend/HOJA-LIB-RP2040 Author has given their consent for this to be GPL'd: ![image](/attachments/c2551d3a-9b35-4c67-ad28-3778f9e04e29) Reviewed-on: #26
This commit is contained in:
parent
4e1af50ebd
commit
8f8d47704d
15 changed files with 1505 additions and 631 deletions
12
.changelogs/v1.2.0.md
Normal file
12
.changelogs/v1.2.0.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
This release introduces a major new feature to combat a regression introduced in Switch firmware 19.0.0. For those unaware, Switch firmware 19.0.0 breaks compatibility with GCC adapters, including NaxGCC, which advertises itself as a GCC adapter.
|
||||
|
||||
Starting with this version, you will be able to connect NaxGCC in "Pro-Controller Mode" by pressing and holding `Start` while plugging it in. This will cause the NaxGCC to advertise itself as a Nintendo Switch Pro Controller, and therefore be unaffected by the bug in the latest Switch firmware. All input consistency modes remain fully functional while in this mode, and your settings (including calibration) carry over as well.
|
||||
|
||||
While in Pro-Controller Mode, pressing `Z+Start` will act like the home button on a regular Pro Controller. Additionally, pressing `L` will press both `L` and `ZL` at the same time (since the GCC only has one left shoulder button). This is useful if you want to map things like jump (short-hop macro) or shield (prevent rolling) to it.
|
||||
|
||||
> [!NOTE]
|
||||
> As of this version, rumble will _not_ work while in Pro Controller Mode.
|
||||
|
||||
---
|
||||
|
||||
To update your firmware, plug in your controller to your computer while keeping the `A+X+Y` buttons held. Then drag & drop the `.uf2` file (found below, under Downloads) onto the storage device that appears.
|
|
@ -10,8 +10,19 @@ jobs:
|
|||
check:
|
||||
runs-on: nix-flakes
|
||||
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up attic binary cache
|
||||
uses: https://git.naxdy.org/NaxdyOrg/attic-action@v0.3
|
||||
with:
|
||||
endpoint: "${{ vars.BINARY_CACHE_URL }}"
|
||||
token: ""
|
||||
cache: "${{ vars.PUBLIC_BINARY_CACHE_NAME }}"
|
||||
skip-push: true
|
||||
|
||||
- name: Run Clippy
|
||||
run: |
|
||||
nix develop . --command cargo clippy -- -Dwarnings
|
||||
nix build .#clippy --print-build-logs -j auto
|
||||
|
|
|
@ -20,9 +20,15 @@ jobs:
|
|||
token: "${{ secrets.PUBLIC_BINARY_CACHE_AUTH_KEY }}"
|
||||
cache: "${{ vars.PUBLIC_BINARY_CACHE_NAME }}"
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run Clippy
|
||||
run: |
|
||||
nix build .#clippy --print-build-logs -j auto
|
||||
|
||||
- name: Build firmware image
|
||||
run: |
|
||||
nix build .# -o dist --print-build-logs
|
||||
|
||||
- name: (Re-)generate tag
|
||||
run: |
|
||||
git config --global user.email "noreply@naxdy.org"
|
||||
|
@ -32,6 +38,7 @@ jobs:
|
|||
git tag nightly -m "Nightly Release"
|
||||
git checkout nightly
|
||||
git push --set-upstream origin nightly --force
|
||||
|
||||
- name: Publish nightly release
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1.3.0
|
||||
with:
|
||||
|
|
163
Cargo.lock
generated
163
Cargo.lock
generated
|
@ -2,6 +2,18 @@
|
|||
# It is not intended for manual editing.
|
||||
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]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
|
@ -77,6 +89,12 @@ version = "0.13.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -109,9 +127,9 @@ checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
|
|||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -136,7 +154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||
dependencies = [
|
||||
"bare-metal",
|
||||
"bitfield",
|
||||
"bitfield 0.13.2",
|
||||
"embedded-hal 0.2.7",
|
||||
"volatile-register",
|
||||
]
|
||||
|
@ -309,7 +327,8 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
|||
|
||||
[[package]]
|
||||
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 = [
|
||||
"defmt",
|
||||
"embassy-futures",
|
||||
|
@ -325,7 +344,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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 = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
|
@ -338,7 +358,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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 = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
|
@ -349,13 +370,15 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "embassy-futures"
|
||||
version = "0.1.1"
|
||||
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||
dependencies = [
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
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 = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
|
@ -366,10 +389,12 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "embassy-net-driver"
|
||||
version = "0.2.0"
|
||||
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||
|
||||
[[package]]
|
||||
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 = [
|
||||
"embassy-futures",
|
||||
"embassy-net-driver",
|
||||
|
@ -378,7 +403,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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 = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
|
@ -403,7 +429,6 @@ dependencies = [
|
|||
"embedded-storage",
|
||||
"embedded-storage-async",
|
||||
"fixed",
|
||||
"futures",
|
||||
"nb 1.1.0",
|
||||
"pio",
|
||||
"pio-proc",
|
||||
|
@ -414,7 +439,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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 = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
|
@ -426,7 +452,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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 = [
|
||||
"cfg-if",
|
||||
"critical-section",
|
||||
|
@ -444,6 +471,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "embassy-time-driver"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||
dependencies = [
|
||||
"document-features",
|
||||
]
|
||||
|
@ -451,10 +479,12 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "embassy-time-queue-driver"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||
|
||||
[[package]]
|
||||
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 = [
|
||||
"defmt",
|
||||
"embassy-futures",
|
||||
|
@ -469,6 +499,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "embassy-usb-driver"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.naxdy.org/NaxdyOrg/embassy.git?branch=naxgcc-fw#16151cce0271573a66206aa6e85932c20bbf0c70"
|
||||
dependencies = [
|
||||
"defmt",
|
||||
]
|
||||
|
@ -630,59 +661,12 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
|
@ -696,8 +680,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
|
@ -733,6 +715,15 @@ dependencies = [
|
|||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
|
@ -768,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -875,7 +866,7 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
|||
|
||||
[[package]]
|
||||
name = "naxgcc-fw"
|
||||
version = "1.1.1"
|
||||
version = "1.2.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
|
@ -1453,15 +1444,19 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
|||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
version = "0.2.9"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||
checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usbd-hid"
|
||||
version = "0.6.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "975bd411f4a939986751ea09992a24fa47c4d25c6ed108d04b4c2999a4fd0132"
|
||||
checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"ssmarshal",
|
||||
|
@ -1471,20 +1466,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "usbd-hid-descriptors"
|
||||
version = "0.1.2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcbee8c6735e90894fba04770bc41e11fd3c5256018856e15dc4dd1e6c8a3dd1"
|
||||
checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed"
|
||||
dependencies = [
|
||||
"bitfield",
|
||||
"bitfield 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usbd-hid-macros"
|
||||
version = "0.6.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261079a9ada015fa1acac7cc73c98559f3a92585e15f508034beccf6a2ab75a2"
|
||||
checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"hashbrown 0.13.2",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
|
@ -1687,3 +1684,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
|||
dependencies = [
|
||||
"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",
|
||||
]
|
||||
|
|
41
Cargo.toml
41
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "naxgcc-fw"
|
||||
version = "1.1.1"
|
||||
version = "1.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -9,33 +9,33 @@ edition = "2021"
|
|||
embassy-time = { version = "0.3.0", features = [
|
||||
"defmt",
|
||||
"defmt-timestamp-uptime",
|
||||
], path = "lib/embassy-rs/embassy-time" }
|
||||
embassy-embedded-hal = { version = "0.1.0", features = [
|
||||
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||
embassy-embedded-hal = { version = "0.2.0", features = [
|
||||
"defmt",
|
||||
], path = "lib/embassy-rs/embassy-embedded-hal" }
|
||||
embassy-sync = { version = "0.5.0", features = [
|
||||
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||
embassy-sync = { version = "0.6.0", features = [
|
||||
"defmt",
|
||||
], path = "lib/embassy-rs/embassy-sync" }
|
||||
embassy-executor = { version = "0.5.0", features = [
|
||||
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||
embassy-executor = { version = "0.6.0", features = [
|
||||
"task-arena-size-32768",
|
||||
"arch-cortex-m",
|
||||
"executor-thread",
|
||||
"executor-interrupt",
|
||||
"defmt",
|
||||
"integrated-timers",
|
||||
], path = "lib/embassy-rs/embassy-executor" }
|
||||
embassy-rp = { version = "0.1.0", features = [
|
||||
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||
embassy-rp = { version = "0.2.0", features = [
|
||||
"defmt",
|
||||
"unstable-pac",
|
||||
"time-driver",
|
||||
"critical-section-impl",
|
||||
], path = "lib/embassy-rs/embassy-rp" }
|
||||
embassy-usb = { version = "0.1.0", features = [
|
||||
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||
embassy-usb = { version = "0.3.0", features = [
|
||||
"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 = [
|
||||
"defmt",
|
||||
], path = "lib/embassy-rs/embassy-futures" }
|
||||
], git = "https://git.naxdy.org/NaxdyOrg/embassy.git", branch = "naxgcc-fw" }
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
fixed = "1.23.1"
|
||||
|
@ -48,7 +48,7 @@ libm = { version = "0.2.8" }
|
|||
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
||||
cortex-m-rt = "0.7.0"
|
||||
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"
|
||||
rand = { version = "0.8.5", default-features = false }
|
||||
|
||||
|
@ -79,14 +79,14 @@ overflow-checks = false
|
|||
codegen-units = 8
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
opt-level = 0
|
||||
opt-level = 3
|
||||
overflow-checks = false
|
||||
|
||||
[profile.release.build-override]
|
||||
codegen-units = 8
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
opt-level = 0
|
||||
opt-level = 3
|
||||
overflow-checks = false
|
||||
|
||||
# cargo test
|
||||
|
@ -106,12 +106,3 @@ debug-assertions = false
|
|||
incremental = false
|
||||
lto = 'fat'
|
||||
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" }
|
||||
|
|
72
flake.lock
72
flake.lock
|
@ -1,22 +1,5 @@
|
|||
{
|
||||
"nodes": {
|
||||
"embassy-rs-patched": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1710754402,
|
||||
"narHash": "sha256-HyTw5VQXlSqz9UOq0Dc6G/NWNzQOPXf3PNWffMkfLC4=",
|
||||
"ref": "naxgcc-fw",
|
||||
"rev": "2ee4657727b9679998d941de00b43e1754f570bf",
|
||||
"revCount": 6754,
|
||||
"type": "git",
|
||||
"url": "https://gitea@git.naxdy.org/NaxdyOrg/embassy"
|
||||
},
|
||||
"original": {
|
||||
"ref": "naxgcc-fw",
|
||||
"type": "git",
|
||||
"url": "https://gitea@git.naxdy.org/NaxdyOrg/embassy"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
|
@ -35,24 +18,6 @@
|
|||
"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": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
@ -75,27 +40,27 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1710283656,
|
||||
"narHash": "sha256-nI+AOy4uK6jLGBi9nsbHjL1EdSIzoo8oa+9oeVhbyFc=",
|
||||
"lastModified": 1728740863,
|
||||
"narHash": "sha256-u+rxA79a0lyhG+u+oPBRtTDtzz8kvkc9a6SWSt9ekVc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "51063ed4f2343a59fdeebb279bb81d87d453942b",
|
||||
"rev": "a3f9ad65a0bf298ed5847629a57808b97e6e8077",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-23.11",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1706487304,
|
||||
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
|
||||
"lastModified": 1718428119,
|
||||
"narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
|
||||
"rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -107,7 +72,6 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"embassy-rs-patched": "embassy-rs-patched",
|
||||
"flake-utils": "flake-utils",
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs",
|
||||
|
@ -116,15 +80,14 @@
|
|||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710382258,
|
||||
"narHash": "sha256-2FW1q+o34VBweYQiEkRaSEkNMq3ecrn83VzETeGiVbY=",
|
||||
"lastModified": 1728700003,
|
||||
"narHash": "sha256-Ox1pvEHxLK6lAdaKQW21Zvk65SPDag+cD8YA444R/og=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "8ce81e71ab04a7e906fae62da086d6ee5d6cfc21",
|
||||
"rev": "fc1e58ebabe0cef4442eedea07556ff0c9eafcfe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -147,21 +110,6 @@
|
|||
"repo": "default",
|
||||
"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",
|
||||
|
|
42
flake.nix
42
flake.nix
|
@ -2,17 +2,12 @@
|
|||
description = "Firmware for the NaxGCC";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-23.11";
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-24.05";
|
||||
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
embassy-rs-patched = {
|
||||
url = "git+https://gitea@git.naxdy.org/NaxdyOrg/embassy?ref=naxgcc-fw";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
naersk = {
|
||||
url = "github:nmattia/naersk";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
@ -25,7 +20,6 @@
|
|||
, rust-overlay
|
||||
, flake-utils
|
||||
, naersk
|
||||
, embassy-rs-patched
|
||||
}: (flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
|
@ -51,12 +45,6 @@
|
|||
};
|
||||
|
||||
CARGO_BUILD_TARGET = "thumbv6m-none-eabi";
|
||||
|
||||
prepCmd = ''
|
||||
mkdir -p lib
|
||||
rm lib/embassy-rs || true
|
||||
ln -s "${embassy-rs-patched}" lib/embassy-rs
|
||||
'';
|
||||
in
|
||||
{
|
||||
packages.default = self.packages.${system}.naxgcc-fw-uf2;
|
||||
|
@ -66,20 +54,26 @@
|
|||
${pkgs.elf2uf2-rs}/bin/elf2uf2-rs ${self.packages.${system}.naxgcc-fw}/bin/${self.packages.${system}.naxgcc-fw.pname} $out/bin/${self.packages.${system}.naxgcc-fw.pname}.uf2
|
||||
'';
|
||||
|
||||
packages.naxgcc-fw = naersk_lib.buildPackage {
|
||||
pname = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.name;
|
||||
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
|
||||
packages.naxgcc-fw = pkgs.callPackage
|
||||
({ mode ? "build" }: naersk_lib.buildPackage {
|
||||
pname = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.name;
|
||||
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
|
||||
|
||||
prePatch = prepCmd;
|
||||
inherit mode;
|
||||
|
||||
src = self;
|
||||
src = self;
|
||||
|
||||
cargoBuildOptions = _orig: _orig ++ [
|
||||
"--target=${CARGO_BUILD_TARGET}"
|
||||
];
|
||||
cargoBuildOptions = _orig: _orig ++ [
|
||||
"--target=${CARGO_BUILD_TARGET}"
|
||||
];
|
||||
|
||||
# if a tree falls in the forest and no one is around to hear it, does it make a sound?
|
||||
DEFMT_LOG = "off";
|
||||
# if a tree falls in the forest and no one is around to hear it, does it make a sound?
|
||||
DEFMT_LOG = "off";
|
||||
})
|
||||
{ };
|
||||
|
||||
packages.clippy = self.packages.${system}.naxgcc-fw.override {
|
||||
mode = "clippy";
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
|
@ -92,8 +86,6 @@
|
|||
DEFMT_LOG = "debug";
|
||||
|
||||
inherit CARGO_BUILD_TARGET;
|
||||
|
||||
shellHook = prepCmd;
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
|
108
src/config.rs
108
src/config.rs
|
@ -16,8 +16,8 @@ use packed_struct::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
gcc_hid::{Buttons1, Buttons2, MUTEX_INPUT_CONSISTENCY_MODE, SIGNAL_CHANGE_RUMBLE_STRENGTH},
|
||||
helpers::{PackedFloat, ToPackedFloatArray, ToRegularArray, XyValuePair},
|
||||
hid::gcc::{GcButtons1, GcButtons2, GcState},
|
||||
input::{
|
||||
read_ext_adc, Stick, StickAxis, FLOAT_ORIGIN, SPI_ACS_SHARED, SPI_CCS_SHARED, SPI_SHARED,
|
||||
},
|
||||
|
@ -26,6 +26,7 @@ use crate::{
|
|||
LinearizedCalibration, NotchCalibration, NotchStatus, CALIBRATION_ORDER,
|
||||
NOTCH_ADJUSTMENT_ORDER, NO_OF_ADJ_NOTCHES, NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES,
|
||||
},
|
||||
usb_comms::{MUTEX_INPUT_CONSISTENCY_MODE, SIGNAL_CHANGE_RUMBLE_STRENGTH},
|
||||
ADDR_OFFSET, FLASH_SIZE,
|
||||
};
|
||||
|
||||
|
@ -36,7 +37,7 @@ use embassy_sync::{
|
|||
};
|
||||
use embassy_time::Timer;
|
||||
|
||||
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
|
||||
use crate::input::CHANNEL_GCC_STATE;
|
||||
|
||||
/// Whether we are currently calibrating the sticks. Updates are dispatched when the status changes.
|
||||
/// Initial status is assumed to be false.
|
||||
|
@ -78,7 +79,7 @@ const MAX_ANALOG_SCALER: u8 = 125;
|
|||
/// a certain mode.
|
||||
#[derive(Default, Debug, Clone, Format)]
|
||||
pub struct OverrideGcReportInstruction {
|
||||
pub report: GcReport,
|
||||
pub report: GcState,
|
||||
pub duration_ms: u64,
|
||||
}
|
||||
|
||||
|
@ -563,6 +564,15 @@ pub enum InputConsistencyMode {
|
|||
PC = 3,
|
||||
}
|
||||
|
||||
/// Not saved, but set upon plugging in the controller.
|
||||
#[derive(Debug, Clone, Copy, Format, PrimitiveEnum_u8, PartialEq, Eq)]
|
||||
pub enum ControllerMode {
|
||||
/// Advertise itself as a GCC adapter with 1 controller (itself) connected.
|
||||
GcAdapter = 0,
|
||||
/// Pretend to be a Nintendo Switch Pro Controller connected via USB.
|
||||
Procon = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Format, PackedStruct)]
|
||||
#[packed_struct(endian = "msb")]
|
||||
pub struct ControllerConfig {
|
||||
|
@ -637,6 +647,8 @@ impl ControllerConfig {
|
|||
/// Trait for providing button presses, used in the calibration process.
|
||||
trait ButtonPressProvider {
|
||||
/// 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);
|
||||
|
||||
/// Wait for a single button release.
|
||||
|
@ -670,7 +682,7 @@ trait 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) {
|
||||
loop {
|
||||
|
@ -770,7 +782,7 @@ impl<'a, T: RawMutex, const I: usize, const J: usize, const K: usize> ButtonPres
|
|||
}
|
||||
|
||||
pub fn is_awaitable_button_pressed(
|
||||
report: &GcReport,
|
||||
report: &GcState,
|
||||
button_to_wait_for: &AwaitableButtons,
|
||||
) -> bool {
|
||||
match button_to_wait_for {
|
||||
|
@ -1136,7 +1148,7 @@ async fn configuration_main_loop<
|
|||
>(
|
||||
current_config: &ControllerConfig,
|
||||
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 {
|
||||
let mut final_config = current_config.clone();
|
||||
let config_options = [
|
||||
|
@ -1194,15 +1206,15 @@ async fn configuration_main_loop<
|
|||
// exit
|
||||
0 => {
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1222,15 +1234,15 @@ async fn configuration_main_loop<
|
|||
// calibrate lstick
|
||||
1 => {
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1251,15 +1263,15 @@ async fn configuration_main_loop<
|
|||
// calibrate rstick
|
||||
2 => {
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1310,15 +1322,15 @@ async fn configuration_main_loop<
|
|||
.clamp(-ABS_MAX_SNAPBACK, ABS_MAX_SNAPBACK);
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1396,15 +1408,15 @@ async fn configuration_main_loop<
|
|||
.clamp(0, MAX_WAVESHAPING) as u8;
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1482,15 +1494,15 @@ async fn configuration_main_loop<
|
|||
.clamp(0, MAX_SMOOTHING) as u8;
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1557,15 +1569,15 @@ async fn configuration_main_loop<
|
|||
.clamp(-1, MAX_CARDINAL_SNAP);
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1613,15 +1625,15 @@ async fn configuration_main_loop<
|
|||
as u8;
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1661,16 +1673,16 @@ async fn configuration_main_loop<
|
|||
SIGNAL_CHANGE_RUMBLE_STRENGTH.signal(*to_adjust);
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
button_z: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1697,15 +1709,15 @@ async fn configuration_main_loop<
|
|||
};
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1731,15 +1743,15 @@ async fn configuration_main_loop<
|
|||
// display waveshaping values on both sticks
|
||||
38 => {
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1757,15 +1769,15 @@ async fn configuration_main_loop<
|
|||
// display stick smoothing values on both sticks
|
||||
39 => {
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1783,15 +1795,15 @@ async fn configuration_main_loop<
|
|||
// display snapback values on both sticks
|
||||
40 => {
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_r: true,
|
||||
button_l: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
@ -1854,15 +1866,15 @@ pub async fn config_task(mut flash: Flash<'static, FLASH, Async, FLASH_SIZE>) {
|
|||
info!("Entering config mode.");
|
||||
|
||||
override_gcc_state_and_wait(&OverrideGcReportInstruction {
|
||||
report: GcReport {
|
||||
report: GcState {
|
||||
trigger_r: 255,
|
||||
trigger_l: 255,
|
||||
buttons_2: Buttons2 {
|
||||
buttons_2: GcButtons2 {
|
||||
button_l: true,
|
||||
button_r: true,
|
||||
..Default::default()
|
||||
},
|
||||
buttons_1: Buttons1 {
|
||||
buttons_1: GcButtons1 {
|
||||
button_x: true,
|
||||
button_y: true,
|
||||
button_a: true,
|
||||
|
|
198
src/hid/gcc.rs
Normal file
198
src/hid/gcc.rs
Normal file
|
@ -0,0 +1,198 @@
|
|||
use defmt::{info, trace, Format};
|
||||
use embassy_usb::{
|
||||
class::hid::{ReportId, RequestHandler},
|
||||
control::OutResponse,
|
||||
};
|
||||
|
||||
use crate::usb_comms::{HidReportBuilder, SIGNAL_RUMBLE};
|
||||
use packed_struct::{derive::PackedStruct, PackedStruct};
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const GCC_REPORT_DESCRIPTOR: &[u8] = &[
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x05, // Usage (Game Pad)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0xA1, 0x03, // Collection (Report)
|
||||
0x85, 0x11, // Report ID (17)
|
||||
0x19, 0x00, // Usage Minimum (Undefined)
|
||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x05, // Report Count (5)
|
||||
0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0xC0, // End Collection
|
||||
0xA1, 0x03, // Collection (Report)
|
||||
0x85, 0x21, // Report ID (33)
|
||||
0x05, 0x00, // Usage Page (Undefined)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0xFF, // Logical Maximum (-1)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
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, 0x01, // Usage Minimum (0x01)
|
||||
0x29, 0x08, // Usage Maximum (0x08)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x32, // Usage (Z)
|
||||
0x09, 0x33, // Usage (Rx)
|
||||
0x09, 0x34, // Usage (Ry)
|
||||
0x09, 0x35, // Usage (Rz)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x06, // Report Count (6)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0xC0, // End Collection
|
||||
0xA1, 0x03, // Collection (Report)
|
||||
0x85, 0x13, // Report ID (19)
|
||||
0x19, 0x00, // Usage Minimum (Undefined)
|
||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||
pub struct GcButtons1 {
|
||||
#[packed_field(bits = "0")]
|
||||
pub button_a: bool,
|
||||
#[packed_field(bits = "1")]
|
||||
pub button_b: bool,
|
||||
#[packed_field(bits = "2")]
|
||||
pub button_x: bool,
|
||||
#[packed_field(bits = "3")]
|
||||
pub button_y: bool,
|
||||
#[packed_field(bits = "4")]
|
||||
pub dpad_left: bool,
|
||||
#[packed_field(bits = "5")]
|
||||
pub dpad_right: bool,
|
||||
#[packed_field(bits = "6")]
|
||||
pub dpad_down: bool,
|
||||
#[packed_field(bits = "7")]
|
||||
pub dpad_up: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||
pub struct GcButtons2 {
|
||||
#[packed_field(bits = "0")]
|
||||
pub button_start: bool,
|
||||
#[packed_field(bits = "1")]
|
||||
pub button_z: bool,
|
||||
#[packed_field(bits = "2")]
|
||||
pub button_r: bool,
|
||||
#[packed_field(bits = "3")]
|
||||
pub button_l: bool,
|
||||
#[packed_field(bits = "4..=7")]
|
||||
pub blank1: u8,
|
||||
}
|
||||
|
||||
///
|
||||
/// Struct representing the controller state. Used for HID communications in
|
||||
/// GCC adapter mode, as well as for the internal representation of the controller.
|
||||
///
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct, Format)]
|
||||
#[packed_struct(bit_numbering = "msb0", size_bytes = "8")]
|
||||
pub struct GcState {
|
||||
#[packed_field(bits = "0..=7")]
|
||||
pub buttons_1: GcButtons1,
|
||||
#[packed_field(bits = "8..=15")]
|
||||
pub buttons_2: GcButtons2,
|
||||
#[packed_field(bits = "16..=23")]
|
||||
pub stick_x: u8,
|
||||
#[packed_field(bits = "24..=31")]
|
||||
pub stick_y: u8,
|
||||
#[packed_field(bits = "32..=39")]
|
||||
pub cstick_x: u8,
|
||||
#[packed_field(bits = "40..=47")]
|
||||
pub cstick_y: u8,
|
||||
#[packed_field(bits = "48..=55")]
|
||||
pub trigger_l: u8,
|
||||
#[packed_field(bits = "56..=63")]
|
||||
pub trigger_r: u8,
|
||||
}
|
||||
|
||||
impl Default for GcState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buttons_1: GcButtons1::default(),
|
||||
buttons_2: GcButtons2::default(),
|
||||
stick_x: 127,
|
||||
stick_y: 127,
|
||||
cstick_x: 127,
|
||||
cstick_y: 127,
|
||||
trigger_l: 0,
|
||||
trigger_r: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GcReportBuilder {
|
||||
gc_first: bool,
|
||||
}
|
||||
|
||||
impl HidReportBuilder<37> for GcReportBuilder {
|
||||
async fn get_hid_report(&mut self, state: &GcState) -> [u8; 37] {
|
||||
let mut buffer = [0u8; 37];
|
||||
|
||||
buffer[0] = 0x21;
|
||||
buffer[1] |= 0x14;
|
||||
|
||||
let data = state.pack().expect("Failed to pack GC input data");
|
||||
|
||||
if !self.gc_first {
|
||||
buffer[1] |= 0x04;
|
||||
buffer[10] |= 0x04;
|
||||
buffer[19] |= 0x04;
|
||||
buffer[28] |= 0x04;
|
||||
self.gc_first = true;
|
||||
} else {
|
||||
// controller in "port 1"
|
||||
buffer[2..=9].copy_from_slice(&data);
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GccRequestHandler;
|
||||
|
||||
impl RequestHandler for GccRequestHandler {
|
||||
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);
|
||||
|
||||
if data.len() > 1 {
|
||||
SIGNAL_RUMBLE.signal((data[1] & 0x01) != 0);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
2
src/hid/mod.rs
Normal file
2
src/hid/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod gcc;
|
||||
pub mod procon;
|
762
src/hid/procon.rs
Normal file
762
src/hid/procon.rs
Normal file
|
@ -0,0 +1,762 @@
|
|||
///
|
||||
/// The majority of the logic in this file is derived from HOJA-LIB-RP2040
|
||||
/// https://github.com/HandHeldLegend/HOJA-LIB-RP2040
|
||||
///
|
||||
/// The original author gave their consent for this to be included in the NaxGCC firmware,
|
||||
/// and for this file to be distributed under the GPLv3, see https://git.naxdy.org/NaxdyOrg/NaxGCC-FW/pulls/26
|
||||
///
|
||||
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::HidReportBuilder;
|
||||
|
||||
use super::gcc::GcState;
|
||||
|
||||
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)
|
||||