Make keys light up when pressed

This commit is contained in:
2023-04-26 18:39:47 +02:00
parent 2fc050eb4f
commit 4f59a59693
9 changed files with 245 additions and 95 deletions

160
Cargo.lock generated
View File

@ -44,17 +44,6 @@ dependencies = [
"critical-section", "critical-section",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -115,6 +104,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -252,7 +247,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]] [[package]]
name = "embassy-cortex-m" name = "embassy-cortex-m"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"atomic-polyfill 1.0.2", "atomic-polyfill 1.0.2",
"cfg-if", "cfg-if",
@ -267,7 +262,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-embedded-hal" name = "embassy-embedded-hal"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"embassy-sync", "embassy-sync",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
@ -281,7 +276,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-executor" name = "embassy-executor"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"atomic-polyfill 1.0.2", "atomic-polyfill 1.0.2",
"cfg-if", "cfg-if",
@ -296,7 +291,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-futures" name = "embassy-futures"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"log", "log",
] ]
@ -304,7 +299,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-hal-common" name = "embassy-hal-common"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
@ -312,7 +307,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-macros" name = "embassy-macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
@ -323,12 +318,12 @@ dependencies = [
[[package]] [[package]]
name = "embassy-net-driver" name = "embassy-net-driver"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
[[package]] [[package]]
name = "embassy-net-driver-channel" name = "embassy-net-driver-channel"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"embassy-futures", "embassy-futures",
"embassy-net-driver", "embassy-net-driver",
@ -338,7 +333,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-rp" name = "embassy-rp"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"atomic-polyfill 1.0.2", "atomic-polyfill 1.0.2",
"cfg-if", "cfg-if",
@ -372,7 +367,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-sync" name = "embassy-sync"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"critical-section", "critical-section",
@ -385,7 +380,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-time" name = "embassy-time"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"atomic-polyfill 1.0.2", "atomic-polyfill 1.0.2",
"cfg-if", "cfg-if",
@ -400,7 +395,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-usb" name = "embassy-usb"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"embassy-futures", "embassy-futures",
"embassy-net-driver-channel", "embassy-net-driver-channel",
@ -414,12 +409,12 @@ dependencies = [
[[package]] [[package]]
name = "embassy-usb-driver" name = "embassy-usb-driver"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
[[package]] [[package]]
name = "embassy-usb-logger" name = "embassy-usb-logger"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/embassy-rs/embassy.git#4bfe6248936bf9d12185ada7f43c938d87f99841" source = "git+https://github.com/embassy-rs/embassy.git#732614579b86c2a63856b6e8e2622e09322600a7"
dependencies = [ dependencies = [
"embassy-futures", "embassy-futures",
"embassy-sync", "embassy-sync",
@ -511,6 +506,27 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]] [[package]]
name = "fixedbitset" name = "fixedbitset"
version = "0.4.2" version = "0.4.2"
@ -638,12 +654,9 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
@ -653,14 +666,37 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.2" version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
] ]
[[package]]
name = "io-lifetimes"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -672,15 +708,15 @@ dependencies = [
[[package]] [[package]]
name = "lalrpop" name = "lalrpop"
version = "0.19.8" version = "0.19.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87"
dependencies = [ dependencies = [
"ascii-canvas", "ascii-canvas",
"atty",
"bit-set", "bit-set",
"diff", "diff",
"ena", "ena",
"is-terminal",
"itertools", "itertools",
"lalrpop-util", "lalrpop-util",
"petgraph", "petgraph",
@ -695,9 +731,9 @@ dependencies = [
[[package]] [[package]]
name = "lalrpop-util" name = "lalrpop-util"
version = "0.19.8" version = "0.19.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd"
dependencies = [ dependencies = [
"regex", "regex",
] ]
@ -714,6 +750,12 @@ version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.9"
@ -942,9 +984,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.52" version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -986,9 +1028,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.1" version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -997,9 +1039,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.28" version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "rgb" name = "rgb"
@ -1048,6 +1090,20 @@ dependencies = [
"semver 1.0.17", "semver 1.0.17",
] ]
[[package]]
name = "rustix"
version = "0.36.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.12" version = "1.0.12"
@ -1083,22 +1139,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.157" version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.157" version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.2", "syn 2.0.10",
] ]
[[package]] [[package]]
@ -1197,9 +1253,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.2" version = "2.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1259,7 +1315,7 @@ dependencies = [
[[package]] [[package]]
name = "tgnt" name = "tgnt"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.nubo.sh/hulthe/tgnt.git#eb18dc95902e5698e6a506798559d367d7fd7ced" source = "git+https://git.nubo.sh/hulthe/tgnt.git#643f75cf0a33208ec18c38ea7d9ccf06f344ff35"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -1281,7 +1337,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.2", "syn 2.0.10",
] ]
[[package]] [[package]]

