use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel}; // Channel for sending WPM data pub static WPM_CHANNEL: Channel = Channel::new(); pub struct BucketWpmTracker { buckets: [u8; 15], // 15 one-second buckets current_second: u64, } impl BucketWpmTracker { pub fn new() -> Self { Self { buckets: [0; 15], current_second: 0, } } pub fn add_keypress(&mut self, timestamp_ms: u64) { let second = timestamp_ms / 1000; let bucket_idx = (second % 15) as usize; // On new second, clear old buckets if second != self.current_second { let seconds_elapsed = second.saturating_sub(self.current_second).min(15); for i in 0..seconds_elapsed { let idx = ((self.current_second + i + 1) % 15) as usize; self.buckets[idx] = 0; } self.current_second = second; } self.buckets[bucket_idx] = self.buckets[bucket_idx].saturating_add(1); } pub fn calculate_wpm(&mut self, current_time_ms: u64) -> u64 { let current_second = current_time_ms / 1000; // Clear buckets older than 15 seconds if current_second != self.current_second { let seconds_elapsed = current_second.saturating_sub(self.current_second).min(15); for i in 0..seconds_elapsed { let idx = ((self.current_second + i + 1) % 15) as usize; self.buckets[idx] = 0; } self.current_second = current_second; } let total_chars: u32 = self.buckets.iter().map(|&x| x as u32).sum(); // extrapolate 15s of data to 60s // WPM = (chars / 5 chars per word) * (60 seconds / 15 seconds) ((total_chars as f64 * 4f64) / 5f64) as u64 } }