diff --git a/Cargo.lock b/Cargo.lock index 61c7999..137a8ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,17 +44,6 @@ dependencies = [ "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]] name = "autocfg" version = "1.1.0" @@ -115,6 +104,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -252,7 +247,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "embassy-cortex-m" 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 = [ "atomic-polyfill 1.0.2", "cfg-if", @@ -267,7 +262,7 @@ dependencies = [ [[package]] name = "embassy-embedded-hal" 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 = [ "embassy-sync", "embedded-hal 0.2.7", @@ -281,7 +276,7 @@ dependencies = [ [[package]] name = "embassy-executor" 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 = [ "atomic-polyfill 1.0.2", "cfg-if", @@ -296,7 +291,7 @@ dependencies = [ [[package]] name = "embassy-futures" 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 = [ "log", ] @@ -304,7 +299,7 @@ dependencies = [ [[package]] name = "embassy-hal-common" 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 = [ "num-traits", ] @@ -312,7 +307,7 @@ dependencies = [ [[package]] name = "embassy-macros" 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 = [ "darling", "proc-macro2", @@ -323,12 +318,12 @@ dependencies = [ [[package]] name = "embassy-net-driver" 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]] name = "embassy-net-driver-channel" 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 = [ "embassy-futures", "embassy-net-driver", @@ -338,7 +333,7 @@ dependencies = [ [[package]] name = "embassy-rp" 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 = [ "atomic-polyfill 1.0.2", "cfg-if", @@ -372,7 +367,7 @@ dependencies = [ [[package]] name = "embassy-sync" 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 = [ "cfg-if", "critical-section", @@ -385,7 +380,7 @@ dependencies = [ [[package]] name = "embassy-time" 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 = [ "atomic-polyfill 1.0.2", "cfg-if", @@ -400,7 +395,7 @@ dependencies = [ [[package]] name = "embassy-usb" 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 = [ "embassy-futures", "embassy-net-driver-channel", @@ -414,12 +409,12 @@ dependencies = [ [[package]] name = "embassy-usb-driver" 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]] name = "embassy-usb-logger" 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 = [ "embassy-futures", "embassy-sync", @@ -511,6 +506,27 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "fixedbitset" version = "0.4.2" @@ -638,12 +654,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "ident_case" @@ -653,14 +666,37 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "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]] name = "itertools" version = "0.10.5" @@ -672,15 +708,15 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" dependencies = [ "ascii-canvas", - "atty", "bit-set", "diff", "ena", + "is-terminal", "itertools", "lalrpop-util", "petgraph", @@ -695,9 +731,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd" dependencies = [ "regex", ] @@ -714,6 +750,12 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -942,9 +984,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] @@ -986,9 +1028,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -997,9 +1039,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "rgb" @@ -1048,6 +1090,20 @@ dependencies = [ "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]] name = "rustversion" version = "1.0.12" @@ -1083,22 +1139,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.157" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.157" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.10", ] [[package]] @@ -1197,9 +1253,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.2" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" +checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" dependencies = [ "proc-macro2", "quote", @@ -1259,7 +1315,7 @@ dependencies = [ [[package]] name = "tgnt" 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 = [ "serde", ] @@ -1281,7 +1337,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.10", ] [[package]] diff --git a/src/bin/left.rs b/src/bin/left.rs index 6985f0d..8d600e3 100644 --- a/src/bin/left.rs +++ b/src/bin/left.rs @@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) { 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 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; usb::setup_logger_and_keyboard(board.USB).await; @@ -44,7 +44,6 @@ async fn main(_spawner: Spawner) { }; let keyboard = KeyboardConfig { - layers, pins: [ // row 1 board.d24.degrade(), @@ -69,20 +68,17 @@ async fn main(_spawner: Spawner) { board.scl.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; for w in 0usize.. { 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; } } diff --git a/src/keyboard.rs b/src/keyboard.rs index 8e20692..85d8c41 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -2,21 +2,39 @@ use core::sync::atomic::{AtomicU16, Ordering}; use alloc::{boxed::Box, vec::Vec}; 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 futures::{select_biased, FutureExt}; use log::{debug, error, info, warn}; +use static_cell::StaticCell; use tgnt::{button::Button, layer::Layer}; -use crate::usb::keyboard::KB_REPORT; - -static CURRENT_LAYER: AtomicU16 = AtomicU16::new(0); +use crate::{ + lights::Lights, + usb::keyboard::KB_REPORT, + ws2812::{Rgb, Ws2812}, +}; pub struct KeyboardConfig { + /// Array of input pins of each switch pub pins: [AnyPin; SWITCH_COUNT], + /// Array of LED indices of each switch + pub led_map: [usize; SWITCH_COUNT], + pub led_driver: Ws2812>, pub layers: Vec, } +struct State { + current_layer: AtomicU16, + layers: &'static [Layer], + /// Array of LED indices of each switch + led_map: [usize; SWITCH_COUNT], + lights: Lights, SWITCH_COUNT>, +} + impl KeyboardConfig { pub async fn create(self) { let spawner = Spawner::for_current_executor().await; @@ -31,8 +49,15 @@ impl KeyboardConfig { self.layers.len() ); - let layers = Box::leak(self.layers.into_boxed_slice()); - for (i, layer) in layers.iter().enumerate() { + static STATE: StaticCell = StaticCell::new(); + 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 { warn!( "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() { - 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?"); 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; /// Task for monitoring a single switch pin, and handling button presses. #[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 mut pin = Input::new(pin, Pull::Up); loop { @@ -65,15 +90,15 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) - // TODO: do we need debouncing? // get current layer - let mut current_layer = CURRENT_LAYER.load(Ordering::Relaxed); - let layer_count = layers.len() as u16; + let mut current_layer = state.current_layer.load(Ordering::Relaxed); + let layer_count = state.layers.len() as u16; if current_layer >= layer_count { error!("current layer was out of bounds for some reason ({current_layer})"); 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})"); - CURRENT_LAYER.store(0, Ordering::Relaxed); + state.current_layer.store(0, Ordering::Relaxed); continue; }; @@ -90,50 +115,69 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) - 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 { &Button::Key(key) => { KB_REPORT.lock().await.press_key(key); + state.lights.update(set_led(Rgb::new(0, 150, 0))).await; wait_for_release.await; KB_REPORT.lock().await.release_key(key); + state.lights.update(set_led(Rgb::new(0, 0, 0))).await; continue; } &Button::Mod(modifier) => { KB_REPORT.lock().await.press_modifier(modifier); + state.lights.update(set_led(Rgb::new(100, 100, 0))).await; wait_for_release.await; KB_REPORT.lock().await.release_modifier(modifier); + state.lights.update(set_led(Rgb::new(0, 0, 0))).await; continue; } - &Button::ModTap { keycode, modifier } => { + &Button::ModTap(key, modifier) => { + state.lights.update(set_led(Rgb::new(100, 100, 0))).await; select_biased! { _ = Timer::after(MOD_TAP_TIME).fuse() => { KB_REPORT.lock().await.press_modifier(modifier); + state.lights.update(set_led(Rgb::new(0, 0, 150))).await; pin.wait_for_high().await; 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"); continue; } _ = 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; - 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; } } } Button::NextLayer => { 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}"); } Button::PrevLayer => { 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}"); } Button::None => {} } wait_for_release.await; + state.lights.update(set_led(Rgb::new(0, 0, 0))).await; } } diff --git a/src/lib.rs b/src/lib.rs index fdf3a1d..d81c133 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ extern crate alloc; pub mod allocator; pub mod board; pub mod keyboard; +pub mod lights; pub mod neopixel; pub mod panic_handler; pub mod usb; diff --git a/src/lights.rs b/src/lights.rs new file mode 100644 index 0000000..e369e12 --- /dev/null +++ b/src/lights.rs @@ -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 { + state: Mutex>, +} + +struct State { + colors: [Rgb; N], + driver: Ws2812

, +} + +impl Lights { + pub const fn new(driver: Ws2812

) -> 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; + } +} diff --git a/src/usb.rs b/src/usb.rs index d57d234..a521c77 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -33,7 +33,9 @@ pub async fn setup_logger_and_keyboard(usb: 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], config_descriptor: [0; 256], bos_descriptor: [0; 256], diff --git a/src/usb/logger.rs b/src/usb/logger.rs index d426b31..0da393f 100644 --- a/src/usb/logger.rs +++ b/src/usb/logger.rs @@ -15,7 +15,6 @@ use static_cell::StaticCell; pub const BUFFER_SIZE: usize = 16 * 1024; static BUFFER: Pipe = Pipe::new(); -static STATE: StaticCell> = StaticCell::new(); struct UsbLogger; @@ -23,11 +22,12 @@ pub async fn setup(usb_builder: &mut Builder<'static, Driver<'static, USB>>) { unsafe { static LOGGER: UsbLogger = UsbLogger; 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; + static STATE: StaticCell> = StaticCell::new(); let state = STATE.init(cdc_acm::State::new()); 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)); } -//pub async fn print(s: &str) { -// BUFFER.writer().write_all(s.as_bytes()).await.ok(/* infallible */); -//} - #[embassy_executor::task] async fn log_task(mut class: CdcAcmClass<'static, Driver<'static, USB>>) { let mut buf = [0u8; MAX_PACKET_SIZE as usize]; diff --git a/src/util.rs b/src/util.rs index 18b5652..86ece38 100644 --- a/src/util.rs +++ b/src/util.rs @@ -15,13 +15,17 @@ pub async fn stall() -> ! { // The colours are a transition r - g - b - back to r. pub fn wheel(mut wheel_pos: u8) -> Rgb { wheel_pos = 255 - wheel_pos; - if wheel_pos < 85 { - return Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3); - } - if wheel_pos < 170 { + let rgb = if wheel_pos < 85 { + Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3) + } else if wheel_pos < 170 { wheel_pos -= 85; - return Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3); - } - wheel_pos -= 170; - Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0) + Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3) + } else { + wheel_pos -= 170; + Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0) + }; + + // tone the brightness down a bit, sheesh. + //rgb / 4 + rgb } diff --git a/src/ws2812.rs b/src/ws2812.rs index 91a5b56..7d0e264 100644 --- a/src/ws2812.rs +++ b/src/ws2812.rs @@ -1,5 +1,6 @@ use core::fmt::{self, Debug}; use core::mem::transmute; +use core::ops::Div; use embassy_rp::dma::{self, AnyChannel}; use embassy_rp::pio::{ @@ -128,3 +129,12 @@ impl Debug for Rgb { f.debug_tuple("Rgb").field(&r).field(&g).field(&b).finish() } } + +impl Div 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) + } +}