View File

@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) {
let _neopixel_power = Output::new(board.neopixel_power, Level::High); let _neopixel_power = Output::new(board.neopixel_power, Level::High);
let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel.degrade()); let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel.degrade());
let mut neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade()); let neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await; neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
usb::setup_logger_and_keyboard(board.USB).await; usb::setup_logger_and_keyboard(board.USB).await;
@ -44,7 +44,6 @@ async fn main(_spawner: Spawner) {
}; };
let keyboard = KeyboardConfig { let keyboard = KeyboardConfig {
layers,
pins: [ pins: [
// row 1 // row 1
board.d24.degrade(), board.d24.degrade(),
@ -69,20 +68,17 @@ async fn main(_spawner: Spawner) {
board.scl.degrade(), board.scl.degrade(),
board.sda.degrade(), board.sda.degrade(),
], ],
// the index of the LEDs is different than the switch index.
// each number is the index of the LED for the switch of that index.
led_map: [4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 14, 13, 12, 11, 10, 15, 16, 17],
led_driver: neopixels_d5,
layers,
}; };
keyboard.create().await; keyboard.create().await;
for w in 0usize.. { for w in 0usize.. {
neopixel.write(&[wheel(w as u8)]).await; neopixel.write(&[wheel(w as u8)]).await;
neopixels_d5
.write(&[
wheel((w + 50) as u8),
wheel((w + 100) as u8),
wheel((w + 150) as u8),
wheel((w + 200) as u8),
])
.await;
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(10)).await;
} }
} }

View File

