From 386aecb58f7229786e046d00498265a5acd8fda6 Mon Sep 17 00:00:00 2001 From: Nick Mello Date: Sat, 11 Jul 2026 21:51:57 -0500 Subject: [PATCH] keyboard: Move keyboard logic Signed-off-by: Nicholas Mello --- Cargo.lock | 2 + Cargo.toml | 1 + src/keyboard.rs | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 63 +++++-------------------- 4 files changed, 139 insertions(+), 50 deletions(-) create mode 100644 src/keyboard.rs diff --git a/Cargo.lock b/Cargo.lock index 1035e36..fd7b8c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,6 +33,7 @@ dependencies = [ "embassy-executor", "embassy-futures", "embassy-rp", + "embassy-sync", "embassy-time", "embassy-usb", "panic-probe", @@ -514,6 +515,7 @@ checksum = "7bbd85cf5a5ae56bdf26f618364af642d1d0a4e245cdd75cd9aabda382f65a81" dependencies = [ "cfg-if", "critical-section", + "defmt 1.1.1", "embedded-io-async 0.7.0", "futures-core", "futures-sink", diff --git a/Cargo.toml b/Cargo.toml index 61df29f..4d71fe6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ defmt-rtt = "1.3.0" embassy-executor = { version = "0.10.0", features = ["executor-thread", "platform-cortex-m"] } embassy-futures = { version = "0.1.2", features = ["defmt"] } embassy-rp = { version = "0.10.0", features = ["chrono", "defmt", "rp2040", "rt", "time-driver", "critical-section-impl"] } +embassy-sync = { version = "0.8.0", features = ["defmt"] } embassy-time = "0.5.1" embassy-usb = { version = "0.6.0", features = ["defmt"] } panic-probe = { version = "1.0.0", features = ["defmt"] } diff --git a/src/keyboard.rs b/src/keyboard.rs new file mode 100644 index 0000000..6a249b0 --- /dev/null +++ b/src/keyboard.rs @@ -0,0 +1,123 @@ +use core::sync::atomic::Ordering; + +use defmt::*; +use embassy_rp::gpio::Input; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex}; +use embassy_time::{Duration, Timer}; +use embassy_usb::{ + class::hid::{HidProtocolMode, HidWriter}, + driver::Driver, +}; +use usbd_hid::descriptor::KeyboardReport; + +use crate::HID_PROTOCOL_MODE; + +const WRITE_N: usize = 8; + +pub struct Key<'a> { + button: Input<'a>, + value: char, +} + +impl Key<'_> { + pub async fn process<'d, D: Driver<'d>>( + &mut self, + mut writer: Mutex>, + ) { + loop { + self.button.wait_for_high().await; + info!("Button {} pressed", self.value); + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.get_mut().write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.get_mut().write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } + + // Debounce + Timer::after(Duration::from_millis(50)).await; + + self.button.wait_for_low().await; + info!("Button {} unpressed", self.value); + + if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { + match writer.get_mut().write(&[0, 0, 0, 0, 0, 0, 0, 0]).await { + Ok(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.get_mut().write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } + + // Debounce + Timer::after(Duration::from_millis(50)).await; + } + } +} + +impl Key<'_> { + #[allow(unused)] + pub async fn set_value(mut self, value: char) { + self.value = value; + } +} + +pub struct Keyboard<'d, D: Driver<'d>, const KEY_N: usize> { + writer: Mutex>, + keys: [Option>; KEY_N], + num_keys: usize, +} + +pub enum KeyboardError { + MaxKeys, +} + +impl<'d, D: Driver<'d>, const KEY_N: usize> Keyboard<'d, D, KEY_N> { + pub fn new(writer: HidWriter<'d, D, WRITE_N>) -> Self { + Self { + writer: Mutex::new(writer), + keys: [const { None }; KEY_N], + num_keys: 0, + } + } + + pub fn add_key(&mut self, button: Input<'d>, value: char) -> Result<(), KeyboardError> { + let key = self + .keys + .get_mut(self.num_keys) + .ok_or(KeyboardError::MaxKeys)?; + *key = Some(Key { button, value }); + + self.num_keys += 1; + + Ok(()) + } + + pub async fn process(mut self) { + // TODO: Make this a loop that is concatinated together + self.keys[0].as_mut().unwrap().process(self.writer).await; + } +} diff --git a/src/main.rs b/src/main.rs index 0fb17af..e291baf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,11 @@ #![no_main] mod heartbeat; +mod keyboard; +use crate::heartbeat::heartbeat; +use crate::keyboard::Keyboard; use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; - use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -18,6 +20,7 @@ use embassy_usb::class::hid::{ use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; + use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -84,55 +87,15 @@ async fn main(_spawner: Spawner) { // Enable the schmitt trigger to slightly debounce. signal_pin.set_schmitt(true); - let (reader, mut writer) = hid.split(); + let (reader, writer) = hid.split(); - // Do stuff with the class! - let in_fut = async { - loop { - signal_pin.wait_for_high().await; - info!("HIGH DETECTED"); - - if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { - match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { - Ok(()) => {} - Err(e) => warn!("Failed to send boot report: {:?}", e), - }; - } else { - // Create a report with the A key pressed. (no shift modifier) - let report = KeyboardReport { - keycodes: [4, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - // Send the report. - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; - } - - signal_pin.wait_for_low().await; - info!("LOW DETECTED"); - if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 { - match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await { - Ok(()) => {} - Err(e) => warn!("Failed to send boot report: {:?}", e), - }; - } else { - let report = KeyboardReport { - keycodes: [0, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - match writer.write_serialize(&report).await { - Ok(()) => {} - Err(e) => warn!("Failed to send report: {:?}", e), - }; - } + let mut keyboard = Keyboard::<_, 1>::new(writer); + match keyboard.add_key(signal_pin, 'a') { + Ok(()) => info!("Key 'a' registered"), + Err(_) => { + defmt::panic!("Failed to register key!"); } - }; + } let out_fut = async { reader.run(false, &mut request_handler).await; @@ -142,8 +105,8 @@ async fn main(_spawner: Spawner) { let led = Output::new(p.PIN_25, Level::Low); join( - join(usb.run(), heartbeat::heartbeat(led)), - join(in_fut, out_fut), + join(usb.run(), heartbeat(led)), + join(keyboard.process(), out_fut), ) .await; }