diff --git a/.cargo/config b/.cargo/config index bdf3eb5..d625541 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,35 +1,12 @@ -# -# Cargo Configuration for the https://github.com/rp-rs/rp-hal.git repository. -# -# Copyright (c) The RP-RS Developers, 2021 -# -# You might want to make a similar file in your own repository if you are -# writing programs for Raspberry Silicon microcontrollers. -# -# This file is MIT or Apache-2.0 as per the repository README.md file -# - [build] -# Set the default target to match the Cortex-M0+ in the RP2040 target = "thumbv6m-none-eabi" -# Target specific options [target.thumbv6m-none-eabi] -# Pass some extra options to rustc, some of which get passed on to the linker. -# -# * inline-threshold=5 makes the compiler more aggressive and inlining functions -# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't -# have SIMD) rustflags = [ "-C", "linker=flip-link", - "-C", "inline-threshold=5", + "-C", "inline-threshold=5", # inline functions more aggressively "-C", "no-vectorize-loops", ] -# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB -# Bootloader mode: -runner = "elf2uf2-rs -d" - -# This runner will find a supported SWD debug probe and flash your RP2040 over -# SWD: -# runner = "probe-run --chip RP2040" +#runner = "elf2uf2-rs -d" +runner = "probe-run --chip RP2040" diff --git a/src/keyboard.rs b/src/keyboard.rs index 124e0d7..eed9a7f 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -70,7 +70,7 @@ pub enum EventKind { } pub const KB_SUBSCRIBERS: usize = 2; -pub const ACTUAL_KB_SUBSCRIBERS: usize = KB_SUBSCRIBERS + 2; +const ACTUAL_KB_SUBSCRIBERS: usize = KB_SUBSCRIBERS + 2; const KB_EVENT_CAP: usize = 128; static KB_EVENTS: PubSubChannel = PubSubChannel::new(); @@ -254,7 +254,7 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> ! } _ = wait_for_release.fuse() => { events.publish_immediate(ev(PressKey(key))); - Timer::after(Duration::from_millis(10)).await; + Timer::after(Duration::from_millis(20)).await; events.publish_immediate(ev(ReleaseKey(key))); continue; } diff --git a/src/keyboard/lights.rs b/src/keyboard/lights.rs index fa52857..63b90dd 100644 --- a/src/keyboard/lights.rs +++ b/src/keyboard/lights.rs @@ -1,66 +1,152 @@ +use core::cmp::min; + use embassy_time::{Duration, Timer}; use futures::{select_biased, FutureExt}; -use crate::ws2812::Rgb; +use crate::{util::wheel, ws2812::Rgb}; -use super::{EventKind, KbEvents, State, SWITCH_COUNT}; +use super::{Event, EventKind, KbEvents, State, SWITCH_COUNT}; + +/// Duration until the keyboard starts the idle animation +const UNTIL_IDLE: Duration = Duration::from_secs(30); + +///// Duration from idle until the keyboard goes to sleep +//const UNTIL_SLEEP: Duration = Duration::from_secs(10); + +const IDLE_ANIMATION_SPEED: u64 = 3; +const IDLE_ANIMATION_KEY_OFFSET: u64 = 10; +const IDLE_BRIGHTNESS_RAMPUP: Duration = Duration::from_secs(120); +const MAX_IDLE_BRIGHTESS: f32 = 1.0; +const MIN_IDLE_BRIGHTESS: f32 = 0.05; #[embassy_executor::task] pub(super) async fn task(mut events: KbEvents, state: &'static State) { loop { select_biased! { - event = events.recv().fuse() => { - let set_button_led = |color: Rgb| { - let led_num = state.led_map.get(event.source_button).copied(); - move |leds: &mut [Rgb; SWITCH_COUNT]| { - if event.source != state.half { - return; - } - - if let Some(led) = led_num.and_then(|i| leds.get_mut(i)) { - *led = color; - } - } - }; - - match event.kind { - EventKind::PressKey(_) => { - state.lights.update(set_button_led(Rgb::new(0, 150, 0))).await; - } - EventKind::PressModifier(_) => { - state.lights.update(set_button_led(Rgb::new(0, 0, 150))).await; - } - EventKind::ReleaseKey(_) | EventKind::ReleaseModifier(_) => { - state.lights.update(set_button_led(Rgb::new(0, 0, 0))).await; - } - EventKind::SetLayer(layer) => { - let buttons_to_light_up = match layer { - 0 => [0, 1, 2, 3, 4].as_ref(), - 1 => &[5, 6, 7, 8, 9], - 2 => &[10, 11, 12, 13, 14], - _ => &[], - }; - - state.lights.update(|leds| { - for &button in buttons_to_light_up { - let Some(&led_id) = state.led_map.get(button) else { continue; }; - let Some(rgb) = leds.get_mut(led_id) else { continue; }; - *rgb = Rgb::new(100, 0, 100); - } - }).await; - - Timer::after(Duration::from_millis(200)).await; - - state.lights.update(|leds| { - for &button in buttons_to_light_up { - let Some(&led_id) = state.led_map.get(button) else { continue; }; - let Some(rgb) = leds.get_mut(led_id) else { continue; }; - *rgb = Rgb::new(0, 0, 0); - } + event = events.recv().fuse() => handle_event(event, state).await, + _ = Timer::after(UNTIL_IDLE).fuse() => { + select_biased! { + event = events.recv().fuse() => { + state.lights.update(|lights| { + lights.iter_mut().for_each(|rgb| *rgb = Rgb::new(0, 0, 0)); }).await; + handle_event(event, state).await; } + _ = idle_animation(state).fuse() => {} } } } } } + +async fn idle_animation(state: &'static State) { + for tick in 0.. { + const FRAMETIME: Duration = Duration::from_millis(16); + + state + .lights + .update(|lights| { + const N_MAX: u64 = IDLE_BRIGHTNESS_RAMPUP.as_millis() / FRAMETIME.as_millis(); + + let brightness = if tick >= N_MAX { + MAX_IDLE_BRIGHTESS + } else { + ((tick as f32) / N_MAX as f32).clamp(MIN_IDLE_BRIGHTESS, MAX_IDLE_BRIGHTESS) + }; + + for (n, &i) in state.led_map.iter().enumerate() { + let Some(light) = lights.get_mut(i) else { continue }; + let (r, g, b) = wheel( + (n as u64 * IDLE_ANIMATION_KEY_OFFSET + tick * IDLE_ANIMATION_SPEED) as u8, + ) + .components(); + let rgb = Rgb::new( + ((r as f32) * brightness) as u8, + ((g as f32) * brightness) as u8, + ((b as f32) * brightness) as u8, + ); + *light = rgb; + } + }) + .await; + + Timer::after(FRAMETIME).await; + } +} + +async fn handle_event(event: Event, state: &'static State) { + let set_button_led = |color: Rgb| { + let led_num = state.led_map.get(event.source_button).copied(); + move |leds: &mut [Rgb; SWITCH_COUNT]| { + if event.source != state.half { + return; + } + + if let Some(led) = led_num.and_then(|i| leds.get_mut(i)) { + *led = color; + } + } + }; + + match event.kind { + EventKind::PressKey(_) => { + state + .lights + .update(set_button_led(Rgb::new(0, 150, 0))) + .await; + } + EventKind::PressModifier(_) => { + state + .lights + .update(set_button_led(Rgb::new(0, 0, 150))) + .await; + } + EventKind::ReleaseKey(_) | EventKind::ReleaseModifier(_) => { + state.lights.update(set_button_led(Rgb::new(0, 0, 0))).await; + } + EventKind::SetLayer(layer) => { + let layer = min(layer, state.layers.len().saturating_sub(1) as u16); + let buttons_to_light_up = if state.layers.len() <= 3 { + match layer { + 0 => [0, 1, 2, 3, 4].as_ref(), + 1 => &[5, 6, 7, 8, 9], + 2 => &[10, 11, 12, 13, 14], + _ => &[], + } + } else { + match layer { + 0 => [0, 5, 10].as_ref(), + 1 => &[1, 6, 11], + 2 => &[2, 7, 12], + 3 => &[3, 8, 13], + 4 => &[4, 9, 14], + _ => &[], + } + }; + + state + .lights + .update(|leds| { + for &button in buttons_to_light_up { + let Some(&led_id) = state.led_map.get(button) else { continue; }; + let Some(rgb) = leds.get_mut(led_id) else { continue; }; + *rgb = Rgb::new(100, 0, 100); + } + }) + .await; + + Timer::after(Duration::from_millis(200)).await; + + state + .lights + .update(|leds| { + for &button in buttons_to_light_up { + let Some(&led_id) = state.led_map.get(button) else { continue; }; + let Some(rgb) = leds.get_mut(led_id) else { continue; }; + *rgb = Rgb::new(0, 0, 0); + } + }) + .await; + } + } +} diff --git a/src/uart.rs b/src/uart.rs index c99ba89..94c99db 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -61,10 +61,10 @@ async fn uart_task(uart: BufferedUart<'static, UART0>, this_half: Half, mut even }; let message: Message = unsafe { transmute(buf) }; // crimes :) - info!("got msg: {:?}", message); - match message { - Message::KeyboardEvent(event) => events_tx.send(event), + match &message { + Message::KeyboardEvent(event) => events_tx.send(event.clone()), } + info!("got msg: {:?}", message); } }; diff --git a/src/util.rs b/src/util.rs index 86ece38..efe5987 100644 --- a/src/util.rs +++ b/src/util.rs @@ -15,7 +15,7 @@ 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; - let rgb = if wheel_pos < 85 { + if wheel_pos < 85 { Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3) } else if wheel_pos < 170 { wheel_pos -= 85; @@ -23,9 +23,5 @@ pub fn wheel(mut wheel_pos: u8) -> Rgb { } else { wheel_pos -= 170; Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0) - }; - - // tone the brightness down a bit, sheesh. - //rgb / 4 - rgb + } }