Code refactor

This commit is contained in:
Christoffer Martinsson 2025-09-19 15:22:27 +02:00
parent 6dbec2425e
commit 932d89e9ce
6 changed files with 96 additions and 66 deletions

View File

@ -1,6 +1,8 @@
//! Bootloader entry helpers shared between power-on checks and runtime combos. //! Bootloader entry helpers shared between power-on checks and runtime combos.
use crate::{NUMBER_OF_KEYS, StatusLed, layout, status::StatusMode}; use crate::{KeyMatrix, StatusLed, layout, status::StatusMode};
#[cfg(all(test, feature = "std"))]
use crate::NUMBER_OF_KEYS;
use cortex_m::asm; use cortex_m::asm;
use rp2040_hal::{ use rp2040_hal::{
gpio::AnyPin, gpio::AnyPin,
@ -11,7 +13,7 @@ use usbd_human_interface_device::page::Keyboard;
/// Returns true when the runtime bootloader chord is held. /// Returns true when the runtime bootloader chord is held.
/// ///
/// The chord requires two Fn buttons, both Shift buttons and the primary Ctrl. /// The chord requires two Fn buttons, both Shift buttons and the primary Ctrl.
pub fn chord_requested(pressed_keys: &[bool; NUMBER_OF_KEYS]) -> bool { pub fn chord_requested(pressed_keys: &KeyMatrix) -> bool {
if !modifier_pressed(pressed_keys, Keyboard::LeftShift) if !modifier_pressed(pressed_keys, Keyboard::LeftShift)
|| !modifier_pressed(pressed_keys, Keyboard::RightShift) || !modifier_pressed(pressed_keys, Keyboard::RightShift)
{ {
@ -30,7 +32,7 @@ pub fn chord_requested(pressed_keys: &[bool; NUMBER_OF_KEYS]) -> bool {
active_fn >= 2 active_fn >= 2
} }
fn modifier_pressed(pressed_keys: &[bool; NUMBER_OF_KEYS], key: Keyboard) -> bool { fn modifier_pressed(pressed_keys: &KeyMatrix, key: Keyboard) -> bool {
layout::MAP[0] layout::MAP[0]
.iter() .iter()
.enumerate() .enumerate()

View File

@ -126,19 +126,10 @@ where
}; };
if self.debounce_counter[button_index] >= threshold { if self.debounce_counter[button_index] >= threshold {
if current_state { self.pressed[button_index] = match current_state {
let elapsed = self true => self.should_register_press(button_index),
.scan_counter false => false,
.wrapping_sub(self.last_press_scan[button_index]); };
if self.last_press_scan[button_index] == 0
|| elapsed >= self.min_press_gap_scans
{
self.pressed[button_index] = true;
self.last_press_scan[button_index] = self.scan_counter;
}
} else {
self.pressed[button_index] = false;
}
self.debounce_counter[button_index] = 0; self.debounce_counter[button_index] = 0;
} }
} }
@ -148,6 +139,17 @@ where
self.pressed self.pressed
} }
fn should_register_press(&mut self, button_index: usize) -> bool {
let elapsed = self.scan_counter.wrapping_sub(self.last_press_scan[button_index]);
let can_register = self.last_press_scan[button_index] == 0
|| elapsed >= self.min_press_gap_scans;
if can_register {
self.last_press_scan[button_index] = self.scan_counter;
}
can_register
}
#[cfg(all(test, feature = "std"))] #[cfg(all(test, feature = "std"))]
pub(crate) fn set_scan_counter(&mut self, value: u32) { pub(crate) fn set_scan_counter(&mut self, value: u32) {
self.scan_counter = value; self.scan_counter = value;

View File

@ -1,6 +1,6 @@
//! Keyboard state management and HID report generation. //! Keyboard state management and HID report generation.
use crate::NUMBER_OF_KEYS; use crate::{NUMBER_OF_KEYS, KeyMatrix, KeyReport};
use crate::layout; use crate::layout;
use crate::status::StatusSummary; use crate::status::StatusSummary;
use usbd_human_interface_device::page::Keyboard; use usbd_human_interface_device::page::Keyboard;
@ -50,8 +50,8 @@ impl KeyboardState {
pub fn process_scan( pub fn process_scan(
&mut self, &mut self,
pressed_keys: [bool; NUMBER_OF_KEYS], pressed_keys: KeyMatrix,
) -> [Keyboard; NUMBER_OF_KEYS] { ) -> KeyReport {
let fn_mode = Self::fn_mode(&pressed_keys); let fn_mode = Self::fn_mode(&pressed_keys);
for (index, pressed) in pressed_keys.iter().enumerate() { for (index, pressed) in pressed_keys.iter().enumerate() {
@ -85,6 +85,16 @@ impl KeyboardState {
self.sticky_state self.sticky_state
} }
fn toggle_sticky_state(&mut self) {
self.sticky_state = match self.sticky_state {
StickyState::Inactive => StickyState::Armed,
StickyState::Armed | StickyState::Latched => {
self.sticky_key = Keyboard::NoEventIndicated;
StickyState::Inactive
}
};
}
pub fn status_summary( pub fn status_summary(
&self, &self,
usb_initialized: bool, usb_initialized: bool,
@ -103,34 +113,27 @@ impl KeyboardState {
) )
} }
fn build_report(&mut self, fn_mode: u8) -> [Keyboard; NUMBER_OF_KEYS] { fn build_report(&mut self, fn_mode: u8) -> KeyReport {
let mut report = [Keyboard::NoEventIndicated; NUMBER_OF_KEYS]; let mut report = [Keyboard::NoEventIndicated; NUMBER_OF_KEYS];
let mut sticky_toggle_requested = false;
for (index, button) in self.buttons.iter_mut().enumerate() { for (index, button) in self.buttons.iter_mut().enumerate() {
let changed = button.pressed != button.previous_pressed; let changed = button.pressed != button.previous_pressed;
let just_pressed = changed && button.pressed; let just_pressed = changed && button.pressed;
if just_pressed
&& index as u8 == layout::STICKY_BUTTON[0]
&& fn_mode == layout::STICKY_BUTTON[1]
{
self.sticky_state = match self.sticky_state {
StickyState::Inactive => StickyState::Armed,
StickyState::Armed | StickyState::Latched => {
self.sticky_key = Keyboard::NoEventIndicated;
StickyState::Inactive
}
};
} else if just_pressed
&& index as u8 == layout::OS_LOCK_BUTTON[0]
&& fn_mode == layout::OS_LOCK_BUTTON[1]
{
report[36] = layout::OS_LOCK_BUTTON_KEYS[0];
report[37] = layout::OS_LOCK_BUTTON_KEYS[1];
}
if just_pressed { if just_pressed {
button.fn_mode = fn_mode; button.fn_mode = fn_mode;
match (index as u8, fn_mode) {
(idx, layer) if idx == layout::STICKY_BUTTON[0] && layer == layout::STICKY_BUTTON[1] => {
sticky_toggle_requested = true;
}
(idx, layer) if idx == layout::OS_LOCK_BUTTON[0] && layer == layout::OS_LOCK_BUTTON[1] => {
report[36] = layout::OS_LOCK_BUTTON_KEYS[0];
report[37] = layout::OS_LOCK_BUTTON_KEYS[1];
}
_ => {}
}
} }
let layer_key = layout::MAP[button.fn_mode as usize][index]; let layer_key = layout::MAP[button.fn_mode as usize][index];
@ -151,13 +154,17 @@ impl KeyboardState {
button.previous_pressed = button.pressed; button.previous_pressed = button.pressed;
} }
if sticky_toggle_requested {
self.toggle_sticky_state();
}
const STICKY_REPORT_INDEX: usize = 46; const STICKY_REPORT_INDEX: usize = 46;
report[STICKY_REPORT_INDEX] = self.sticky_key; report[STICKY_REPORT_INDEX] = self.sticky_key;
report report
} }
fn fn_mode(pressed_keys: &[bool; NUMBER_OF_KEYS]) -> u8 { fn fn_mode(pressed_keys: &KeyMatrix) -> u8 {
let active_fn_keys = layout::FN_BUTTONS let active_fn_keys = layout::FN_BUTTONS
.iter() .iter()
.filter(|key_index| pressed_keys[**key_index as usize]) .filter(|key_index| pressed_keys[**key_index as usize])

View File

@ -24,6 +24,10 @@ pub use hardware::{
pub use keyboard::{KeyboardState, StickyState}; pub use keyboard::{KeyboardState, StickyState};
pub use status::{StatusLed, StatusMode, StatusSummary}; pub use status::{StatusLed, StatusMode, StatusSummary};
// Type aliases for better code readability
pub type KeyMatrix = [bool; NUMBER_OF_KEYS];
pub type KeyReport = [usbd_human_interface_device::page::Keyboard; NUMBER_OF_KEYS];
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
static mut __bi_entries_start: u8 = 0; static mut __bi_entries_start: u8 = 0;

View File

@ -8,7 +8,7 @@
#![no_main] #![no_main]
use cmdr_keyboard_42::hardware::{self, timers}; use cmdr_keyboard_42::hardware::{self, timers};
use cmdr_keyboard_42::{Board, BoardParts, KeyboardState, StatusMode, bootloader}; use cmdr_keyboard_42::{Board, BoardParts, KeyboardState, StatusMode, bootloader, KeyReport};
use embedded_hal_0_2::timer::CountDown; use embedded_hal_0_2::timer::CountDown;
use fugit::ExtU32; use fugit::ExtU32;
use panic_halt as _; use panic_halt as _;
@ -25,6 +25,31 @@ use usbd_human_interface_device::prelude::*;
#[used] #[used]
pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
fn handle_usb_state_changes(
usb_dev: &UsbDevice<rp2040_hal::usb::UsbBus>,
usb_suspended: &mut bool,
wake_on_input: &mut bool,
last_activity_ms: &mut u32,
status_time_ms: u32,
) {
let current_suspended = usb_dev.state() == UsbDeviceState::Suspend;
let was_suspended = *usb_suspended;
match (was_suspended, current_suspended) {
(true, false) => {
*last_activity_ms = status_time_ms;
*wake_on_input = false;
}
(false, true) => {
*wake_on_input = true;
}
_ => {}
}
*usb_suspended = current_suspended;
}
#[rp2040_hal::entry] #[rp2040_hal::entry]
fn main() -> ! { fn main() -> ! {
let BoardParts { let BoardParts {
@ -86,14 +111,12 @@ fn main() -> ! {
); );
} }
let should_scan = if usb_suspended { let should_scan = !usb_suspended || {
static mut SUSPENDED_SCAN_COUNTER: u8 = 0; static mut SUSPENDED_SCAN_COUNTER: u8 = 0;
unsafe { unsafe {
SUSPENDED_SCAN_COUNTER = (SUSPENDED_SCAN_COUNTER + 1) % 20; SUSPENDED_SCAN_COUNTER = (SUSPENDED_SCAN_COUNTER + 1) % 20;
SUSPENDED_SCAN_COUNTER == 0 SUSPENDED_SCAN_COUNTER == 0
} }
} else {
true
}; };
if usb_tick.wait().is_ok() && should_scan { if usb_tick.wait().is_ok() && should_scan {
@ -102,9 +125,8 @@ fn main() -> ! {
if bootloader::chord_requested(&pressed_keys) { if bootloader::chord_requested(&pressed_keys) {
if !usb_suspended { if !usb_suspended {
let mut attempts: u8 = 0; for _ in 0..3 {
while attempts < 3 { let clear_report: KeyReport = [Keyboard::NoEventIndicated; hardware::NUMBER_OF_KEYS];
let clear_report = [Keyboard::NoEventIndicated; hardware::NUMBER_OF_KEYS];
match keyboard.device().write_report(clear_report) { match keyboard.device().write_report(clear_report) {
Ok(_) => break, Ok(_) => break,
Err(UsbHidError::WouldBlock) | Err(UsbHidError::Duplicate) => { Err(UsbHidError::WouldBlock) | Err(UsbHidError::Duplicate) => {
@ -112,7 +134,6 @@ fn main() -> ! {
} }
Err(_) => break, Err(_) => break,
} }
attempts = attempts.saturating_add(1);
} }
} }
@ -167,17 +188,12 @@ fn main() -> ! {
} }
} }
let usb_state = usb_dev.state(); handle_usb_state_changes(
let was_suspended = usb_suspended; &usb_dev,
usb_suspended = usb_state == UsbDeviceState::Suspend; &mut usb_suspended,
&mut wake_on_input,
if was_suspended && !usb_suspended { &mut last_activity_ms,
last_activity_ms = status_time_ms; status_time_ms,
wake_on_input = false; );
}
if !was_suspended && usb_suspended {
wake_on_input = true;
}
} }
} }

View File

@ -166,18 +166,17 @@ fn breathe(color: RGB8, elapsed_ms: u32, period_ms: u32) -> RGB8 {
if period_ms == 0 { if period_ms == 0 {
return color; return color;
} }
let period = period_ms.max(1); let period = period_ms.max(1);
let time_in_period = (elapsed_ms % period) as f32; let phase = (elapsed_ms % period) as f32 / period as f32;
let period_f = period as f32;
let phase = time_in_period / period_f;
let brightness = if phase < 0.5 { let brightness = if phase < 0.5 {
1.0 - (phase * 2.0) 1.0 - (phase * 2.0)
} else { } else {
(phase - 0.5) * 2.0 (phase - 0.5) * 2.0
}; };
let clamped = brightness.max(0.0).min(1.0); let brightness_factor = ((brightness.clamp(0.0, 1.0) * 255.0) + 0.5) as u8;
let ramp = (clamped * 255.0 + 0.5) as u8;
scale_color(color, ramp) scale_color(color, brightness_factor)
} }
fn scale_color(color: RGB8, factor: u8) -> RGB8 { fn scale_color(color: RGB8, factor: u8) -> RGB8 {