Send keyboard events using async Channel
This commit is contained in:
@@ -1,18 +1,9 @@
|
|||||||
use core::sync::atomic::Ordering;
|
use crate::usb::{KeyboardAction, KeyboardEvent};
|
||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_rp::gpio::Input;
|
use embassy_rp::gpio::Input;
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||||
|
use embassy_sync::channel::Sender;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embassy_usb::{
|
|
||||||
class::hid::{HidProtocolMode, HidWriter},
|
|
||||||
driver::Driver,
|
|
||||||
};
|
|
||||||
use usbd_hid::descriptor::KeyboardReport;
|
|
||||||
|
|
||||||
use crate::usb::HID_PROTOCOL_MODE;
|
|
||||||
|
|
||||||
const WRITE_N: usize = 8;
|
|
||||||
|
|
||||||
pub struct Key<'a> {
|
pub struct Key<'a> {
|
||||||
button: Input<'a>,
|
button: Input<'a>,
|
||||||
@@ -20,33 +11,22 @@ pub struct Key<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Key<'_> {
|
impl Key<'_> {
|
||||||
pub async fn process<'d, D: Driver<'d>>(
|
pub async fn process<'ch, M, const N: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut writer: Mutex<CriticalSectionRawMutex, HidWriter<'d, D, WRITE_N>>,
|
sender: Sender<'ch, M, KeyboardEvent, N>,
|
||||||
) {
|
) where
|
||||||
|
M: RawMutex,
|
||||||
|
{
|
||||||
loop {
|
loop {
|
||||||
self.button.wait_for_high().await;
|
self.button.wait_for_high().await;
|
||||||
info!("Button {} pressed", self.value);
|
info!("Button {} pressed", self.value);
|
||||||
|
|
||||||
if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
|
sender
|
||||||
match writer.get_mut().write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
|
.send(KeyboardEvent {
|
||||||
Ok(()) => {}
|
key: self.value,
|
||||||
Err(e) => warn!("Failed to send boot report: {:?}", e),
|
action: KeyboardAction::Press,
|
||||||
};
|
})
|
||||||
} else {
|
.await;
|
||||||
// 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
|
// Debounce
|
||||||
Timer::after(Duration::from_millis(50)).await;
|
Timer::after(Duration::from_millis(50)).await;
|
||||||
@@ -54,23 +34,12 @@ impl Key<'_> {
|
|||||||
self.button.wait_for_low().await;
|
self.button.wait_for_low().await;
|
||||||
info!("Button {} unpressed", self.value);
|
info!("Button {} unpressed", self.value);
|
||||||
|
|
||||||
if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
|
sender
|
||||||
match writer.get_mut().write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
|
.send(KeyboardEvent {
|
||||||
Ok(()) => {}
|
key: self.value,
|
||||||
Err(e) => warn!("Failed to send boot report: {:?}", e),
|
action: KeyboardAction::Depress,
|
||||||
};
|
})
|
||||||
} else {
|
.await;
|
||||||
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
|
// Debounce
|
||||||
Timer::after(Duration::from_millis(50)).await;
|
Timer::after(Duration::from_millis(50)).await;
|
||||||
@@ -85,8 +54,7 @@ impl Key<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Keyboard<'d, D: Driver<'d>, const KEY_N: usize> {
|
pub struct Keyboard<'d, const KEY_N: usize> {
|
||||||
writer: Mutex<CriticalSectionRawMutex, HidWriter<'d, D, WRITE_N>>,
|
|
||||||
keys: [Option<Key<'d>>; KEY_N],
|
keys: [Option<Key<'d>>; KEY_N],
|
||||||
num_keys: usize,
|
num_keys: usize,
|
||||||
}
|
}
|
||||||
@@ -95,10 +63,9 @@ pub enum KeyboardError {
|
|||||||
MaxKeys,
|
MaxKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, D: Driver<'d>, const KEY_N: usize> Keyboard<'d, D, KEY_N> {
|
impl<'d, const KEY_N: usize> Keyboard<'d, KEY_N> {
|
||||||
pub fn new(writer: HidWriter<'d, D, WRITE_N>) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
writer: Mutex::new(writer),
|
|
||||||
keys: [const { None }; KEY_N],
|
keys: [const { None }; KEY_N],
|
||||||
num_keys: 0,
|
num_keys: 0,
|
||||||
}
|
}
|
||||||
@@ -116,8 +83,11 @@ impl<'d, D: Driver<'d>, const KEY_N: usize> Keyboard<'d, D, KEY_N> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process(mut self) {
|
pub async fn process<'ch, M, const N: usize>(mut self, sender: Sender<'ch, M, KeyboardEvent, N>)
|
||||||
|
where
|
||||||
|
M: RawMutex,
|
||||||
|
{
|
||||||
// TODO: Make this a loop that is concatinated together
|
// TODO: Make this a loop that is concatinated together
|
||||||
self.keys[0].as_mut().unwrap().process(self.writer).await;
|
self.keys[0].as_mut().unwrap().process(sender).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/main.rs
14
src/main.rs
@@ -14,6 +14,8 @@ use embassy_rp::bind_interrupts;
|
|||||||
use embassy_rp::gpio::{Input, Level, Output, Pull};
|
use embassy_rp::gpio::{Input, Level, Output, Pull};
|
||||||
use embassy_rp::peripherals::USB;
|
use embassy_rp::peripherals::USB;
|
||||||
use embassy_rp::usb::{Driver, InterruptHandler};
|
use embassy_rp::usb::{Driver, InterruptHandler};
|
||||||
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
|
use embassy_sync::channel::Channel;
|
||||||
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@@ -23,12 +25,14 @@ bind_interrupts!(struct Irqs {
|
|||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
|
let keyboard_events: Channel<ThreadModeRawMutex, usb::KeyboardEvent, 64> = Channel::new();
|
||||||
|
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let driver = Driver::new(p.USB, Irqs);
|
let driver = Driver::new(p.USB, Irqs);
|
||||||
let mut usb_buf = usb::UsbKeyboardBuf::new();
|
let mut usb_buf = usb::UsbKeyboardBuf::new();
|
||||||
let (usbkey, writer) = usb::UsbKeyboard::create_usb(&mut usb_buf, driver);
|
let usbkey = usb::UsbKeyboard::create_usb(&mut usb_buf, driver);
|
||||||
|
|
||||||
// Set up the signal pin that will be used to trigger the keyboard.
|
// Set up the signal pin that will be used to trigger the keyboard.
|
||||||
let mut signal_pin = Input::new(p.PIN_16, Pull::None);
|
let mut signal_pin = Input::new(p.PIN_16, Pull::None);
|
||||||
@@ -36,7 +40,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
// Enable the schmitt trigger to slightly debounce.
|
// Enable the schmitt trigger to slightly debounce.
|
||||||
signal_pin.set_schmitt(true);
|
signal_pin.set_schmitt(true);
|
||||||
|
|
||||||
let mut keyboard = Keyboard::<_, 1>::new(writer);
|
let mut keyboard = Keyboard::<1>::new();
|
||||||
match keyboard.add_key(signal_pin, 'a') {
|
match keyboard.add_key(signal_pin, 'a') {
|
||||||
Ok(()) => info!("Key 'a' registered"),
|
Ok(()) => info!("Key 'a' registered"),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -46,5 +50,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let led = Output::new(p.PIN_25, Level::Low);
|
let led = Output::new(p.PIN_25, Level::Low);
|
||||||
|
|
||||||
join(join(usbkey.run(), heartbeat(led)), keyboard.process()).await;
|
join(
|
||||||
|
join(usbkey.run(keyboard_events.receiver()), heartbeat(led)),
|
||||||
|
keyboard.process(keyboard_events.sender()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
103
src/usb.rs
103
src/usb.rs
@@ -4,6 +4,8 @@ use defmt::*;
|
|||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_rp::peripherals::USB;
|
use embassy_rp::peripherals::USB;
|
||||||
use embassy_rp::usb::Driver;
|
use embassy_rp::usb::Driver;
|
||||||
|
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||||
|
use embassy_sync::channel::Receiver;
|
||||||
use embassy_usb::UsbDevice;
|
use embassy_usb::UsbDevice;
|
||||||
use embassy_usb::class::hid::{
|
use embassy_usb::class::hid::{
|
||||||
HidBootProtocol, HidProtocolMode, HidReader, HidReaderWriter, HidSubclass, HidWriter, ReportId,
|
HidBootProtocol, HidProtocolMode, HidReader, HidReaderWriter, HidSubclass, HidWriter, ReportId,
|
||||||
@@ -15,6 +17,18 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
|||||||
|
|
||||||
pub static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
|
pub static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum KeyboardAction {
|
||||||
|
Press,
|
||||||
|
Depress,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct KeyboardEvent {
|
||||||
|
pub key: char,
|
||||||
|
pub action: KeyboardAction,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UsbKeyboardBuf<'d> {
|
pub struct UsbKeyboardBuf<'d> {
|
||||||
// Create embassy-usb DeviceBuilder using the driver and config.
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
// It needs some buffers for building the descriptors.
|
// It needs some buffers for building the descriptors.
|
||||||
@@ -44,14 +58,12 @@ impl<'d> UsbKeyboardBuf<'d> {
|
|||||||
pub struct UsbKeyboard<'d> {
|
pub struct UsbKeyboard<'d> {
|
||||||
usb: UsbDevice<'d, Driver<'d, USB>>,
|
usb: UsbDevice<'d, Driver<'d, USB>>,
|
||||||
reader: HidReader<'d, Driver<'d, USB>, 1>,
|
reader: HidReader<'d, Driver<'d, USB>, 1>,
|
||||||
|
writer: HidWriter<'d, Driver<'d, USB>, 8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> UsbKeyboard<'d> {
|
impl<'d> UsbKeyboard<'d> {
|
||||||
// HidWriter<'_, Driver<'_, USB>, 8>
|
// HidWriter<'_, Driver<'_, USB>, 8>
|
||||||
pub fn create_usb(
|
pub fn create_usb(buf: &'d mut UsbKeyboardBuf<'d>, driver: Driver<'d, USB>) -> Self {
|
||||||
buf: &'d mut UsbKeyboardBuf<'d>,
|
|
||||||
driver: Driver<'d, USB>,
|
|
||||||
) -> (Self, HidWriter<'d, Driver<'d, USB>, 8>) {
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
config.manufacturer = Some("Nicholas Mello");
|
config.manufacturer = Some("Nicholas Mello");
|
||||||
@@ -99,17 +111,90 @@ impl<'d> UsbKeyboard<'d> {
|
|||||||
|
|
||||||
let usb = builder.build();
|
let usb = builder.build();
|
||||||
|
|
||||||
(Self { usb, reader }, writer)
|
Self {
|
||||||
|
usb,
|
||||||
|
reader,
|
||||||
|
writer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(mut self) {
|
pub async fn run<'ch, M, const N: usize>(self, receiver: Receiver<'ch, M, KeyboardEvent, N>)
|
||||||
|
where
|
||||||
|
M: RawMutex,
|
||||||
|
{
|
||||||
let mut request_handler = MyRequestHandler {};
|
let mut request_handler = MyRequestHandler {};
|
||||||
|
|
||||||
let out_fut = async {
|
let Self {
|
||||||
self.reader.run(false, &mut request_handler).await;
|
mut usb,
|
||||||
|
reader,
|
||||||
|
mut writer,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let reader_fut = async {
|
||||||
|
reader.run(false, &mut request_handler).await;
|
||||||
};
|
};
|
||||||
|
|
||||||
join(self.usb.run(), out_fut).await;
|
let writer_fut = async {
|
||||||
|
loop {
|
||||||
|
let event = receiver.receive().await;
|
||||||
|
|
||||||
|
match event {
|
||||||
|
KeyboardEvent {
|
||||||
|
key: 'a',
|
||||||
|
action: KeyboardAction::Press,
|
||||||
|
} => {
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyboardEvent {
|
||||||
|
key: 'a',
|
||||||
|
action: KeyboardAction::Depress,
|
||||||
|
} => {
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
defmt::panic!("Unexpected event!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
join(usb.run(), join(reader_fut, writer_fut)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user