@ -2,21 +2,39 @@ use core::sync::atomic::{AtomicU16, Ordering};
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio::{AnyPin, Input, Pin, Pull}; use embassy_rp::{
gpio::{AnyPin, Input, Pin, Pull},
pio::PioInstanceBase,
};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use futures::{select_biased, FutureExt}; use futures::{select_biased, FutureExt};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use static_cell::StaticCell;
use tgnt::{button::Button, layer::Layer}; use tgnt::{button::Button, layer::Layer};
use crate::usb::keyboard::KB_REPORT; use crate::{
lights::Lights,
static CURRENT_LAYER: AtomicU16 = AtomicU16::new(0); usb::keyboard::KB_REPORT,
ws2812::{Rgb, Ws2812},
};
pub struct KeyboardConfig { pub struct KeyboardConfig {
/// Array of input pins of each switch
pub pins: [AnyPin; SWITCH_COUNT], pub pins: [AnyPin; SWITCH_COUNT],
/// Array of LED indices of each switch
pub led_map: [usize; SWITCH_COUNT],
pub led_driver: Ws2812<PioInstanceBase<1>>,
pub layers: Vec<Layer>, pub layers: Vec<Layer>,
} }
struct State {
current_layer: AtomicU16,
layers: &'static [Layer],
/// Array of LED indices of each switch
led_map: [usize; SWITCH_COUNT],
lights: Lights<PioInstanceBase<1>, SWITCH_COUNT>,
}
impl KeyboardConfig { impl KeyboardConfig {
pub async fn create(self) { pub async fn create(self) {
let spawner = Spawner::for_current_executor().await; let spawner = Spawner::for_current_executor().await;
@ -31,8 +49,15 @@ impl KeyboardConfig {
self.layers.len() self.layers.len()
); );
let layers = Box::leak(self.layers.into_boxed_slice()); static STATE: StaticCell<State> = StaticCell::new();
for (i, layer) in layers.iter().enumerate() { let state = STATE.init_with(|| State {
current_layer: AtomicU16::new(0),
layers: Box::leak(self.layers.into_boxed_slice()),
lights: Lights::new(self.led_driver),
led_map: self.led_map,
});
for (i, layer) in state.layers.iter().enumerate() {
if layer.buttons.len() != SWITCH_COUNT { if layer.buttons.len() != SWITCH_COUNT {
warn!( warn!(
"layer {i} defines {} buttons, but there are {SWITCH_COUNT} switches", "layer {i} defines {} buttons, but there are {SWITCH_COUNT} switches",
@ -42,7 +67,7 @@ impl KeyboardConfig {
} }
for (i, pin) in self.pins.into_iter().enumerate() { for (i, pin) in self.pins.into_iter().enumerate() {
if spawner.spawn(switch_task(i, pin, layers)).is_err() { if spawner.spawn(switch_task(i, pin, state)).is_err() {
error!("failed to spawn switch task, pool_size mismatch?"); error!("failed to spawn switch task, pool_size mismatch?");
break; break;
} }
@ -50,12 +75,12 @@ impl KeyboardConfig {
} }
} }
const MOD_TAP_TIME: Duration = Duration::from_millis(100); const MOD_TAP_TIME: Duration = Duration::from_millis(150);
const SWITCH_COUNT: usize = 18; const SWITCH_COUNT: usize = 18;
/// Task for monitoring a single switch pin, and handling button presses. /// Task for monitoring a single switch pin, and handling button presses.
#[embassy_executor::task(pool_size = 18)] #[embassy_executor::task(pool_size = 18)]
async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -> ! { async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> ! {
let _pin_nr = pin.pin(); let _pin_nr = pin.pin();
let mut pin = Input::new(pin, Pull::Up); let mut pin = Input::new(pin, Pull::Up);
loop { loop {
@ -65,15 +90,15 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -
// TODO: do we need debouncing? // TODO: do we need debouncing?
// get current layer // get current layer
let mut current_layer = CURRENT_LAYER.load(Ordering::Relaxed); let mut current_layer = state.current_layer.load(Ordering::Relaxed);
let layer_count = layers.len() as u16; let layer_count = state.layers.len() as u16;
if current_layer >= layer_count { if current_layer >= layer_count {
error!("current layer was out of bounds for some reason ({current_layer})"); error!("current layer was out of bounds for some reason ({current_layer})");
current_layer = 0; current_layer = 0;
} }
let Some(Layer { buttons }) = layers.get(usize::from(current_layer)) else { let Some(Layer { buttons }) = state.layers.get(usize::from(current_layer)) else {
error!("current layer was out of bounds for some reason ({current_layer})"); error!("current layer was out of bounds for some reason ({current_layer})");
CURRENT_LAYER.store(0, Ordering::Relaxed); state.current_layer.store(0, Ordering::Relaxed);
continue; continue;
}; };
@ -90,50 +115,69 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -
debug!("switch {switch_num} button {button:?} released"); debug!("switch {switch_num} button {button:?} released");
}; };
let set_led = |color: Rgb| {
let led_num = state.led_map.get(switch_num).copied();
move |leds: &mut [Rgb; SWITCH_COUNT]| {
if let Some(led) = led_num.and_then(|i| leds.get_mut(i)) {
*led = color;
}
}
};
match button { match button {
&Button::Key(key) => { &Button::Key(key) => {
KB_REPORT.lock().await.press_key(key); KB_REPORT.lock().await.press_key(key);
state.lights.update(set_led(Rgb::new(0, 150, 0))).await;
wait_for_release.await; wait_for_release.await;
KB_REPORT.lock().await.release_key(key); KB_REPORT.lock().await.release_key(key);
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
continue; continue;
} }
&Button::Mod(modifier) => { &Button::Mod(modifier) => {
KB_REPORT.lock().await.press_modifier(modifier); KB_REPORT.lock().await.press_modifier(modifier);
state.lights.update(set_led(Rgb::new(100, 100, 0))).await;
wait_for_release.await; wait_for_release.await;
KB_REPORT.lock().await.release_modifier(modifier); KB_REPORT.lock().await.release_modifier(modifier);
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
continue; continue;
} }
&Button::ModTap { keycode, modifier } => { &Button::ModTap(key, modifier) => {
state.lights.update(set_led(Rgb::new(100, 100, 0))).await;
select_biased! { select_biased! {
_ = Timer::after(MOD_TAP_TIME).fuse() => { _ = Timer::after(MOD_TAP_TIME).fuse() => {
KB_REPORT.lock().await.press_modifier(modifier); KB_REPORT.lock().await.press_modifier(modifier);
state.lights.update(set_led(Rgb::new(0, 0, 150))).await;
pin.wait_for_high().await; pin.wait_for_high().await;
KB_REPORT.lock().await.release_modifier(modifier); KB_REPORT.lock().await.release_modifier(modifier);
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
debug!("switch {switch_num} button {button:?} released"); debug!("switch {switch_num} button {button:?} released");
continue; continue;
} }
_ = wait_for_release.fuse() => { _ = wait_for_release.fuse() => {
KB_REPORT.lock().await.press_key(keycode); KB_REPORT.lock().await.press_key(key);
state.lights.update(set_led(Rgb::new(0, 150, 0))).await;
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(10)).await;
KB_REPORT.lock().await.release_key(keycode); KB_REPORT.lock().await.release_key(key);
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
continue; continue;
} }
} }
} }
Button::NextLayer => { Button::NextLayer => {
let next_layer = (current_layer + 1) % layer_count; let next_layer = (current_layer + 1) % layer_count;
CURRENT_LAYER.store(next_layer, Ordering::Relaxed); state.current_layer.store(next_layer, Ordering::Relaxed);
debug!("switched to layer {next_layer}"); debug!("switched to layer {next_layer}");
} }
Button::PrevLayer => { Button::PrevLayer => {
let prev_layer = current_layer.checked_sub(1).unwrap_or(layer_count - 1); let prev_layer = current_layer.checked_sub(1).unwrap_or(layer_count - 1);
CURRENT_LAYER.store(prev_layer, Ordering::Relaxed); state.current_layer.store(prev_layer, Ordering::Relaxed);
debug!("switched to layer {prev_layer}"); debug!("switched to layer {prev_layer}");
} }
Button::None => {} Button::None => {}
} }
wait_for_release.await; wait_for_release.await;
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
} }
} }

View File

@ -6,6 +6,7 @@ extern crate alloc;
pub mod allocator; pub mod allocator;
pub mod board; pub mod board;
pub mod keyboard; pub mod keyboard;
pub mod lights;
pub mod neopixel; pub mod neopixel;
pub mod panic_handler; pub mod panic_handler;
pub mod usb; pub mod usb;

41
src/lights.rs Normal file
View File

@ -0,0 +1,41 @@
use crate::ws2812::Ws2812;
use embassy_rp::pio::PioInstance;
use embassy_sync::mutex::Mutex;
use crate::{util::CS, ws2812::Rgb};
pub struct Lights<P: PioInstance, const N: usize> {
state: Mutex<CS, State<P, N>>,
}
struct State<P: PioInstance, const N: usize> {
colors: [Rgb; N],
driver: Ws2812<P>,
}
impl<P: PioInstance, const N: usize> Lights<P, N> {
pub const fn new(driver: Ws2812<P>) -> Self {
Lights {
state: Mutex::new(State {
colors: [Rgb::new(0, 0, 0); N],
driver,
}),
}
}
pub fn colors_mut(&mut self) -> &[Rgb; N] {
&self.state.get_mut().colors
}
/// Run a function to update the colors, and then immediately refresh the LEDs.
pub async fn update(&self, f: impl FnOnce(&mut [Rgb; N])) {
let State { colors, driver } = &mut *self.state.lock().await;
f(colors);
driver.write(colors).await
}
/// Update the LEDs with the currently set colors.
pub async fn refresh(&self) {
self.update(|_| ()).await;
}
}

View File

@ -33,7 +33,9 @@ pub async fn setup_logger_and_keyboard(usb: USB) {
} }
pub fn builder(usb: USB) -> Builder<'static, Driver<'static, USB>> { pub fn builder(usb: USB) -> Builder<'static, Driver<'static, USB>> {
let state = STATE.init(State { // calling init here can't panic because this function can't be called
// twice since we are taking ownership of the only USB peripheral.
let state = STATE.init_with(|| State {
device_descriptor: [0; 256], device_descriptor: [0; 256],
config_descriptor: [0; 256], config_descriptor: [0; 256],
bos_descriptor: [0; 256], bos_descriptor: [0; 256],

View File

@ -15,7 +15,6 @@ use static_cell::StaticCell;
pub const BUFFER_SIZE: usize = 16 * 1024; pub const BUFFER_SIZE: usize = 16 * 1024;
static BUFFER: Pipe<CS, BUFFER_SIZE> = Pipe::new(); static BUFFER: Pipe<CS, BUFFER_SIZE> = Pipe::new();
static STATE: StaticCell<cdc_acm::State<'static>> = StaticCell::new();
struct UsbLogger; struct UsbLogger;
@ -23,11 +22,12 @@ pub async fn setup(usb_builder: &mut Builder<'static, Driver<'static, USB>>) {
unsafe { unsafe {
static LOGGER: UsbLogger = UsbLogger; static LOGGER: UsbLogger = UsbLogger;
log::set_logger_racy(&LOGGER).unwrap(); log::set_logger_racy(&LOGGER).unwrap();
log::set_max_level(log::LevelFilter::Debug);
} }
log::set_max_level(log::LevelFilter::Debug);
let spawner = Spawner::for_current_executor().await; let spawner = Spawner::for_current_executor().await;
static STATE: StaticCell<cdc_acm::State<'static>> = StaticCell::new();
let state = STATE.init(cdc_acm::State::new()); let state = STATE.init(cdc_acm::State::new());
let class = CdcAcmClass::new(usb_builder, state, MAX_PACKET_SIZE as u16); let class = CdcAcmClass::new(usb_builder, state, MAX_PACKET_SIZE as u16);
@ -35,10 +35,6 @@ pub async fn setup(usb_builder: &mut Builder<'static, Driver<'static, USB>>) {
spawner.must_spawn(log_task(class)); spawner.must_spawn(log_task(class));
} }
//pub async fn print(s: &str) {
// BUFFER.writer().write_all(s.as_bytes()).await.ok(/* infallible */);
//}
#[embassy_executor::task] #[embassy_executor::task]
async fn log_task(mut class: CdcAcmClass<'static, Driver<'static, USB>>) { async fn log_task(mut class: CdcAcmClass<'static, Driver<'static, USB>>) {
let mut buf = [0u8; MAX_PACKET_SIZE as usize]; let mut buf = [0u8; MAX_PACKET_SIZE as usize];

View File

@ -15,13 +15,17 @@ pub async fn stall() -> ! {
// The colours are a transition r - g - b - back to r. // The colours are a transition r - g - b - back to r.
pub fn wheel(mut wheel_pos: u8) -> Rgb { pub fn wheel(mut wheel_pos: u8) -> Rgb {
wheel_pos = 255 - wheel_pos; wheel_pos = 255 - wheel_pos;
if wheel_pos < 85 { let rgb = if wheel_pos < 85 {
return Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3); Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3)
} } else if wheel_pos < 170 {
if wheel_pos < 170 {
wheel_pos -= 85; wheel_pos -= 85;
return Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3); Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3)
} } else {
wheel_pos -= 170; wheel_pos -= 170;
Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0) Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0)
};
// tone the brightness down a bit, sheesh.
//rgb / 4
rgb
} }

View File

@ -1,5 +1,6 @@
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use core::mem::transmute; use core::mem::transmute;
use core::ops::Div;
use embassy_rp::dma::{self, AnyChannel}; use embassy_rp::dma::{self, AnyChannel};
use embassy_rp::pio::{ use embassy_rp::pio::{
@ -128,3 +129,12 @@ impl Debug for Rgb {
f.debug_tuple("Rgb").field(&r).field(&g).field(&b).finish() f.debug_tuple("Rgb").field(&r).field(&g).field(&b).finish()
} }
} }
impl Div<u8> for Rgb {
type Output = Rgb;
fn div(self, d: u8) -> Self::Output {
let (r, g, b) = self.components();
Rgb::new(r / d, g / d, b / d)
}
}